From 5c1cb4f8cd52477d3a763229c2a247695faad96c Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 02:18:56 -0400 Subject: [PATCH 01/57] Refactor Packet Monitor into stacked asynchronous graphs (#1483) Render portrait Beacon, Deauth, and Probe histories as independently scaled 4-pixel graphs with count guides, distinct zero baselines, a visible channel indicator, and a non-blocking 200 ms update cycle. --- esp32_marauder/WiFiScan.cpp | 324 ++++++++++++++++-------------------- esp32_marauder/WiFiScan.h | 28 ++-- 2 files changed, 157 insertions(+), 195 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index e3f46f56c..52dc4c3ac 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -4379,41 +4379,35 @@ void WiFiScan::RunPacketMonitor(uint8_t scan_mode, uint16_t color) { if (scan_mode == WIFI_PACKET_MONITOR) startPcap("packet_monitor"); + #if defined(HAS_SCREEN) && defined(HAS_ILI9341) + if (scan_mode == WIFI_PACKET_MONITOR) + this->resetPacketMonitorGraph(); + #endif + #ifdef HAS_ILI9341 if ((scan_mode != WIFI_SCAN_PACKET_RATE) && (scan_mode != WIFI_SCAN_CHAN_ANALYZER) && (scan_mode != WIFI_SCAN_CHAN_ACT)) { #ifdef HAS_SCREEN display_obj.init(); - #ifdef HAS_CAP_TOUCH - display_obj.tft.setRotation(3); // Pancake: landscape-3 - #else - display_obj.tft.setRotation(1); - #endif + display_obj.tft.setRotation(SCREEN_ORIENTATION); display_obj.tft.fillScreen(TFT_BLACK); #endif #ifdef HAS_SCREEN #ifndef HAS_CYD_TOUCH - display_obj.setCalData(true); + display_obj.setCalData(false); #else - //display_obj.touchscreen.setRotation(1); + //display_obj.touchscreen.setRotation(SCREEN_ORIENTATION); #endif //display_obj.tft.setFreeFont(1); display_obj.tft.setFreeFont(NULL); display_obj.tft.setTextSize(1); - display_obj.tft.fillRect(127, 0, WIDTH_1 - 127, 28, TFT_BLACK); // Buttons - display_obj.tft.fillRect(12, 0, 90, 32, TFT_BLACK); // color key - delay(10); - display_obj.tftDrawGraphObjects(x_scale); //draw graph objects - display_obj.tftDrawColorKey(); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); + this->drawPacketMonitorControls(); + this->drawPacketMonitorGraphs(); #endif } else { @@ -9754,180 +9748,144 @@ bool WiFiScan::filterActive() { #endif #ifdef HAS_SCREEN + #ifdef HAS_ILI9341 + void WiFiScan::resetPacketMonitorGraph() { + memset(packet_monitor_beacons, 0, sizeof(packet_monitor_beacons)); + memset(packet_monitor_deauths, 0, sizeof(packet_monitor_deauths)); + memset(packet_monitor_probes, 0, sizeof(packet_monitor_probes)); + num_beacon = 0; + num_deauth = 0; + num_probe = 0; + initTime = millis(); + } + void WiFiScan::samplePacketMonitorGraph() { + memmove(packet_monitor_beacons, packet_monitor_beacons + 1, + sizeof(packet_monitor_beacons) - sizeof(packet_monitor_beacons[0])); + memmove(packet_monitor_deauths, packet_monitor_deauths + 1, + sizeof(packet_monitor_deauths) - sizeof(packet_monitor_deauths[0])); + memmove(packet_monitor_probes, packet_monitor_probes + 1, + sizeof(packet_monitor_probes) - sizeof(packet_monitor_probes[0])); + + packet_monitor_beacons[PACKET_MONITOR_HISTORY_LEN - 1] = min(num_beacon, 65535); + packet_monitor_deauths[PACKET_MONITOR_HISTORY_LEN - 1] = min(num_deauth, 65535); + packet_monitor_probes[PACKET_MONITOR_HISTORY_LEN - 1] = min(num_probe, 65535); + num_beacon = 0; + num_deauth = 0; + num_probe = 0; + } + + void WiFiScan::drawPacketMonitorGraph(const uint16_t *values, int16_t top, + int16_t bottom, uint16_t color, + const char *label) { + const int16_t plot_top = top + 12; + const int16_t graph_height = bottom - plot_top; + uint16_t max_value = 1; + for (uint16_t i = 0; i < PACKET_MONITOR_HISTORY_LEN; i++) + max_value = max(max_value, values[i]); + + display_obj.tft.fillRect(0, top, SCREEN_WIDTH, bottom - top + 1, TFT_BLACK); + display_obj.tft.setTextColor(color, TFT_BLACK); + display_obj.tft.setTextSize(1); + display_obj.tft.setCursor(2, top + 2); + display_obj.tft.print(label); + + const int16_t half_y = bottom - (graph_height / 2); + display_obj.tft.drawFastHLine(PACKET_MONITOR_GRAPH_LEFT, plot_top, + SCREEN_WIDTH - PACKET_MONITOR_GRAPH_LEFT, TFT_DARKGREY); + display_obj.tft.drawFastHLine(PACKET_MONITOR_GRAPH_LEFT, half_y, + SCREEN_WIDTH - PACKET_MONITOR_GRAPH_LEFT, TFT_DARKGREY); + display_obj.tft.drawFastHLine(PACKET_MONITOR_GRAPH_LEFT, bottom, + SCREEN_WIDTH - PACKET_MONITOR_GRAPH_LEFT, TFT_LIGHTGREY); + display_obj.tft.setTextColor(TFT_DARKGREY, TFT_BLACK); + display_obj.tft.setCursor(2, plot_top); + display_obj.tft.print(max_value); + display_obj.tft.setCursor(2, half_y - 4); + display_obj.tft.print((max_value + 1) / 2); + + for (uint16_t i = 0; i < PACKET_MONITOR_HISTORY_LEN; i++) { + const int16_t x = PACKET_MONITOR_GRAPH_LEFT + (i * PACKET_MONITOR_COLUMN_WIDTH); + const int16_t height = ((uint32_t)values[i] * graph_height) / max_value; + if (height > 0) + display_obj.tft.fillRect(x, bottom - height, PACKET_MONITOR_COLUMN_WIDTH, + height, color); + } + } + + void WiFiScan::drawPacketMonitorGraphs() { + const int16_t graph_top = 64; + const int16_t lane_height = (SCREEN_HEIGHT - graph_top) / 3; + drawPacketMonitorGraph(packet_monitor_beacons, graph_top, + graph_top + lane_height - 1, TFT_GREEN, "BCN"); + drawPacketMonitorGraph(packet_monitor_deauths, graph_top + lane_height, + graph_top + (lane_height * 2) - 1, TFT_RED, "DEA"); + drawPacketMonitorGraph(packet_monitor_probes, graph_top + (lane_height * 2), + SCREEN_HEIGHT - 1, TFT_BLUE, "PRB"); + } + + void WiFiScan::drawPacketMonitorControls() { + display_obj.tft.fillRect(0, 0, SCREEN_WIDTH, 64, TFT_BLACK); + display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); + display_obj.tft.drawCentreString(text_table1[45], SCREEN_WIDTH / 2, 0, 2); + display_obj.tftDrawChannelScaleButtons(set_channel, false); + display_obj.tftDrawExitScaleButtons(false); + display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); + display_obj.tft.drawCentreString(String("CH ") + set_channel, + SCREEN_WIDTH / 2, 18, 1); + } + #endif + + #ifdef HAS_ILI9341 void WiFiScan::packetMonitorMain(uint32_t currentTime) { - - - for (x_pos = (11 + x_scale); x_pos <= WIDTH_1; x_pos = x_pos) - { - currentTime = millis(); - do_break = false; - - y_pos_x = 0; - y_pos_y = 0; - y_pos_z = 0; + const int8_t b = this->checkAnalyzerButtons(currentTime); - int8_t b = this->checkAnalyzerButtons(currentTime); - - // X - button pressed - if (b == X_MINUS_INDEX) { - if (x_scale > 1) { - x_scale--; - delay(70); - display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - //break; - } - } - // X + button pressed - else if (b == X_PLUS_INDEX) { - if (x_scale < 6) { - x_scale++; - delay(70); - display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - //break; - } - } - - // Y - button pressed - else if (b == Y_MINUS_INDEX) { - if (y_scale > 1) { - y_scale--; - delay(70); - display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - //updateMidway(); - //break; - } - } - - // Y + button pressed - else if (b == Y_PLUS_INDEX) { - if (y_scale < 9) { - y_scale++; - delay(70); - display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - //updateMidway(); - //break; - } - } - - // Channel - button pressed - else if (b == CHAN_MINUS_INDEX) { - #ifndef HAS_DUAL_BAND - if (set_channel > 1) { - set_channel--; - #else - if (dual_band_channel_index > 0) { - dual_band_channel_index--; - set_channel = dual_band_channels[dual_band_channel_index]; - #endif - delay(70); - display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - changeChannel(); - //break; - } - } - - // Channel + button pressed - else if (b == CHAN_PLUS_INDEX) { - #ifndef HAS_DUAL_BAND - if (set_channel < MAX_CHANNEL) { - set_channel++; - #else - if (dual_band_channel_index < (DUAL_BAND_CHANNELS - 1)) { - dual_band_channel_index++; - set_channel = dual_band_channels[dual_band_channel_index]; - #endif - delay(70); - display_obj.tft.fillRect(127, 0, 193, 28, TFT_BLACK); - display_obj.tftDrawXScaleButtons(x_scale); - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - changeChannel(); - //break; - } - } - else if (b == EXIT_BUTTON_INDEX) { - this->StartScan(WIFI_SCAN_OFF); - this->orient_display = true; - return; - } - // } - //} - - if (currentTime - initTime >= GRAPH_REFRESH) { - x_pos += x_scale; - initTime = millis(); - y_pos_x = ((-num_beacon * (y_scale * 3)) + (HEIGHT_1 - 2)); // GREEN - y_pos_y = ((-num_deauth * (y_scale * 3)) + (HEIGHT_1 - 2)); // RED - y_pos_z = ((-num_probe * (y_scale * 3)) + (HEIGHT_1 - 2)); // BLUE - - num_beacon = 0; - num_probe = 0; - num_deauth = 0; - - //CODE FOR PLOTTING CONTINUOUS LINES!!!!!!!!!!!! - //Plot "X" value - display_obj.tft.drawLine(x_pos - x_scale, y_pos_x_old, x_pos, y_pos_x, TFT_GREEN); - //Plot "Z" value - display_obj.tft.drawLine(x_pos - x_scale, y_pos_z_old, x_pos, y_pos_z, TFT_BLUE); - //Plot "Y" value - display_obj.tft.drawLine(x_pos - x_scale, y_pos_y_old, x_pos, y_pos_y, TFT_RED); - - //Draw preceding black 'boxes' to erase old plot lines, !!!WEIRD CODE TO COMPENSATE FOR BUTTONS AND COLOR KEY SO 'ERASER' DOESN'T ERASE BUTTONS AND COLOR KEY!!! - if ((x_pos <= 90) || ((x_pos >= 117) && (x_pos <= WIDTH_1))) //above x axis - display_obj.tft.fillRect(x_pos+1, 28, 10, PKT_HALF - 27, TFT_BLACK); //compensate for buttons! + if (b == CHAN_MINUS_INDEX) { + #ifndef HAS_DUAL_BAND + if (set_channel > 1) + set_channel--; else - display_obj.tft.fillRect(x_pos+1, 0, 10, PKT_HALF + 1, TFT_BLACK); //don't compensate for buttons! - - if (x_pos < 0) // below x axis - display_obj.tft.fillRect(x_pos+1, PKT_HALF + 1, 10, PKT_HALF - 32, TFT_CYAN); + return; + #else + if (dual_band_channel_index > 0) { + dual_band_channel_index--; + set_channel = dual_band_channels[dual_band_channel_index]; + } else - display_obj.tft.fillRect(x_pos+1, PKT_HALF + 1, 10, PKT_HALF - 2, TFT_BLACK); - - - if ( (y_pos_x == PKT_HALF) || (y_pos_y == PKT_HALF) || (y_pos_z == PKT_HALF) ) - display_obj.tft.drawFastHLine(10, PKT_HALF, PKT_AXIS_W, TFT_WHITE); // x axis - - y_pos_x_old = y_pos_x; //set old y pos values to current y pos values - y_pos_y_old = y_pos_y; - y_pos_z_old = y_pos_z; - - //delay(50); - } - + return; + #endif + changeChannel(); + this->drawPacketMonitorControls(); + } + else if (b == CHAN_PLUS_INDEX) { + #ifndef HAS_DUAL_BAND + if (set_channel < MAX_CHANNEL) + set_channel++; + else + return; + #else + if (dual_band_channel_index < (DUAL_BAND_CHANNELS - 1)) { + dual_band_channel_index++; + set_channel = dual_band_channels[dual_band_channel_index]; + } + else + return; + #endif + changeChannel(); + this->drawPacketMonitorControls(); + } + else if (b == EXIT_BUTTON_INDEX) { + this->StartScan(WIFI_SCAN_OFF); + this->orient_display = true; + return; + } + + if (currentTime - initTime >= PACKET_MONITOR_REFRESH_MS) { + initTime = currentTime; + this->samplePacketMonitorGraph(); + this->drawPacketMonitorGraphs(); } - - display_obj.tft.fillRect(127, 0, WIDTH_1 - 127, 28, TFT_BLACK); //erase XY buttons and any lines behind them - display_obj.tft.fillRect(12, 0, 90, 32, TFT_BLACK); // key - - display_obj.tftDrawXScaleButtons(x_scale); //re-draw stuff - display_obj.tftDrawYScaleButtons(y_scale); - display_obj.tftDrawChannelScaleButtons(set_channel); - display_obj.tftDrawExitScaleButtons(); - display_obj.tftDrawColorKey(); - display_obj.tftDrawGraphObjects(x_scale); } + #endif #endif void WiFiScan::changeChannel(int chan) { diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index 6df0cd98f..07d6e86fc 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -389,18 +389,22 @@ class WiFiScan WiFiClientSecure *client = new WiFiClientSecure(); #endif - int x_pos; //position along the graph x axis - float y_pos_x; //current graph y axis position of X value - float y_pos_x_old = 120; //old y axis position of X value - float y_pos_y; //current graph y axis position of Y value - float y_pos_y_old = 120; //old y axis position of Y value - float y_pos_z; //current graph y axis position of Z value - float y_pos_z_old = 120; //old y axis position of Z value - int midway = 0; - byte x_scale = 1; //scale of graph x axis, controlled by touchscreen buttons - byte y_scale = 1; - - bool do_break = false; + #if defined(HAS_SCREEN) && defined(HAS_ILI9341) + static const uint8_t PACKET_MONITOR_COLUMN_WIDTH = 4; + static const uint8_t PACKET_MONITOR_GRAPH_LEFT = 32; + static const uint16_t PACKET_MONITOR_REFRESH_MS = 200; + static const uint16_t PACKET_MONITOR_HISTORY_LEN = + (SCREEN_WIDTH - PACKET_MONITOR_GRAPH_LEFT) / PACKET_MONITOR_COLUMN_WIDTH; + uint16_t packet_monitor_beacons[PACKET_MONITOR_HISTORY_LEN] = {}; + uint16_t packet_monitor_deauths[PACKET_MONITOR_HISTORY_LEN] = {}; + uint16_t packet_monitor_probes[PACKET_MONITOR_HISTORY_LEN] = {}; + void resetPacketMonitorGraph(); + void samplePacketMonitorGraph(); + void drawPacketMonitorGraph(const uint16_t *values, int16_t top, int16_t bottom, + uint16_t color, const char *label); + void drawPacketMonitorGraphs(); + void drawPacketMonitorControls(); + #endif bool wsl_bypass_enabled = false; From 6c2040f463fe7b4abaceed682f314b7663d1b157 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:04:25 -0400 Subject: [PATCH 02/57] Bump firmware version to v1.15.0 --- esp32_marauder/configs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index db9fd3612..80552bc60 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -41,7 +41,7 @@ #define JSON_SETTING_SIZE 2048 -#define MARAUDER_VERSION "v1.14.3" +#define MARAUDER_VERSION "v1.15.0" #define GRAPH_REFRESH 100 From ec23ee077dacb4e71e992eb96bba245261fe4fcd Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:45:25 -0400 Subject: [PATCH 03/57] Add LilyGo T-Dongle C5 support (.github/workflows/build_parallel.yml) --- .github/workflows/build_parallel.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_parallel.yml b/.github/workflows/build_parallel.yml index 9af1be332..e323927cd 100644 --- a/.github/workflows/build_parallel.yml +++ b/.github/workflows/build_parallel.yml @@ -37,6 +37,7 @@ jobs: - { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } + - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=default_16MB,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5NanoC6", flag: "MARAUDER_M5_NANO_C6", fbqn: "esp32:esp32:esp32c6:CDCOnBoot=cdc,PartitionScheme=min_spiffs", file_name: "m5nanoc6", tft: false, tft_file: "", build_dir: "esp32c6", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "Marauder Pancake", flag: "MARAUDER_PANCAKE", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=default_8MB,PSRAM=enabled", file_name: "pancake", tft: true, tft_file: "User_Setup_marauder_pancake.h", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5" } @@ -342,6 +343,7 @@ jobs: | M5 Cardputer | `_m5cardputer.bin` (Available on M5 Burner) | | M5 Cardputer ADV | `_m5cardputer_adv.bin` | | ESP32-C5 DevKit | [`_esp32c5_devkit.bin`](https://github.com/justcallmekoko/ESP32Marauder/wiki/ESP32%E2%80%90C5%E2%80%90DevKitC%E2%80%901) | + | LilyGo T-Dongle C5 | `_t_dongle_c5.bin` | | AWOK V2/V3 screen (white usb) | `_v6_1.bin` | | AWOK V2 flipper (orange usb) | `_flipper.bin` | | AWOK V3 flipper (orange usb) | `_marauder_dev_board_pro.bin` | From 673f7812cab70d6f585e3c1aafb993528c43cf59 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:45:26 -0400 Subject: [PATCH 04/57] Add LilyGo T-Dongle C5 support (.github/workflows/nightly_build.yml) --- .github/workflows/nightly_build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 64d335fc1..e7ebdf860 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -100,6 +100,7 @@ jobs: - { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } + - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=default_16MB,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5NanoC6", flag: "MARAUDER_M5_NANO_C6", fbqn: "esp32:esp32:esp32c6:CDCOnBoot=cdc,PartitionScheme=min_spiffs", file_name: "m5nanoc6", tft: false, tft_file: "", build_dir: "esp32c6", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } steps: @@ -162,8 +163,8 @@ jobs: - name: Install TFT_eSPI uses: actions/checkout@v2 with: - repository: Bodmer/TFT_eSPI - ref: V2.5.34 + repository: ${{ matrix.board.tft_repo || 'Bodmer/TFT_eSPI' }} + ref: ${{ matrix.board.tft_ref || 'V2.5.34' }} path: CustomTFT_eSPI - name: Install XPT2046_Touchscreen @@ -431,4 +432,3 @@ jobs: | AWOK V2/V3 screen (white usb) | `_v6_1.bin` | | AWOK V2 flipper (orange usb) | `_flipper.bin` | | AWOK V3 flipper (orange usb) | `_marauder_dev_board_pro.bin` | - From 99ed700d3da2f5b254efa596d98abc2b4650217c Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:23 -0400 Subject: [PATCH 05/57] Add LilyGo T-Dongle C5 support (.github/workflows/build_parallel.yml) From b0a0a53cf6ea39492721e826ff8366d13d1bcd56 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:25 -0400 Subject: [PATCH 06/57] Add LilyGo T-Dongle C5 support (.github/workflows/nightly_build.yml) From db70f860f7811f2a25c019a0ad79b06c7a03725b Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:27 -0400 Subject: [PATCH 07/57] Add LilyGo T-Dongle C5 support (esp32_marauder/WiFiScan.cpp) --- esp32_marauder/WiFiScan.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 52dc4c3ac..5d3e3d25c 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -39,6 +39,18 @@ LinkedList* ipList; LinkedList* probe_req_ssids; LinkedList* ble_devices; +size_t WiFiScan::retainedAccessPointCount() const { + return access_points == nullptr ? 0 : access_points->size(); +} + +size_t WiFiScan::retainedStationCount() const { + return stations == nullptr ? 0 : stations->size(); +} + +size_t WiFiScan::retainedBleDeviceCount() const { + return ble_devices == nullptr ? 0 : ble_devices->size(); +} + extern "C" int ieee80211_raw_frame_sanity_check(int32_t arg, int32_t arg2, int32_t arg3){ if (arg == 31337) return 1; From 5f7437ccfc80c536a6bbadab8b01f84544a0f0d3 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:28 -0400 Subject: [PATCH 08/57] Add LilyGo T-Dongle C5 support (esp32_marauder/WiFiScan.h) --- esp32_marauder/WiFiScan.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index 07d6e86fc..c8d3bc462 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -802,6 +802,10 @@ class WiFiScan bool send_deauth = false; + size_t retainedAccessPointCount() const; + size_t retainedStationCount() const; + size_t retainedBleDeviceCount() const; + bool channel_hop = false; uint8_t connected_devices = 0; From c91fa070f9438124fb12a9e6e0a04198fd604371 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:29 -0400 Subject: [PATCH 09/57] Add LilyGo T-Dongle C5 support (esp32_marauder/configs.h) --- esp32_marauder/configs.h | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index 80552bc60..788fe4e3e 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -30,6 +30,7 @@ //#define MARAUDER_CYD_GUITION // ESP32-2432S024 GUITION //#define MARAUDER_CYD_3_5_INCH //#define MARAUDER_C5 + //#define MARAUDER_T_DONGLE_C5 //#define MARAUDER_CARDPUTER //#define MARAUDER_CARDPUTER_ADV //#define MARAUDER_V8 @@ -102,6 +103,8 @@ #define HARDWARE_NAME "XIAO ESP32 S3" #elif defined(MARAUDER_C5) #define HARDWARE_NAME "ESP32-C5 DevKit" + #elif defined(MARAUDER_T_DONGLE_C5) + #define HARDWARE_NAME "LilyGo T-Dongle C5" #elif defined(MARAUDER_V8) #define HARDWARE_NAME "Marauder v8" #elif defined(MARAUDER_PANCAKE) @@ -514,6 +517,19 @@ #define HAS_DIRECT_UPLOAD #endif + #ifdef MARAUDER_T_DONGLE_C5 + #define HAS_BT + #define HAS_T_DONGLE_DISPLAY + #define HAS_C5_SD + #define HAS_SD + #define USE_SD + #define HAS_DUAL_BAND + #define HAS_PSRAM + #define HAS_NIMBLE_2 + #define HAS_IDF_3 + #define HAS_DIRECT_UPLOAD + #endif + #ifdef MARAUDER_V8 #define HAS_TOUCH //#define HAS_FLIPPER_LED @@ -2541,8 +2557,10 @@ #define SD_CS 3 #endif - #ifdef MARAUDER_C5 + #if defined(MARAUDER_C5) #define SD_CS 10 + #elif defined(MARAUDER_T_DONGLE_C5) + #define SD_CS 23 #endif #ifdef MARAUDER_V8 @@ -2659,6 +2677,8 @@ #define MEM_LOWER_LIM 10000 #elif defined(MARAUDER_C5) #define MEM_LOWER_LIM 10000 + #elif defined(MARAUDER_T_DONGLE_C5) + #define MEM_LOWER_LIM 10000 #elif defined(MARAUDER_V8) #define MEM_LOWER_LIM 10000 #elif defined(MARAUDER_PANCAKE) @@ -3010,10 +3030,14 @@ #define SD_SCK 18 #endif - #ifdef MARAUDER_C5 + #if defined(MARAUDER_C5) #define SD_MISO 2 #define SD_MOSI 7 #define SD_SCK 6 + #elif defined(MARAUDER_T_DONGLE_C5) + #define SD_MISO 7 + #define SD_MOSI 2 + #define SD_SCK 6 #endif #ifdef MARAUDER_V8 From 95bdfdc355a4f6590924a0e230de9e43be02e438 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:31 -0400 Subject: [PATCH 10/57] Add LilyGo T-Dongle C5 support (esp32_marauder/esp32_marauder.ino) --- esp32_marauder/esp32_marauder.ino | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/esp32_marauder/esp32_marauder.ino b/esp32_marauder/esp32_marauder.ino index c3b2e5eef..3b5c2f917 100644 --- a/esp32_marauder/esp32_marauder.ino +++ b/esp32_marauder/esp32_marauder.ino @@ -39,6 +39,10 @@ https://www.online-utility.org/image/convert/to/XBM #include "CommandLine.h" #include "lang_var.h" +#ifdef HAS_T_DONGLE_DISPLAY + #include "TDongleDisplay.h" +#endif + #ifdef HAS_BATTERY #include "BatteryInterface.h" #endif @@ -75,6 +79,10 @@ Buffer buffer_obj; Settings settings_obj; CommandLine cli_obj; +#ifdef HAS_T_DONGLE_DISPLAY + TDongleDisplay t_dongle_display; +#endif + #ifdef HAS_GPS GpsInterface gps_obj; #endif @@ -359,6 +367,10 @@ void setup() wifi_scan_obj.RunSetup(); + #ifdef HAS_T_DONGLE_DISPLAY + t_dongle_display.begin(); + #endif + #ifdef HAS_SCREEN display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); display_obj.tft.drawCentreString("Initializing...", TFT_WIDTH/2, TFT_HEIGHT * 0.82, 1); @@ -447,6 +459,10 @@ void loop() cli_obj.main(currentTime); wifi_scan_obj.main(currentTime); + #ifdef HAS_T_DONGLE_DISPLAY + t_dongle_display.update(currentTime, wifi_scan_obj); + #endif + #ifdef HAS_GPS gps_obj.main(); #endif From 4545547450fd048c0f65d03f1690131d7a54f574 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:32 -0400 Subject: [PATCH 11/57] Add LilyGo T-Dongle C5 support (esp32_marauder/TDongleDisplay.cpp) --- esp32_marauder/TDongleDisplay.cpp | 78 +++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 esp32_marauder/TDongleDisplay.cpp diff --git a/esp32_marauder/TDongleDisplay.cpp b/esp32_marauder/TDongleDisplay.cpp new file mode 100644 index 000000000..3b0c5d456 --- /dev/null +++ b/esp32_marauder/TDongleDisplay.cpp @@ -0,0 +1,78 @@ +#include "TDongleDisplay.h" + +#ifdef HAS_T_DONGLE_DISPLAY + +#include "WiFiScan.h" + +namespace { +constexpr uint32_t kRefreshMs = 500; +constexpr uint8_t kRowHeight = 13; +} + +void TDongleDisplay::begin() { + pinMode(TFT_BL, OUTPUT); + digitalWrite(TFT_BL, HIGH); + tft.init(); + tft.setRotation(1); + tft.fillScreen(TFT_BLACK); + tft.setTextFont(1); + tft.setTextSize(1); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + tft.drawString("MARAUDER CLI", 2, 1); + tft.drawFastHLine(0, 11, tft.width(), TFT_DARKGREY); +} + +void TDongleDisplay::drawValue(uint8_t row, const char* label, int value, uint16_t color) { + const int y = 14 + (row * kRowHeight); + tft.fillRect(0, y, tft.width(), kRowHeight, TFT_BLACK); + tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK); + tft.drawString(label, 2, y + 2); + tft.setTextColor(color, TFT_BLACK); + tft.drawRightString(String(value), tft.width() - 2, y + 2); +} + +const char* TDongleDisplay::modeLabel(uint8_t mode) const { + switch (mode) { + case WIFI_SCAN_OFF: return "IDLE"; + case WIFI_SCAN_AP: return "WIFI AP"; + case WIFI_SCAN_STATION: return "WIFI STA"; + case WIFI_SCAN_AP_STA: return "AP+STA"; + case WIFI_SCAN_ALL: return "WIFI ALL"; + case WIFI_SCAN_WAR_DRIVE: return "WARDRIVE"; + case BT_SCAN_ALL: return "BLE ALL"; + case BT_SCAN_WAR_DRIVE: + case BT_SCAN_WAR_DRIVE_CONT: return "BLE DRIVE"; + default: return "ACTIVE"; + } +} + +void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { + if (now - last_update < kRefreshMs) return; + last_update = now; + + const int ap_count = static_cast(scan.retainedAccessPointCount()); + const int station_count = static_cast(scan.retainedStationCount()); + const int ble_count = static_cast(scan.retainedBleDeviceCount()); + + if (ap_count != last_ap_count) drawValue(0, "WiFi AP", ap_count, TFT_GREEN); + if (station_count != last_station_count) drawValue(1, "Stations", station_count, TFT_CYAN); + if (ble_count != last_ble_count) drawValue(2, "BLE", ble_count, TFT_MAGENTA); + if (scan.set_channel != last_channel) drawValue(3, "Channel", scan.set_channel, TFT_YELLOW); + + if (scan.currentScanMode != last_mode) { + const int y = 14 + (4 * kRowHeight); + tft.fillRect(0, y, tft.width(), kRowHeight, TFT_BLACK); + tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK); + tft.drawString("Mode", 2, y + 2); + tft.setTextColor(TFT_ORANGE, TFT_BLACK); + tft.drawRightString(modeLabel(scan.currentScanMode), tft.width() - 2, y + 2); + } + + last_ap_count = ap_count; + last_station_count = station_count; + last_ble_count = ble_count; + last_channel = scan.set_channel; + last_mode = scan.currentScanMode; +} + +#endif From c8f0b201d62fc0ecc8f96a1542050b293ed27826 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:33 -0400 Subject: [PATCH 12/57] Add LilyGo T-Dongle C5 support (esp32_marauder/TDongleDisplay.h) --- esp32_marauder/TDongleDisplay.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 esp32_marauder/TDongleDisplay.h diff --git a/esp32_marauder/TDongleDisplay.h b/esp32_marauder/TDongleDisplay.h new file mode 100644 index 000000000..4eb612863 --- /dev/null +++ b/esp32_marauder/TDongleDisplay.h @@ -0,0 +1,29 @@ +#pragma once + +#include "configs.h" + +#ifdef HAS_T_DONGLE_DISPLAY + +#include + +class WiFiScan; + +class TDongleDisplay { + public: + void begin(); + void update(uint32_t now, const WiFiScan& scan); + + private: + TFT_eSPI tft; + uint32_t last_update = 0; + int last_ap_count = -1; + int last_station_count = -1; + int last_ble_count = -1; + int last_channel = -1; + int last_mode = -1; + + const char* modeLabel(uint8_t mode) const; + void drawValue(uint8_t row, const char* label, int value, uint16_t color); +}; + +#endif From 4ec216d0d4e2a711eca2ceb9a3b142979b68f5be Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:35 -0400 Subject: [PATCH 13/57] Add LilyGo T-Dongle C5 support (User_Setup_marauder_t_dongle_c5.h) --- User_Setup_marauder_t_dongle_c5.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 User_Setup_marauder_t_dongle_c5.h diff --git a/User_Setup_marauder_t_dongle_c5.h b/User_Setup_marauder_t_dongle_c5.h new file mode 100644 index 000000000..20f024168 --- /dev/null +++ b/User_Setup_marauder_t_dongle_c5.h @@ -0,0 +1,19 @@ +// TFT_eSPI setup for the LilyGo T-Dongle C5 onboard 80x160 ST7735 display. +#define ST7735_DRIVER +#define TFT_WIDTH 80 +#define TFT_HEIGHT 160 +#define ST7735_GREENTAB160x80 +#define TFT_RGB_ORDER TFT_BGR + +#define TFT_MISO 7 +#define TFT_MOSI 2 +#define TFT_SCLK 6 +#define TFT_CS 10 +#define TFT_DC 3 +#define TFT_RST 1 +#define TFT_BL 0 +#define TFT_BACKLIGHT_ON HIGH + +#define LOAD_GLCD +#define SPI_FREQUENCY 27000000 +#define SPI_READ_FREQUENCY 16000000 From 534a638774a689d0cac4576e7a586eebb52fd7c9 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:36 -0400 Subject: [PATCH 14/57] Add LilyGo T-Dongle C5 support (installer/targets.json) --- installer/targets.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/installer/targets.json b/installer/targets.json index 21e960527..da38a45de 100644 --- a/installer/targets.json +++ b/installer/targets.json @@ -183,6 +183,15 @@ "chipFamily": "ESP32-C5", "esptoolChip": "esp32c5" }, + { + "id": "lilygo-t-dongle-c5", + "displayName": "LilyGo T-Dongle C5", + "aliases": ["T-Dongle C5", "T Dongle C5"], + "buildFlag": "MARAUDER_T_DONGLE_C5", + "assetSuffix": "t_dongle_c5", + "chipFamily": "ESP32-C5", + "esptoolChip": "esp32c5" + }, { "id": "m5-nano-c6", "displayName": "M5 Nano C6", From 772fa11fc9a1796fdbdfb57a8b5b338a71d72fe5 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:46:37 -0400 Subject: [PATCH 15/57] Add LilyGo T-Dongle C5 support (tools/test_installer_manifest.py) --- tools/test_installer_manifest.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/test_installer_manifest.py b/tools/test_installer_manifest.py index 801f0c4fb..531f7e955 100644 --- a/tools/test_installer_manifest.py +++ b/tools/test_installer_manifest.py @@ -68,13 +68,14 @@ def test_registry_contains_unique_complete_build_targets(self) -> None: self.assertIn("github.event_name == 'release'", installer_workflow) self.assertIn('marauder-installer-assets.zip', installer_workflow) self.assertNotIn('release-assets/*.bin\n', installer_workflow) - self.assertEqual(len(registry["targets"]), 25) - self.assertEqual(len(boards), 22) + self.assertEqual(len(registry["targets"]), 26) + self.assertEqual(len(boards), 23) self.assertEqual( private_flags, {"MARAUDER_V8", "MARAUDER_MINI_V3", "DUAL_MINI_C5"}, ) self.assertEqual(registry_flags - private_flags, workflow_flags) + self.assertIn("MARAUDER_T_DONGLE_C5", workflow_flags) self.assertEqual( len(registry_flags), len(registry["targets"]), @@ -187,7 +188,7 @@ def test_combines_complete_stable_release(self) -> None: self.assertEqual(release["metadataStatus"], "authoritative") self.assertEqual(release["channel"], "stable") self.assertEqual(release["sourceCommit"], "a" * 40) - self.assertEqual(len(release["targets"]), 25) + self.assertEqual(len(release["targets"]), 26) self.assertIn("/" + "a" * 40 + "/", release["$schema"]) def test_combiner_rejects_target_identity_drift(self) -> None: From 50f0d8d882ab5d2926d6b0f2fa0cfe221f6ba37a Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:51:39 -0400 Subject: [PATCH 16/57] Use 16 MB T-Dongle partition layout (.github/workflows/build_parallel.yml) --- .github/workflows/build_parallel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_parallel.yml b/.github/workflows/build_parallel.yml index e323927cd..90580df1a 100644 --- a/.github/workflows/build_parallel.yml +++ b/.github/workflows/build_parallel.yml @@ -37,7 +37,7 @@ jobs: - { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=default_16MB,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } + - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=custom,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5NanoC6", flag: "MARAUDER_M5_NANO_C6", fbqn: "esp32:esp32:esp32c6:CDCOnBoot=cdc,PartitionScheme=min_spiffs", file_name: "m5nanoc6", tft: false, tft_file: "", build_dir: "esp32c6", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "Marauder Pancake", flag: "MARAUDER_PANCAKE", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=default_8MB,PSRAM=enabled", file_name: "pancake", tft: true, tft_file: "User_Setup_marauder_pancake.h", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5" } From 2e29898b52d00f78139501f632538fe00748300b Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:51:40 -0400 Subject: [PATCH 17/57] Use 16 MB T-Dongle partition layout (.github/workflows/nightly_build.yml) --- .github/workflows/nightly_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index e7ebdf860..ce2b59abd 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -100,7 +100,7 @@ jobs: - { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=default_16MB,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } + - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=custom,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5NanoC6", flag: "MARAUDER_M5_NANO_C6", fbqn: "esp32:esp32:esp32c6:CDCOnBoot=cdc,PartitionScheme=min_spiffs", file_name: "m5nanoc6", tft: false, tft_file: "", build_dir: "esp32c6", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } steps: From 38bf1b0ef0b3d7eb9083c85e60102f23b4429b57 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:51:41 -0400 Subject: [PATCH 18/57] Use 16 MB T-Dongle partition layout (esp32_marauder/partitions.csv) --- esp32_marauder/partitions.csv | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 esp32_marauder/partitions.csv diff --git a/esp32_marauder/partitions.csv b/esp32_marauder/partitions.csv new file mode 100644 index 000000000..4e9cf237f --- /dev/null +++ b/esp32_marauder/partitions.csv @@ -0,0 +1,7 @@ +# LilyGo T-Dongle C5 16 MB layout (selected only with PartitionScheme=custom) +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x300000, +app1, app, ota_1, 0x310000, 0x300000, +spiffs, data, spiffs, 0x610000, 0x9F0000, From 7a5f03023892da5217ee00594e2fec8dd3a7e768 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:56:08 -0400 Subject: [PATCH 19/57] Fix T-Dongle dashboard build (esp32_marauder/TDongleDisplay.cpp) --- esp32_marauder/TDongleDisplay.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/esp32_marauder/TDongleDisplay.cpp b/esp32_marauder/TDongleDisplay.cpp index 3b0c5d456..219caadf3 100644 --- a/esp32_marauder/TDongleDisplay.cpp +++ b/esp32_marauder/TDongleDisplay.cpp @@ -7,11 +7,12 @@ namespace { constexpr uint32_t kRefreshMs = 500; constexpr uint8_t kRowHeight = 13; +constexpr uint8_t kBacklightPin = 0; } void TDongleDisplay::begin() { - pinMode(TFT_BL, OUTPUT); - digitalWrite(TFT_BL, HIGH); + pinMode(kBacklightPin, OUTPUT); + digitalWrite(kBacklightPin, HIGH); tft.init(); tft.setRotation(1); tft.fillScreen(TFT_BLACK); @@ -28,7 +29,7 @@ void TDongleDisplay::drawValue(uint8_t row, const char* label, int value, uint16 tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK); tft.drawString(label, 2, y + 2); tft.setTextColor(color, TFT_BLACK); - tft.drawRightString(String(value), tft.width() - 2, y + 2); + tft.drawRightString(String(value), tft.width() - 2, y + 2, 1); } const char* TDongleDisplay::modeLabel(uint8_t mode) const { @@ -65,7 +66,7 @@ void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK); tft.drawString("Mode", 2, y + 2); tft.setTextColor(TFT_ORANGE, TFT_BLACK); - tft.drawRightString(modeLabel(scan.currentScanMode), tft.width() - 2, y + 2); + tft.drawRightString(modeLabel(scan.currentScanMode), tft.width() - 2, y + 2, 1); } last_ap_count = ap_count; From 9c99bb22aef236b82d2d2e7dc9b4676e2cd147fd Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 04:56:09 -0400 Subject: [PATCH 20/57] Fix T-Dongle dashboard build (esp32_marauder/WiFiScan.cpp) --- esp32_marauder/WiFiScan.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 5d3e3d25c..e21550c40 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10908,7 +10908,11 @@ uint16_t WiFiScan::rssiToColor(int8_t rssi) { String sidecarPath = filePath + "." + service; File f = SD.open(sidecarPath, FILE_WRITE); if (f) { - f.println("uploaded=" + gps_obj.getDatetime()); + #ifdef HAS_GPS + f.println("uploaded=" + gps_obj.getDatetime()); + #else + f.println("uploaded_uptime_ms=" + String(millis())); + #endif f.close(); Serial.println("[UPLOAD] Sidecar written: " + sidecarPath); } else { From 5c25cf394c2f9ad6cb2117a001ceda26564f5e36 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:01:10 -0400 Subject: [PATCH 21/57] Select T-Dongle TFT setup in CI --- User_Setup_Select.h | 1 + 1 file changed, 1 insertion(+) diff --git a/User_Setup_Select.h b/User_Setup_Select.h index e5ff9cab6..cc72ee96a 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -38,6 +38,7 @@ //#include //#include //#include +//#include //#include // Setup file configured for my ILI9341 //#include // Setup file configured for my ST7735 From 12ab51aebb2a64f3d7dcdac5686185fe5a1a7c2c Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:10:32 -0400 Subject: [PATCH 22/57] Cover T-Dongle scan view labels (platformio.ini) --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 1b80e10d8..5fdab083b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,6 +18,7 @@ build_src_filter = + + + + + build_flags = -std=gnu++17 -Wall From 2f3dbe6b1f426dc11ad84908414545b3eeab80ab Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:10:33 -0400 Subject: [PATCH 23/57] Cover T-Dongle scan view labels (esp32_marauder/TDongleStats.h) --- esp32_marauder/TDongleStats.h | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 esp32_marauder/TDongleStats.h diff --git a/esp32_marauder/TDongleStats.h b/esp32_marauder/TDongleStats.h new file mode 100644 index 000000000..be791a8e8 --- /dev/null +++ b/esp32_marauder/TDongleStats.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +class TDongleStats { + public: + static const char* modeLabel(uint8_t mode); +}; From 2769d3472637520edf446b231544851d0105aa73 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:10:35 -0400 Subject: [PATCH 24/57] Cover T-Dongle scan view labels (esp32_marauder/TDongleStats.cpp) --- esp32_marauder/TDongleStats.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 esp32_marauder/TDongleStats.cpp diff --git a/esp32_marauder/TDongleStats.cpp b/esp32_marauder/TDongleStats.cpp new file mode 100644 index 000000000..c51949d7d --- /dev/null +++ b/esp32_marauder/TDongleStats.cpp @@ -0,0 +1,16 @@ +#include "TDongleStats.h" + +const char* TDongleStats::modeLabel(uint8_t mode) { + switch (mode) { + case 0: return "IDLE"; + case 2: return "WIFI AP"; + case 26: return "WIFI STA"; + case 49: return "AP+STA"; + case 6: return "WIFI ALL"; + case 32: return "WARDRIVE"; + case 10: return "BLE ALL"; + case 34: + case 35: return "BLE DRIVE"; + default: return "ACTIVE"; + } +} From f569f2760c2a3ea20a8f901f5902e153ee73fbaf Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:10:36 -0400 Subject: [PATCH 25/57] Cover T-Dongle scan view labels (esp32_marauder/TDongleDisplay.h) --- esp32_marauder/TDongleDisplay.h | 1 - 1 file changed, 1 deletion(-) diff --git a/esp32_marauder/TDongleDisplay.h b/esp32_marauder/TDongleDisplay.h index 4eb612863..643242316 100644 --- a/esp32_marauder/TDongleDisplay.h +++ b/esp32_marauder/TDongleDisplay.h @@ -22,7 +22,6 @@ class TDongleDisplay { int last_channel = -1; int last_mode = -1; - const char* modeLabel(uint8_t mode) const; void drawValue(uint8_t row, const char* label, int value, uint16_t color); }; From 80b81e65fa36815b65ca9f7b2137a10af2cc0077 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:10:37 -0400 Subject: [PATCH 26/57] Cover T-Dongle scan view labels (esp32_marauder/TDongleDisplay.cpp) --- esp32_marauder/TDongleDisplay.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/esp32_marauder/TDongleDisplay.cpp b/esp32_marauder/TDongleDisplay.cpp index 219caadf3..565b9d14a 100644 --- a/esp32_marauder/TDongleDisplay.cpp +++ b/esp32_marauder/TDongleDisplay.cpp @@ -3,6 +3,7 @@ #ifdef HAS_T_DONGLE_DISPLAY #include "WiFiScan.h" +#include "TDongleStats.h" namespace { constexpr uint32_t kRefreshMs = 500; @@ -32,21 +33,6 @@ void TDongleDisplay::drawValue(uint8_t row, const char* label, int value, uint16 tft.drawRightString(String(value), tft.width() - 2, y + 2, 1); } -const char* TDongleDisplay::modeLabel(uint8_t mode) const { - switch (mode) { - case WIFI_SCAN_OFF: return "IDLE"; - case WIFI_SCAN_AP: return "WIFI AP"; - case WIFI_SCAN_STATION: return "WIFI STA"; - case WIFI_SCAN_AP_STA: return "AP+STA"; - case WIFI_SCAN_ALL: return "WIFI ALL"; - case WIFI_SCAN_WAR_DRIVE: return "WARDRIVE"; - case BT_SCAN_ALL: return "BLE ALL"; - case BT_SCAN_WAR_DRIVE: - case BT_SCAN_WAR_DRIVE_CONT: return "BLE DRIVE"; - default: return "ACTIVE"; - } -} - void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { if (now - last_update < kRefreshMs) return; last_update = now; @@ -66,7 +52,7 @@ void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK); tft.drawString("Mode", 2, y + 2); tft.setTextColor(TFT_ORANGE, TFT_BLACK); - tft.drawRightString(modeLabel(scan.currentScanMode), tft.width() - 2, y + 2, 1); + tft.drawRightString(TDongleStats::modeLabel(scan.currentScanMode), tft.width() - 2, y + 2, 1); } last_ap_count = ap_count; From d6ad5e3b3d0dca75d9bf9fc2d87c832664f71764 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 05:10:38 -0400 Subject: [PATCH 27/57] Cover T-Dongle scan view labels (test/test_t_dongle_stats/test_main.cpp) --- test/test_t_dongle_stats/test_main.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/test_t_dongle_stats/test_main.cpp diff --git a/test/test_t_dongle_stats/test_main.cpp b/test/test_t_dongle_stats/test_main.cpp new file mode 100644 index 000000000..7e85a5e86 --- /dev/null +++ b/test/test_t_dongle_stats/test_main.cpp @@ -0,0 +1,22 @@ +#include + +#include "TDongleStats.h" + +void test_mode_labels_cover_retained_scan_views() { + TEST_ASSERT_EQUAL_STRING("IDLE", TDongleStats::modeLabel(0)); + TEST_ASSERT_EQUAL_STRING("WIFI AP", TDongleStats::modeLabel(2)); + TEST_ASSERT_EQUAL_STRING("WIFI STA", TDongleStats::modeLabel(26)); + TEST_ASSERT_EQUAL_STRING("AP+STA", TDongleStats::modeLabel(49)); + TEST_ASSERT_EQUAL_STRING("WIFI ALL", TDongleStats::modeLabel(6)); + TEST_ASSERT_EQUAL_STRING("WARDRIVE", TDongleStats::modeLabel(32)); + TEST_ASSERT_EQUAL_STRING("BLE ALL", TDongleStats::modeLabel(10)); + TEST_ASSERT_EQUAL_STRING("BLE DRIVE", TDongleStats::modeLabel(34)); + TEST_ASSERT_EQUAL_STRING("BLE DRIVE", TDongleStats::modeLabel(35)); + TEST_ASSERT_EQUAL_STRING("ACTIVE", TDongleStats::modeLabel(255)); +} + +int main(int, char**) { + UNITY_BEGIN(); + RUN_TEST(test_mode_labels_cover_retained_scan_views); + return UNITY_END(); +} From b5539b7aa4bec21c39715c8cc4041614fa216020 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 10:56:27 -0400 Subject: [PATCH 28/57] Fix T-Dongle C5 display and status LED --- User_Setup_marauder_t_dongle_c5.h | 2 +- esp32_marauder/LedInterface.cpp | 36 ++++++++++++++++++++++++++++++- esp32_marauder/LedInterface.h | 5 +++++ esp32_marauder/TDongleDisplay.cpp | 4 +++- esp32_marauder/WiFiScan.cpp | 6 +++--- esp32_marauder/configs.h | 1 + esp32_marauder/esp32_marauder.ino | 8 +++---- 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/User_Setup_marauder_t_dongle_c5.h b/User_Setup_marauder_t_dongle_c5.h index 20f024168..b35c7873f 100644 --- a/User_Setup_marauder_t_dongle_c5.h +++ b/User_Setup_marauder_t_dongle_c5.h @@ -12,7 +12,7 @@ #define TFT_DC 3 #define TFT_RST 1 #define TFT_BL 0 -#define TFT_BACKLIGHT_ON HIGH +#define TFT_BACKLIGHT_ON LOW #define LOAD_GLCD #define SPI_FREQUENCY 27000000 diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index 79f888703..bf9269423 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -23,6 +23,14 @@ void LedInterface::RunSetup() { strip.show(); #endif + #ifdef HAS_T_DONGLE_LED + pinMode(4, OUTPUT); + pinMode(5, OUTPUT); + digitalWrite(4, LOW); + digitalWrite(5, LOW); + this->writeApa102Color(0, 0, 0); + #endif + this->initTime = millis(); } @@ -63,8 +71,33 @@ void LedInterface::setColor(int r, int g, int b) { strip.setPixelColor(0, strip.Color(r, g, b)); strip.show(); #endif + #ifdef HAS_T_DONGLE_LED + this->writeApa102Color(static_cast(r), static_cast(g), + static_cast(b)); + #endif } +#ifdef HAS_T_DONGLE_LED +void LedInterface::writeApa102Byte(uint8_t value) { + for (int bit = 7; bit >= 0; --bit) { + digitalWrite(5, (value >> bit) & 0x01); + digitalWrite(4, HIGH); + digitalWrite(4, LOW); + } +} + +void LedInterface::writeApa102Color(uint8_t red, uint8_t green, uint8_t blue) { + noInterrupts(); + for (uint8_t i = 0; i < 4; ++i) writeApa102Byte(0x00); + writeApa102Byte(0xE8); + writeApa102Byte(blue); + writeApa102Byte(green); + writeApa102Byte(red); + for (uint8_t i = 0; i < 4; ++i) writeApa102Byte(0xFF); + interrupts(); +} +#endif + void LedInterface::sniffLed() { this->setColor(0, 0, 255); } @@ -103,4 +136,5 @@ uint32_t LedInterface::Wheel(byte WheelPos) { WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); #endif -} \ No newline at end of file + return 0; +} diff --git a/esp32_marauder/LedInterface.h b/esp32_marauder/LedInterface.h index 1a5a46084..2801eecb0 100644 --- a/esp32_marauder/LedInterface.h +++ b/esp32_marauder/LedInterface.h @@ -35,6 +35,11 @@ class LedInterface { void ledOff(); void attackLed(); void sniffLed(); + + #ifdef HAS_T_DONGLE_LED + void writeApa102Byte(uint8_t value); + void writeApa102Color(uint8_t red, uint8_t green, uint8_t blue); + #endif public: LedInterface(); diff --git a/esp32_marauder/TDongleDisplay.cpp b/esp32_marauder/TDongleDisplay.cpp index 565b9d14a..f430ead45 100644 --- a/esp32_marauder/TDongleDisplay.cpp +++ b/esp32_marauder/TDongleDisplay.cpp @@ -14,14 +14,16 @@ constexpr uint8_t kBacklightPin = 0; void TDongleDisplay::begin() { pinMode(kBacklightPin, OUTPUT); digitalWrite(kBacklightPin, HIGH); + delay(500); tft.init(); - tft.setRotation(1); + tft.setRotation(3); tft.fillScreen(TFT_BLACK); tft.setTextFont(1); tft.setTextSize(1); tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.drawString("MARAUDER CLI", 2, 1); tft.drawFastHLine(0, 11, tft.width(), TFT_DARKGREY); + digitalWrite(kBacklightPin, LOW); } void TDongleDisplay::drawValue(uint8_t row, const char* label, int value, uint16_t color) { diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index e21550c40..80dcf91f0 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -2463,7 +2463,7 @@ void WiFiScan::setLEDMode(int mode) { xiao_led.attackLED(); #elif defined(MARAUDER_M5STICKC) stickc_led.attackLED(); - #elif defined(HAS_NEOPIXEL_LED) + #elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) led_obj.setMode(MODE_ATTACK); #endif } else if (mode == MODE_SNIFF) { @@ -2473,7 +2473,7 @@ void WiFiScan::setLEDMode(int mode) { xiao_led.sniffLED(); #elif defined(MARAUDER_M5STICKC) stickc_led.sniffLED(); - #elif defined(HAS_NEOPIXEL_LED) + #elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) led_obj.setMode(MODE_SNIFF); #endif } else if (mode == MODE_OFF) { @@ -2483,7 +2483,7 @@ void WiFiScan::setLEDMode(int mode) { xiao_led.offLED(); #elif defined(MARAUDER_M5STICKC) stickc_led.offLED(); - #elif defined(HAS_NEOPIXEL_LED) + #elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) led_obj.setMode(MODE_OFF); #endif } diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index 788fe4e3e..89bd0ee09 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -520,6 +520,7 @@ #ifdef MARAUDER_T_DONGLE_C5 #define HAS_BT #define HAS_T_DONGLE_DISPLAY + #define HAS_T_DONGLE_LED #define HAS_C5_SD #define HAS_SD #define USE_SD diff --git a/esp32_marauder/esp32_marauder.ino b/esp32_marauder/esp32_marauder.ino index 3b5c2f917..33cdbd4bf 100644 --- a/esp32_marauder/esp32_marauder.ino +++ b/esp32_marauder/esp32_marauder.ino @@ -31,7 +31,7 @@ https://www.online-utility.org/image/convert/to/XBM #include "xiaoLED.h" #elif defined(MARAUDER_M5STICKC) || defined(MARAUDER_M5STICKCP2) #include "stickcLED.h" -#elif defined(HAS_NEOPIXEL_LED) +#elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) #include "LedInterface.h" #endif @@ -106,7 +106,7 @@ CommandLine cli_obj; xiaoLED xiao_led; #elif defined(MARAUDER_M5STICKC) || defined(MARAUDER_M5STICKCP2) stickcLED stickc_led; -#elif defined(HAS_NEOPIXEL_LED) +#elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) LedInterface led_obj; #endif @@ -393,7 +393,7 @@ void setup() xiao_led.RunSetup(); #elif defined(MARAUDER_M5STICKC) stickc_led.RunSetup(); - #elif defined(HAS_NEOPIXEL_LED) + #elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) led_obj.RunSetup(); #endif @@ -485,7 +485,7 @@ void loop() xiao_led.main(); #elif defined(MARAUDER_M5STICKC) stickc_led.main(); - #elif defined(HAS_NEOPIXEL_LED) + #elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) led_obj.main(currentTime); #endif From b3c0a232284152b930617383aa28fc8b0036aec2 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:01:20 -0400 Subject: [PATCH 29/57] Expose T-Dongle status LED to scanner --- esp32_marauder/WiFiScan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index c8d3bc462..ec2460fb2 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -64,7 +64,7 @@ #include "xiaoLED.h" #elif defined(MARAUDER_M5STICKC) #include "stickcLED.h" -#elif defined(HAS_NEOPIXEL_LED) +#elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) #include "LedInterface.h" #endif @@ -245,7 +245,7 @@ extern Settings settings_obj; extern xiaoLED xiao_led; #elif defined(MARAUDER_M5STICKC) extern stickcLED stickc_led; -#elif defined(HAS_NEOPIXEL_LED) +#elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) extern LedInterface led_obj; #endif From 9e9a600b52218a77861faf9775332401487a0d84 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:33:17 -0400 Subject: [PATCH 30/57] Fix T-Dongle LED idle state and enable GPS --- esp32_marauder/LedInterface.cpp | 6 +++++- esp32_marauder/configs.h | 5 +++++ tools/test_t_dongle_hardware.py | 37 +++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tools/test_t_dongle_hardware.py diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index bf9269423..69b152d57 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -93,7 +93,11 @@ void LedInterface::writeApa102Color(uint8_t red, uint8_t green, uint8_t blue) { writeApa102Byte(blue); writeApa102Byte(green); writeApa102Byte(red); - for (uint8_t i = 0; i < 4; ++i) writeApa102Byte(0xFF); + // One LED latches after its color frame. A legacy four-byte 0xFF end frame + // is interpreted as additional full-white data by this board's APA102/SK9822 + // and leaves the LED white after the requested color is shown. + digitalWrite(5, LOW); + digitalWrite(4, LOW); interrupts(); } #endif diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index 89bd0ee09..31e04bac4 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -521,6 +521,7 @@ #define HAS_BT #define HAS_T_DONGLE_DISPLAY #define HAS_T_DONGLE_LED + #define HAS_GPS #define HAS_C5_SD #define HAS_SD #define USE_SD @@ -2811,6 +2812,10 @@ #define GPS_SERIAL_INDEX 1 #define GPS_TX 6 #define GPS_RX 9 + #elif defined(MARAUDER_T_DONGLE_C5) + #define GPS_SERIAL_INDEX 1 + #define GPS_TX 12 // External GPS TX -> T-Dongle UART0 RX + #define GPS_RX 11 // External GPS RX -> T-Dongle UART0 TX #elif defined(MARAUDER_C5) #define GPS_SERIAL_INDEX 1 #define GPS_TX 14 diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py new file mode 100644 index 000000000..c797b44b1 --- /dev/null +++ b/tools/test_t_dongle_hardware.py @@ -0,0 +1,37 @@ +import re +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +class TDongleHardwareTests(unittest.TestCase): + def test_t_dongle_enables_uart_gps_header(self): + configs = (ROOT / "esp32_marauder" / "configs.h").read_text() + feature_block = re.search( + r"#ifdef MARAUDER_T_DONGLE_C5(?P.*?)#endif", configs, re.S + ).group("body") + self.assertIn("#define HAS_GPS", feature_block) + + gps_block = next( + body for body in re.findall( + r"#elif defined\(MARAUDER_T_DONGLE_C5\)(.*?)#elif", configs, re.S + ) if "GPS_SERIAL_INDEX" in body + ) + self.assertIn("#define GPS_SERIAL_INDEX 1", gps_block) + self.assertIn("#define GPS_TX 12", gps_block) + self.assertIn("#define GPS_RX 11", gps_block) + + def test_t_dongle_led_does_not_send_white_end_frame(self): + source = (ROOT / "esp32_marauder" / "LedInterface.cpp").read_text() + writer = re.search( + r"void LedInterface::writeApa102Color\(.*?\n\}", source, re.S + ).group(0) + self.assertNotIn("writeApa102Byte(0xFF)", writer) + self.assertIn("digitalWrite(5, LOW)", writer) + self.assertIn("digitalWrite(4, LOW)", writer) + + +if __name__ == "__main__": + unittest.main() From 928f598f4babdb7bfe63b2aebce6d7cba0841d45 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:51:45 -0400 Subject: [PATCH 31/57] Harden T-Dongle APA102 idle handling --- esp32_marauder/LedInterface.cpp | 24 +++++++++++++++++------- esp32_marauder/LedInterface.h | 4 ++++ tools/test_t_dongle_hardware.py | 5 +++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index 69b152d57..0f1d1881a 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -35,22 +35,31 @@ void LedInterface::RunSetup() { } void LedInterface::main(uint32_t currentTime) { - if ((!settings_obj.loadSetting("EnableLED")) || - (this->current_mode == MODE_OFF)) { + uint8_t mode_to_render = settings_obj.loadSetting("EnableLED") + ? this->current_mode : MODE_OFF; + + #ifdef HAS_T_DONGLE_LED + // Only clock a frame when the state changes. Continuously sending idle + // frames can make some APA102-compatible parts fall back to white. + if (mode_to_render == this->last_t_dongle_mode) return; + this->last_t_dongle_mode = mode_to_render; + #endif + + if (mode_to_render == MODE_OFF) { this->ledOff(); return; } - else if (this->current_mode == MODE_RAINBOW) { + else if (mode_to_render == MODE_RAINBOW) { this->rainbow(); } - else if (this->current_mode == MODE_ATTACK) { + else if (mode_to_render == MODE_ATTACK) { this->attackLed(); } - else if (this->current_mode == MODE_SNIFF) { + else if (mode_to_render == MODE_SNIFF) { this->sniffLed(); } - else if (this->current_mode == MODE_CUSTOM) { + else if (mode_to_render == MODE_CUSTOM) { return; } else { @@ -87,9 +96,10 @@ void LedInterface::writeApa102Byte(uint8_t value) { } void LedInterface::writeApa102Color(uint8_t red, uint8_t green, uint8_t blue) { + const uint8_t brightness = (red || green || blue) ? 8 : 0; noInterrupts(); for (uint8_t i = 0; i < 4; ++i) writeApa102Byte(0x00); - writeApa102Byte(0xE8); + writeApa102Byte(0xE0 | brightness); writeApa102Byte(blue); writeApa102Byte(green); writeApa102Byte(red); diff --git a/esp32_marauder/LedInterface.h b/esp32_marauder/LedInterface.h index 2801eecb0..c68e69dd5 100644 --- a/esp32_marauder/LedInterface.h +++ b/esp32_marauder/LedInterface.h @@ -23,6 +23,10 @@ class LedInterface { private: uint32_t initTime = 0; + #ifdef HAS_T_DONGLE_LED + uint8_t last_t_dongle_mode = 0xFF; + #endif + int current_fade_itter = 1; int wheel_pos = 255; int wheel_speed = 1; // lower = slower diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index c797b44b1..296cd729d 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -29,9 +29,14 @@ def test_t_dongle_led_does_not_send_white_end_frame(self): r"void LedInterface::writeApa102Color\(.*?\n\}", source, re.S ).group(0) self.assertNotIn("writeApa102Byte(0xFF)", writer) + self.assertIn("? 8 : 0", writer) + self.assertIn("writeApa102Byte(0xE0 | brightness)", writer) self.assertIn("digitalWrite(5, LOW)", writer) self.assertIn("digitalWrite(4, LOW)", writer) + header = (ROOT / "esp32_marauder" / "LedInterface.h").read_text() + self.assertIn("last_t_dongle_mode", header) + if __name__ == "__main__": unittest.main() From 8c3478057d7f313aaa0e784bcb44caf8710cd713 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:42:32 -0400 Subject: [PATCH 32/57] Use reference APA102 driver for T-Dongle --- .github/workflows/build_parallel.yml | 8 ++++++++ .github/workflows/nightly_build.yml | 8 ++++++++ esp32_marauder/LedInterface.cpp | 27 ++++----------------------- esp32_marauder/LedInterface.h | 5 ++++- tools/test_t_dongle_hardware.py | 26 ++++++++++++++++++++------ 5 files changed, 44 insertions(+), 30 deletions(-) diff --git a/.github/workflows/build_parallel.yml b/.github/workflows/build_parallel.yml index 90580df1a..010875415 100644 --- a/.github/workflows/build_parallel.yml +++ b/.github/workflows/build_parallel.yml @@ -149,6 +149,14 @@ jobs: ref: 1.12.0 path: CustomAdafruit_NeoPixel + - name: Install APA102 for LilyGo T-Dongle C5 + if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5' + uses: actions/checkout@v4 + with: + repository: pololu/apa102-arduino + ref: 3.0.0 + path: CustomAPA102 + - name: Install ArduinoJson uses: actions/checkout@v2 with: diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index ce2b59abd..1d5fba23d 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -202,6 +202,14 @@ jobs: ref: 1.12.0 path: CustomAdafruit_NeoPixel + - name: Install APA102 for LilyGo T-Dongle C5 + if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5' + uses: actions/checkout@v4 + with: + repository: pololu/apa102-arduino + ref: 3.0.0 + path: CustomAPA102 + - name: Install ArduinoJson uses: actions/checkout@v2 with: diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index 0f1d1881a..516a849bf 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -26,8 +26,6 @@ void LedInterface::RunSetup() { #ifdef HAS_T_DONGLE_LED pinMode(4, OUTPUT); pinMode(5, OUTPUT); - digitalWrite(4, LOW); - digitalWrite(5, LOW); this->writeApa102Color(0, 0, 0); #endif @@ -87,28 +85,11 @@ void LedInterface::setColor(int r, int g, int b) { } #ifdef HAS_T_DONGLE_LED -void LedInterface::writeApa102Byte(uint8_t value) { - for (int bit = 7; bit >= 0; --bit) { - digitalWrite(5, (value >> bit) & 0x01); - digitalWrite(4, HIGH); - digitalWrite(4, LOW); - } -} - void LedInterface::writeApa102Color(uint8_t red, uint8_t green, uint8_t blue) { - const uint8_t brightness = (red || green || blue) ? 8 : 0; - noInterrupts(); - for (uint8_t i = 0; i < 4; ++i) writeApa102Byte(0x00); - writeApa102Byte(0xE0 | brightness); - writeApa102Byte(blue); - writeApa102Byte(green); - writeApa102Byte(red); - // One LED latches after its color frame. A legacy four-byte 0xFF end frame - // is interpreted as additional full-white data by this board's APA102/SK9822 - // and leaves the LED white after the requested color is shown. - digitalWrite(5, LOW); - digitalWrite(4, LOW); - interrupts(); + const uint8_t brightness = (red || green || blue) ? 10 : 0; + this->t_dongle_led.startFrame(); + this->t_dongle_led.sendColor(red, green, blue, brightness); + this->t_dongle_led.endFrame(1); } #endif diff --git a/esp32_marauder/LedInterface.h b/esp32_marauder/LedInterface.h index c68e69dd5..54c78a034 100644 --- a/esp32_marauder/LedInterface.h +++ b/esp32_marauder/LedInterface.h @@ -9,6 +9,9 @@ #ifdef HAS_NEOPIXEL_LED #include #endif +#ifdef HAS_T_DONGLE_LED + #include +#endif #define Pixels 1 @@ -25,6 +28,7 @@ class LedInterface { #ifdef HAS_T_DONGLE_LED uint8_t last_t_dongle_mode = 0xFF; + APA102<5, 4> t_dongle_led; #endif int current_fade_itter = 1; @@ -41,7 +45,6 @@ class LedInterface { void sniffLed(); #ifdef HAS_T_DONGLE_LED - void writeApa102Byte(uint8_t value); void writeApa102Color(uint8_t red, uint8_t green, uint8_t blue); #endif diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index 296cd729d..d2a56703c 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -23,20 +23,34 @@ def test_t_dongle_enables_uart_gps_header(self): self.assertIn("#define GPS_TX 12", gps_block) self.assertIn("#define GPS_RX 11", gps_block) - def test_t_dongle_led_does_not_send_white_end_frame(self): + def test_t_dongle_led_uses_guarded_reference_library(self): source = (ROOT / "esp32_marauder" / "LedInterface.cpp").read_text() writer = re.search( r"void LedInterface::writeApa102Color\(.*?\n\}", source, re.S ).group(0) - self.assertNotIn("writeApa102Byte(0xFF)", writer) - self.assertIn("? 8 : 0", writer) - self.assertIn("writeApa102Byte(0xE0 | brightness)", writer) - self.assertIn("digitalWrite(5, LOW)", writer) - self.assertIn("digitalWrite(4, LOW)", writer) + self.assertIn("t_dongle_led.startFrame()", writer) + self.assertIn("t_dongle_led.sendColor(red, green, blue, brightness)", writer) + self.assertIn("t_dongle_led.endFrame(1)", writer) + self.assertIn("? 10 : 0", writer) header = (ROOT / "esp32_marauder" / "LedInterface.h").read_text() + guarded_include = re.search( + r"#ifdef HAS_T_DONGLE_LED\s+#include \s+#endif", header + ) + self.assertIsNotNone(guarded_include) + self.assertIn("APA102<5, 4> t_dongle_led", header) self.assertIn("last_t_dongle_mode", header) + for workflow_name in ("build_parallel.yml", "nightly_build.yml"): + workflow = (ROOT / ".github" / "workflows" / workflow_name).read_text() + install_step = re.search( + r"- name: Install APA102 for LilyGo T-Dongle C5(?P.*?)(?=\n\s+- name:)", + workflow, + re.S, + ).group("body") + self.assertIn("if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5'", install_step) + self.assertIn("repository: pololu/apa102-arduino", install_step) + if __name__ == "__main__": unittest.main() From b416590750fbcd750042b08252cc6f44e5f1bb90 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:49:03 -0400 Subject: [PATCH 33/57] Install APA102 in manifest builds --- .github/workflows/build_installer_manifests.yml | 8 ++++++++ tools/test_t_dongle_hardware.py | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_installer_manifests.yml b/.github/workflows/build_installer_manifests.yml index 9166f6c16..93a8e233d 100644 --- a/.github/workflows/build_installer_manifests.yml +++ b/.github/workflows/build_installer_manifests.yml @@ -157,6 +157,14 @@ jobs: ref: 1.12.0 path: CustomAdafruit_NeoPixel + - name: Install APA102 for LilyGo T-Dongle C5 + if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5' + uses: actions/checkout@v4 + with: + repository: pololu/apa102-arduino + ref: 3.0.0 + path: CustomAPA102 + - name: Install ArduinoJson uses: actions/checkout@v4 with: diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index d2a56703c..d67560e79 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -41,7 +41,11 @@ def test_t_dongle_led_uses_guarded_reference_library(self): self.assertIn("APA102<5, 4> t_dongle_led", header) self.assertIn("last_t_dongle_mode", header) - for workflow_name in ("build_parallel.yml", "nightly_build.yml"): + for workflow_name in ( + "build_parallel.yml", + "nightly_build.yml", + "build_installer_manifests.yml", + ): workflow = (ROOT / ".github" / "workflows" / workflow_name).read_text() install_step = re.search( r"- name: Install APA102 for LilyGo T-Dongle C5(?P.*?)(?=\n\s+- name:)", From a15097897ff490e6be742b39efc118f02a2573ab Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 19:09:31 -0400 Subject: [PATCH 34/57] Fix T-Dongle shared display LED pins --- esp32_marauder/LedInterface.cpp | 13 +++++++++++-- esp32_marauder/LedInterface.h | 6 +++++- esp32_marauder/TDongleDisplay.cpp | 27 +++++++++++++++++++++------ esp32_marauder/TDongleDisplay.h | 2 +- esp32_marauder/esp32_marauder.ino | 5 ++++- tools/test_t_dongle_hardware.py | 8 +++++++- 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index 516a849bf..e27ad9b97 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -24,8 +24,8 @@ void LedInterface::RunSetup() { #endif #ifdef HAS_T_DONGLE_LED - pinMode(4, OUTPUT); - pinMode(5, OUTPUT); + pinMode(2, OUTPUT); + pinMode(7, OUTPUT); this->writeApa102Color(0, 0, 0); #endif @@ -73,6 +73,15 @@ uint8_t LedInterface::getMode() { return this->current_mode; } +#ifdef HAS_T_DONGLE_LED +void LedInterface::refresh() { + // GPIO2 is shared with the display MOSI line. Re-send the intended LED + // frame after display traffic, even when the Marauder mode did not change. + this->last_t_dongle_mode = 0xFF; + this->main(millis()); +} +#endif + void LedInterface::setColor(int r, int g, int b) { #ifdef HAS_NEOPIXEL_LED strip.setPixelColor(0, strip.Color(r, g, b)); diff --git a/esp32_marauder/LedInterface.h b/esp32_marauder/LedInterface.h index 54c78a034..5d42a543a 100644 --- a/esp32_marauder/LedInterface.h +++ b/esp32_marauder/LedInterface.h @@ -28,7 +28,7 @@ class LedInterface { #ifdef HAS_T_DONGLE_LED uint8_t last_t_dongle_mode = 0xFF; - APA102<5, 4> t_dongle_led; + APA102<2, 7> t_dongle_led; #endif int current_fade_itter = 1; @@ -54,6 +54,10 @@ class LedInterface { void RunSetup(); void main(uint32_t currentTime); + #ifdef HAS_T_DONGLE_LED + void refresh(); + #endif + void setMode(uint8_t); void setColor(int r, int g, int b); uint8_t getMode(); diff --git a/esp32_marauder/TDongleDisplay.cpp b/esp32_marauder/TDongleDisplay.cpp index f430ead45..519078bfd 100644 --- a/esp32_marauder/TDongleDisplay.cpp +++ b/esp32_marauder/TDongleDisplay.cpp @@ -35,18 +35,31 @@ void TDongleDisplay::drawValue(uint8_t row, const char* label, int value, uint16 tft.drawRightString(String(value), tft.width() - 2, y + 2, 1); } -void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { - if (now - last_update < kRefreshMs) return; +bool TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { + if (now - last_update < kRefreshMs) return false; last_update = now; + bool drew = false; const int ap_count = static_cast(scan.retainedAccessPointCount()); const int station_count = static_cast(scan.retainedStationCount()); const int ble_count = static_cast(scan.retainedBleDeviceCount()); - if (ap_count != last_ap_count) drawValue(0, "WiFi AP", ap_count, TFT_GREEN); - if (station_count != last_station_count) drawValue(1, "Stations", station_count, TFT_CYAN); - if (ble_count != last_ble_count) drawValue(2, "BLE", ble_count, TFT_MAGENTA); - if (scan.set_channel != last_channel) drawValue(3, "Channel", scan.set_channel, TFT_YELLOW); + if (ap_count != last_ap_count) { + drawValue(0, "WiFi AP", ap_count, TFT_GREEN); + drew = true; + } + if (station_count != last_station_count) { + drawValue(1, "Stations", station_count, TFT_CYAN); + drew = true; + } + if (ble_count != last_ble_count) { + drawValue(2, "BLE", ble_count, TFT_MAGENTA); + drew = true; + } + if (scan.set_channel != last_channel) { + drawValue(3, "Channel", scan.set_channel, TFT_YELLOW); + drew = true; + } if (scan.currentScanMode != last_mode) { const int y = 14 + (4 * kRowHeight); @@ -55,6 +68,7 @@ void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { tft.drawString("Mode", 2, y + 2); tft.setTextColor(TFT_ORANGE, TFT_BLACK); tft.drawRightString(TDongleStats::modeLabel(scan.currentScanMode), tft.width() - 2, y + 2, 1); + drew = true; } last_ap_count = ap_count; @@ -62,6 +76,7 @@ void TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { last_ble_count = ble_count; last_channel = scan.set_channel; last_mode = scan.currentScanMode; + return drew; } #endif diff --git a/esp32_marauder/TDongleDisplay.h b/esp32_marauder/TDongleDisplay.h index 643242316..596e73dd9 100644 --- a/esp32_marauder/TDongleDisplay.h +++ b/esp32_marauder/TDongleDisplay.h @@ -11,7 +11,7 @@ class WiFiScan; class TDongleDisplay { public: void begin(); - void update(uint32_t now, const WiFiScan& scan); + bool update(uint32_t now, const WiFiScan& scan); private: TFT_eSPI tft; diff --git a/esp32_marauder/esp32_marauder.ino b/esp32_marauder/esp32_marauder.ino index 33cdbd4bf..57656ec11 100644 --- a/esp32_marauder/esp32_marauder.ino +++ b/esp32_marauder/esp32_marauder.ino @@ -460,7 +460,10 @@ void loop() wifi_scan_obj.main(currentTime); #ifdef HAS_T_DONGLE_DISPLAY - t_dongle_display.update(currentTime, wifi_scan_obj); + const bool t_dongle_display_drew = t_dongle_display.update(currentTime, wifi_scan_obj); + #if defined(HAS_T_DONGLE_LED) + if (t_dongle_display_drew) led_obj.refresh(); + #endif #endif #ifdef HAS_GPS diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index d67560e79..83f74c8c1 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -38,9 +38,15 @@ def test_t_dongle_led_uses_guarded_reference_library(self): r"#ifdef HAS_T_DONGLE_LED\s+#include \s+#endif", header ) self.assertIsNotNone(guarded_include) - self.assertIn("APA102<5, 4> t_dongle_led", header) + self.assertIn("APA102<2, 7> t_dongle_led", header) self.assertIn("last_t_dongle_mode", header) + sketch = (ROOT / "esp32_marauder" / "esp32_marauder.ino").read_text() + self.assertIn("if (t_dongle_display_drew) led_obj.refresh();", sketch) + + display_header = (ROOT / "esp32_marauder" / "TDongleDisplay.h").read_text() + self.assertIn("bool update(uint32_t now, const WiFiScan& scan);", display_header) + for workflow_name in ( "build_parallel.yml", "nightly_build.yml", From 7f1aa4b7409621375bc3f1b53270fc4e6094716a Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 19:30:25 -0400 Subject: [PATCH 35/57] Restore display SPI after T-Dongle LED writes --- esp32_marauder/LedInterface.cpp | 11 +++++++++-- esp32_marauder/LedInterface.h | 3 ++- esp32_marauder/configs.h | 5 +++++ tools/test_t_dongle_hardware.py | 21 +++++++++++++++++++-- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index e27ad9b97..fa4c3c7ed 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -24,8 +24,8 @@ void LedInterface::RunSetup() { #endif #ifdef HAS_T_DONGLE_LED - pinMode(2, OUTPUT); - pinMode(7, OUTPUT); + pinMode(T_DONGLE_LED_DATA_PIN, OUTPUT); + pinMode(T_DONGLE_LED_CLOCK_PIN, OUTPUT); this->writeApa102Color(0, 0, 0); #endif @@ -99,6 +99,13 @@ void LedInterface::writeApa102Color(uint8_t red, uint8_t green, uint8_t blue) { this->t_dongle_led.startFrame(); this->t_dongle_led.sendColor(red, green, blue, brightness); this->t_dongle_led.endFrame(1); + + // The LED bit-bangs the display's MOSI/MISO pins and replaces their GPIO + // matrix routing. Restore the shared hardware-SPI bus before the next TFT + // or SD transaction; reinitializing the TFT itself would clear the panel. + SPI.end(); + SPI.begin(T_DONGLE_SPI_SCLK_PIN, T_DONGLE_SPI_MISO_PIN, + T_DONGLE_SPI_MOSI_PIN, -1); } #endif diff --git a/esp32_marauder/LedInterface.h b/esp32_marauder/LedInterface.h index 5d42a543a..d9c4c917a 100644 --- a/esp32_marauder/LedInterface.h +++ b/esp32_marauder/LedInterface.h @@ -11,6 +11,7 @@ #endif #ifdef HAS_T_DONGLE_LED #include + #include #endif #define Pixels 1 @@ -28,7 +29,7 @@ class LedInterface { #ifdef HAS_T_DONGLE_LED uint8_t last_t_dongle_mode = 0xFF; - APA102<2, 7> t_dongle_led; + APA102 t_dongle_led; #endif int current_fade_itter = 1; diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index 31e04bac4..55f9eb8d1 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -521,6 +521,11 @@ #define HAS_BT #define HAS_T_DONGLE_DISPLAY #define HAS_T_DONGLE_LED + #define T_DONGLE_LED_DATA_PIN 2 + #define T_DONGLE_LED_CLOCK_PIN 7 + #define T_DONGLE_SPI_SCLK_PIN 6 + #define T_DONGLE_SPI_MISO_PIN 7 + #define T_DONGLE_SPI_MOSI_PIN 2 #define HAS_GPS #define HAS_C5_SD #define HAS_SD diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index 83f74c8c1..f849b7675 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -13,6 +13,11 @@ def test_t_dongle_enables_uart_gps_header(self): r"#ifdef MARAUDER_T_DONGLE_C5(?P.*?)#endif", configs, re.S ).group("body") self.assertIn("#define HAS_GPS", feature_block) + self.assertIn("#define T_DONGLE_LED_DATA_PIN 2", feature_block) + self.assertIn("#define T_DONGLE_LED_CLOCK_PIN 7", feature_block) + self.assertIn("#define T_DONGLE_SPI_SCLK_PIN 6", feature_block) + self.assertIn("#define T_DONGLE_SPI_MISO_PIN 7", feature_block) + self.assertIn("#define T_DONGLE_SPI_MOSI_PIN 2", feature_block) gps_block = next( body for body in re.findall( @@ -32,13 +37,25 @@ def test_t_dongle_led_uses_guarded_reference_library(self): self.assertIn("t_dongle_led.sendColor(red, green, blue, brightness)", writer) self.assertIn("t_dongle_led.endFrame(1)", writer) self.assertIn("? 10 : 0", writer) + self.assertIn("SPI.end()", writer) + self.assertIn( + "SPI.begin(T_DONGLE_SPI_SCLK_PIN, T_DONGLE_SPI_MISO_PIN,", + writer, + ) header = (ROOT / "esp32_marauder" / "LedInterface.h").read_text() guarded_include = re.search( - r"#ifdef HAS_T_DONGLE_LED\s+#include \s+#endif", header + r"#ifdef HAS_T_DONGLE_LED\s+" + r"#include \s+" + r"#include \s+" + r"#endif", + header, ) self.assertIsNotNone(guarded_include) - self.assertIn("APA102<2, 7> t_dongle_led", header) + self.assertIn( + "APA102 t_dongle_led", + header, + ) self.assertIn("last_t_dongle_mode", header) sketch = (ROOT / "esp32_marauder" / "esp32_marauder.ino").read_text() From 3259173dd616201a2957dcd4add6355b676506a2 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 19:45:50 -0400 Subject: [PATCH 36/57] Defer display SPI restore until redraw --- esp32_marauder/LedInterface.cpp | 7 ------- esp32_marauder/LedInterface.h | 1 - esp32_marauder/TDongleDisplay.cpp | 26 +++++++++++++++++++++----- tools/test_t_dongle_hardware.py | 12 ++++++------ 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/esp32_marauder/LedInterface.cpp b/esp32_marauder/LedInterface.cpp index fa4c3c7ed..20b56d469 100644 --- a/esp32_marauder/LedInterface.cpp +++ b/esp32_marauder/LedInterface.cpp @@ -99,13 +99,6 @@ void LedInterface::writeApa102Color(uint8_t red, uint8_t green, uint8_t blue) { this->t_dongle_led.startFrame(); this->t_dongle_led.sendColor(red, green, blue, brightness); this->t_dongle_led.endFrame(1); - - // The LED bit-bangs the display's MOSI/MISO pins and replaces their GPIO - // matrix routing. Restore the shared hardware-SPI bus before the next TFT - // or SD transaction; reinitializing the TFT itself would clear the panel. - SPI.end(); - SPI.begin(T_DONGLE_SPI_SCLK_PIN, T_DONGLE_SPI_MISO_PIN, - T_DONGLE_SPI_MOSI_PIN, -1); } #endif diff --git a/esp32_marauder/LedInterface.h b/esp32_marauder/LedInterface.h index d9c4c917a..a95c68ade 100644 --- a/esp32_marauder/LedInterface.h +++ b/esp32_marauder/LedInterface.h @@ -11,7 +11,6 @@ #endif #ifdef HAS_T_DONGLE_LED #include - #include #endif #define Pixels 1 diff --git a/esp32_marauder/TDongleDisplay.cpp b/esp32_marauder/TDongleDisplay.cpp index 519078bfd..7f171bf88 100644 --- a/esp32_marauder/TDongleDisplay.cpp +++ b/esp32_marauder/TDongleDisplay.cpp @@ -4,6 +4,7 @@ #include "WiFiScan.h" #include "TDongleStats.h" +#include namespace { constexpr uint32_t kRefreshMs = 500; @@ -43,25 +44,40 @@ bool TDongleDisplay::update(uint32_t now, const WiFiScan& scan) { const int ap_count = static_cast(scan.retainedAccessPointCount()); const int station_count = static_cast(scan.retainedStationCount()); const int ble_count = static_cast(scan.retainedBleDeviceCount()); + const bool ap_changed = ap_count != last_ap_count; + const bool station_changed = station_count != last_station_count; + const bool ble_changed = ble_count != last_ble_count; + const bool channel_changed = scan.set_channel != last_channel; + const bool mode_changed = scan.currentScanMode != last_mode; - if (ap_count != last_ap_count) { + if (!(ap_changed || station_changed || ble_changed || channel_changed || mode_changed)) { + return false; + } + + // LED updates bit-bang the TFT's MOSI/MISO pins. Reclaim the shared bus only + // when a redraw is required, then let the caller write the LED state last. + SPI.end(); + SPI.begin(T_DONGLE_SPI_SCLK_PIN, T_DONGLE_SPI_MISO_PIN, + T_DONGLE_SPI_MOSI_PIN, -1); + + if (ap_changed) { drawValue(0, "WiFi AP", ap_count, TFT_GREEN); drew = true; } - if (station_count != last_station_count) { + if (station_changed) { drawValue(1, "Stations", station_count, TFT_CYAN); drew = true; } - if (ble_count != last_ble_count) { + if (ble_changed) { drawValue(2, "BLE", ble_count, TFT_MAGENTA); drew = true; } - if (scan.set_channel != last_channel) { + if (channel_changed) { drawValue(3, "Channel", scan.set_channel, TFT_YELLOW); drew = true; } - if (scan.currentScanMode != last_mode) { + if (mode_changed) { const int y = 14 + (4 * kRowHeight); tft.fillRect(0, y, tft.width(), kRowHeight, TFT_BLACK); tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK); diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index f849b7675..88ab7576f 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -37,17 +37,12 @@ def test_t_dongle_led_uses_guarded_reference_library(self): self.assertIn("t_dongle_led.sendColor(red, green, blue, brightness)", writer) self.assertIn("t_dongle_led.endFrame(1)", writer) self.assertIn("? 10 : 0", writer) - self.assertIn("SPI.end()", writer) - self.assertIn( - "SPI.begin(T_DONGLE_SPI_SCLK_PIN, T_DONGLE_SPI_MISO_PIN,", - writer, - ) + self.assertNotIn("SPI.begin", writer) header = (ROOT / "esp32_marauder" / "LedInterface.h").read_text() guarded_include = re.search( r"#ifdef HAS_T_DONGLE_LED\s+" r"#include \s+" - r"#include \s+" r"#endif", header, ) @@ -64,6 +59,11 @@ def test_t_dongle_led_uses_guarded_reference_library(self): display_header = (ROOT / "esp32_marauder" / "TDongleDisplay.h").read_text() self.assertIn("bool update(uint32_t now, const WiFiScan& scan);", display_header) + display_source = (ROOT / "esp32_marauder" / "TDongleDisplay.cpp").read_text() + restore_index = display_source.index("SPI.begin(T_DONGLE_SPI_SCLK_PIN") + draw_index = display_source.index('drawValue(0, "WiFi AP"') + self.assertLess(restore_index, draw_index) + for workflow_name in ( "build_parallel.yml", "nightly_build.yml", From c26906f0c12dbb7eb44f592ef1bf24a4edbcb599 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 20:04:16 -0400 Subject: [PATCH 37/57] Make T-Dongle LED the final bus writer --- esp32_marauder/esp32_marauder.ino | 11 ++++++----- tools/test_t_dongle_hardware.py | 9 ++++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/esp32_marauder/esp32_marauder.ino b/esp32_marauder/esp32_marauder.ino index 57656ec11..34633ca09 100644 --- a/esp32_marauder/esp32_marauder.ino +++ b/esp32_marauder/esp32_marauder.ino @@ -460,10 +460,7 @@ void loop() wifi_scan_obj.main(currentTime); #ifdef HAS_T_DONGLE_DISPLAY - const bool t_dongle_display_drew = t_dongle_display.update(currentTime, wifi_scan_obj); - #if defined(HAS_T_DONGLE_LED) - if (t_dongle_display_drew) led_obj.refresh(); - #endif + t_dongle_display.update(currentTime, wifi_scan_obj); #endif #ifdef HAS_GPS @@ -488,7 +485,11 @@ void loop() xiao_led.main(); #elif defined(MARAUDER_M5STICKC) stickc_led.main(); - #elif defined(HAS_NEOPIXEL_LED) || defined(HAS_T_DONGLE_LED) + #elif defined(HAS_T_DONGLE_LED) + // The LED shares GPIO2/GPIO7 with the display/SD bus. Always make it the + // final writer so later SPI activity cannot leave it latched white. + led_obj.refresh(); + #elif defined(HAS_NEOPIXEL_LED) led_obj.main(currentTime); #endif diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index 88ab7576f..835ce2d85 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -54,7 +54,14 @@ def test_t_dongle_led_uses_guarded_reference_library(self): self.assertIn("last_t_dongle_mode", header) sketch = (ROOT / "esp32_marauder" / "esp32_marauder.ino").read_text() - self.assertIn("if (t_dongle_display_drew) led_obj.refresh();", sketch) + final_writer = re.search( + r"#elif defined\(HAS_T_DONGLE_LED\)(?P.*?)" + r"#elif defined\(HAS_NEOPIXEL_LED\)", + sketch, + re.S, + ).group("body") + self.assertIn("led_obj.refresh();", final_writer) + self.assertLess(sketch.index("buffer_obj.save();"), sketch.index(final_writer)) display_header = (ROOT / "esp32_marauder" / "TDongleDisplay.h").read_text() self.assertIn("bool update(uint32_t now, const WiFiScan& scan);", display_header) From 649a87ff84e21aadb292c91f653a1fa71d7fd961 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Wed, 19 Aug 2026 20:17:16 -0400 Subject: [PATCH 38/57] Correct T-Dongle LED clock pin --- esp32_marauder/configs.h | 2 +- tools/test_t_dongle_hardware.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index 55f9eb8d1..72512aef6 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -522,7 +522,7 @@ #define HAS_T_DONGLE_DISPLAY #define HAS_T_DONGLE_LED #define T_DONGLE_LED_DATA_PIN 2 - #define T_DONGLE_LED_CLOCK_PIN 7 + #define T_DONGLE_LED_CLOCK_PIN 6 #define T_DONGLE_SPI_SCLK_PIN 6 #define T_DONGLE_SPI_MISO_PIN 7 #define T_DONGLE_SPI_MOSI_PIN 2 diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index 835ce2d85..5482b0f0b 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -14,7 +14,7 @@ def test_t_dongle_enables_uart_gps_header(self): ).group("body") self.assertIn("#define HAS_GPS", feature_block) self.assertIn("#define T_DONGLE_LED_DATA_PIN 2", feature_block) - self.assertIn("#define T_DONGLE_LED_CLOCK_PIN 7", feature_block) + self.assertIn("#define T_DONGLE_LED_CLOCK_PIN 6", feature_block) self.assertIn("#define T_DONGLE_SPI_SCLK_PIN 6", feature_block) self.assertIn("#define T_DONGLE_SPI_MISO_PIN 7", feature_block) self.assertIn("#define T_DONGLE_SPI_MOSI_PIN 2", feature_block) From 9a164862259a9551d4fecb061ec738e9371c832b Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:04:49 -0400 Subject: [PATCH 39/57] fix: scan complete IPv4 subnet ranges --- esp32_marauder/IPv4Range.cpp | 43 +++++++++++++++ esp32_marauder/IPv4Range.h | 20 +++++++ esp32_marauder/WiFiScan.cpp | 40 ++++++++++---- esp32_marauder/WiFiScan.h | 2 + esp32_marauder/configs.h | 2 +- esp32_marauder/utils.h | 70 +++++++++++------------- platformio.ini | 1 + test/test_ipv4_range/test_main.cpp | 86 ++++++++++++++++++++++++++++++ 8 files changed, 214 insertions(+), 50 deletions(-) create mode 100644 esp32_marauder/IPv4Range.cpp create mode 100644 esp32_marauder/IPv4Range.h create mode 100644 test/test_ipv4_range/test_main.cpp diff --git a/esp32_marauder/IPv4Range.cpp b/esp32_marauder/IPv4Range.cpp new file mode 100644 index 000000000..5e9c7cfef --- /dev/null +++ b/esp32_marauder/IPv4Range.cpp @@ -0,0 +1,43 @@ +#include "IPv4Range.h" + +namespace marauder { + +namespace { + +bool isContiguousMask(uint32_t mask) { + const uint32_t inverted = ~mask; + return (inverted & (inverted + 1U)) == 0U; +} + +} // namespace + +IPv4HostRange ipv4HostRange(uint32_t address, uint32_t subnetMask) { + const uint32_t network = address & subnetMask; + const uint32_t broadcast = network | ~subnetMask; + const bool valid = isContiguousMask(subnetMask) && + (broadcast - network) >= 2U; + + return {network, broadcast, valid ? network + 1U : 0U, + valid ? broadcast - 1U : 0U, valid}; +} + +uint32_t nextIPv4Host(uint32_t current, const IPv4HostRange& range) { + if (!range.valid || current >= range.last) { + return 0U; + } + if (current < range.first) { + return range.first; + } + return current + 1U; +} + +uint32_t previousIPv4Host(uint32_t current, uint32_t steps, + const IPv4HostRange& range) { + if (!range.valid || current < range.first || current > range.last || + steps > current - range.first) { + return 0U; + } + return current - steps; +} + +} // namespace marauder diff --git a/esp32_marauder/IPv4Range.h b/esp32_marauder/IPv4Range.h new file mode 100644 index 000000000..5049c765e --- /dev/null +++ b/esp32_marauder/IPv4Range.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace marauder { + +struct IPv4HostRange { + uint32_t network; + uint32_t broadcast; + uint32_t first; + uint32_t last; + bool valid; +}; + +IPv4HostRange ipv4HostRange(uint32_t address, uint32_t subnetMask); +uint32_t nextIPv4Host(uint32_t current, const IPv4HostRange& range); +uint32_t previousIPv4Host(uint32_t current, uint32_t steps, + const IPv4HostRange& range); + +} // namespace marauder diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 80dcf91f0..694695164 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -3363,7 +3363,8 @@ void WiFiScan::RunPingScan(uint8_t scan_mode, uint16_t color) { #endif this->prepareScanStage(TFT_RED, TFT_BLACK); #endif - this->current_scan_ip = this->gateway; + this->current_scan_ip = getNetworkIP(this->ip_addr, this->subnet); + this->last_scan_ip = IPAddress(0, 0, 0, 0); //Serial.print(F("Cleared IPs: ")); this->clearList(CLEAR_IPS); if (scan_mode == WIFI_PING_SCAN) @@ -3442,8 +3443,10 @@ void WiFiScan::RunPortScanAll(uint8_t scan_mode, uint16_t color) { (scan_mode == WIFI_SCAN_DNS) || (scan_mode == WIFI_SCAN_HTTP) || (scan_mode == WIFI_SCAN_HTTPS) || - (scan_mode == WIFI_SCAN_RDP)) - this->current_scan_ip = this->gateway; + (scan_mode == WIFI_SCAN_RDP)) { + this->current_scan_ip = getNetworkIP(this->ip_addr, this->subnet); + this->last_scan_ip = IPAddress(0, 0, 0, 0); + } Serial.println(F("Starting Port Scan with...")); this->showNetworkInfo(); @@ -10468,6 +10471,18 @@ bool WiFiScan::checkHostPort(IPAddress ip, uint16_t port, uint16_t timeout) { return false; } +IPAddress WiFiScan::advanceScanIP() { + do { + this->current_scan_ip = getNextIP(this->current_scan_ip, this->subnet); + } while ((this->current_scan_ip != IPAddress(0, 0, 0, 0)) && + (this->current_scan_ip == this->ip_addr)); + + if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { + this->last_scan_ip = this->current_scan_ip; + } + return this->current_scan_ip; +} + #ifndef HAS_IDF_3 bool WiFiScan::readARP(IPAddress targ_ip) { // Convert IPAddress to ip4_addr_t using IP4_ADDR @@ -10537,7 +10552,8 @@ bool WiFiScan::checkHostPort(IPAddress ip, uint16_t port, uint16_t timeout) { //this->arp_count = 0; - if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { + if (this->current_scan_ip != IPAddress(0, 0, 0, 0) && + this->advanceScanIP() != IPAddress(0, 0, 0, 0)) { ip4_addr_t lwip_ip; IP4_ADDR(&lwip_ip, this->current_scan_ip[0], @@ -10549,8 +10565,6 @@ bool WiFiScan::checkHostPort(IPAddress ip, uint16_t port, uint16_t timeout) { delay(100); - this->current_scan_ip = getNextIP(this->current_scan_ip, this->subnet); - this->arp_count++; if (this->arp_count >= 10) { @@ -10558,7 +10572,7 @@ bool WiFiScan::checkHostPort(IPAddress ip, uint16_t port, uint16_t timeout) { this->arp_count = 0; - for (int i = 10; i > 0; i--) { + for (int i = 9; i >= 0; i--) { IPAddress check_ip = getPrevIP(this->current_scan_ip, this->subnet, i); display_string = ""; output_line = ""; @@ -10586,7 +10600,7 @@ bool WiFiScan::checkHostPort(IPAddress ip, uint16_t port, uint16_t timeout) { for (int i = this->arp_count; i > 0; i--) { delay(250); - IPAddress check_ip = getPrevIP(this->current_scan_ip, this->subnet, i); + IPAddress check_ip = getPrevIP(this->last_scan_ip, this->subnet, i - 1); display_string = ""; output_line = ""; if (this->readARP(check_ip)) { @@ -10622,10 +10636,11 @@ void WiFiScan::pingScan(uint8_t scan_mode) { if (scan_mode == WIFI_PING_SCAN) { if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { - this->current_scan_ip = getNextIP(this->current_scan_ip, this->subnet); + this->advanceScanIP(); // Check if IP is alive - if (this->isHostAlive(this->current_scan_ip)) { + if ((this->current_scan_ip != IPAddress(0, 0, 0, 0)) && + this->isHostAlive(this->current_scan_ip)) { output_line = this->current_scan_ip.toString(); display_string.concat(output_line); uint8_t temp_len = display_string.length(); @@ -10668,7 +10683,10 @@ void WiFiScan::pingScan(uint8_t scan_mode) { targ_port = 3389; if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { - this->current_scan_ip = getNextIP(this->current_scan_ip, this->subnet); + this->advanceScanIP(); + if (this->current_scan_ip == IPAddress(0, 0, 0, 0)) { + return; + } #ifndef HAS_IDF_3 if (this->singleARP(this->current_scan_ip)) { #else diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index ec2460fb2..dc39eec21 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -716,6 +716,7 @@ class WiFiScan bool singleARP(IPAddress ip_addr); void pingScan(uint8_t scan_mode = WIFI_PING_SCAN); void portScan(uint8_t scan_mode = WIFI_PORT_SCAN_ALL, uint16_t targ_port = 22); + IPAddress advanceScanIP(); bool isHostAlive(IPAddress ip); bool checkHostPort(IPAddress ip, uint16_t port, uint16_t timeout = 100); String extractManufacturer(const uint8_t* payload); @@ -930,6 +931,7 @@ class WiFiScan IPAddress subnet; IPAddress current_scan_ip; + IPAddress last_scan_ip; uint16_t current_scan_port = 1; diff --git a/esp32_marauder/configs.h b/esp32_marauder/configs.h index 72512aef6..41444ed34 100644 --- a/esp32_marauder/configs.h +++ b/esp32_marauder/configs.h @@ -42,7 +42,7 @@ #define JSON_SETTING_SIZE 2048 -#define MARAUDER_VERSION "v1.15.0" +#define MARAUDER_VERSION "v1.15.1" #define GRAPH_REFRESH 100 diff --git a/esp32_marauder/utils.h b/esp32_marauder/utils.h index 397ac1454..23d2a3a52 100644 --- a/esp32_marauder/utils.h +++ b/esp32_marauder/utils.h @@ -7,6 +7,7 @@ #include #include "configs.h" +#include "IPv4Range.h" #include "MarauderMacAddress.h" #include "esp_heap_caps.h" @@ -193,52 +194,45 @@ inline void convertMacStringToUint8(const String& macStr, uint8_t macAddr[6]) { } -inline IPAddress getNextIP(IPAddress currentIP, IPAddress subnetMask) { - // Convert IPAddress to uint32_t - uint32_t ipInt = (currentIP[0] << 24) | (currentIP[1] << 16) | (currentIP[2] << 8) | currentIP[3]; - uint32_t maskInt = (subnetMask[0] << 24) | (subnetMask[1] << 16) | (subnetMask[2] << 8) | subnetMask[3]; - - uint32_t networkBase = ipInt & maskInt; - uint32_t broadcast = networkBase | ~maskInt; - - uint32_t nextIP = ipInt + 1; - - if (nextIP <= networkBase) { - nextIP = networkBase + 1; - } - if (nextIP >= broadcast) { - return IPAddress(0, 0, 0, 0); // no more IPs - } +inline uint32_t ipAddressToUint32(const IPAddress& address) { + return (static_cast(address[0]) << 24) | + (static_cast(address[1]) << 16) | + (static_cast(address[2]) << 8) | + static_cast(address[3]); +} +inline IPAddress uint32ToIPAddress(uint32_t address) { return IPAddress( - (nextIP >> 24) & 0xFF, - (nextIP >> 16) & 0xFF, - (nextIP >> 8) & 0xFF, - nextIP & 0xFF + (address >> 24) & 0xFF, + (address >> 16) & 0xFF, + (address >> 8) & 0xFF, + address & 0xFF ); } -inline IPAddress getPrevIP(IPAddress currentIP, IPAddress subnetMask, uint16_t stepsBack) { - // Convert IPAddress to uint32_t - uint32_t ipInt = (currentIP[0] << 24) | (currentIP[1] << 16) | (currentIP[2] << 8) | currentIP[3]; - uint32_t maskInt = (subnetMask[0] << 24) | (subnetMask[1] << 16) | (subnetMask[2] << 8) | subnetMask[3]; - - uint32_t networkBase = ipInt & maskInt; - uint32_t broadcast = networkBase | ~maskInt; +inline marauder::IPv4HostRange getIPHostRange(const IPAddress& address, + const IPAddress& subnetMask) { + return marauder::ipv4HostRange(ipAddressToUint32(address), + ipAddressToUint32(subnetMask)); +} - uint32_t prevIP = ipInt - stepsBack; +inline IPAddress getNetworkIP(const IPAddress& address, + const IPAddress& subnetMask) { + return uint32ToIPAddress(getIPHostRange(address, subnetMask).network); +} - // Ensure prevIP is not below the usable range - if (prevIP <= networkBase) { - return IPAddress(0, 0, 0, 0); // No more IPs - } +inline IPAddress getNextIP(const IPAddress& currentIP, + const IPAddress& subnetMask) { + const marauder::IPv4HostRange range = getIPHostRange(currentIP, subnetMask); + return uint32ToIPAddress( + marauder::nextIPv4Host(ipAddressToUint32(currentIP), range)); +} - return IPAddress( - (prevIP >> 24) & 0xFF, - (prevIP >> 16) & 0xFF, - (prevIP >> 8) & 0xFF, - prevIP & 0xFF - ); +inline IPAddress getPrevIP(const IPAddress& currentIP, + const IPAddress& subnetMask, uint16_t stepsBack) { + const marauder::IPv4HostRange range = getIPHostRange(currentIP, subnetMask); + return uint32ToIPAddress(marauder::previousIPv4Host( + ipAddressToUint32(currentIP), stepsBack, range)); } inline uint16_t getNextPort(uint16_t port) { diff --git a/platformio.ini b/platformio.ini index 5fdab083b..fe73d5450 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,6 +19,7 @@ build_src_filter = + + + + + build_flags = -std=gnu++17 -Wall diff --git a/test/test_ipv4_range/test_main.cpp b/test/test_ipv4_range/test_main.cpp new file mode 100644 index 000000000..f07f1be07 --- /dev/null +++ b/test/test_ipv4_range/test_main.cpp @@ -0,0 +1,86 @@ +#include + +#include "IPv4Range.h" + +namespace { + +constexpr uint32_t ip(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { + return (static_cast(a) << 24) | + (static_cast(b) << 16) | + (static_cast(c) << 8) | static_cast(d); +} + +} // namespace + +void setUp() {} +void tearDown() {} + +void test_slash_24_range_uses_network_and_broadcast_boundaries() { + const auto range = marauder::ipv4HostRange(ip(192, 168, 1, 77), + ip(255, 255, 255, 0)); + TEST_ASSERT_TRUE(range.valid); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 0), range.network); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 255), range.broadcast); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 1), range.first); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 254), range.last); +} + +void test_slash_23_range_includes_hosts_below_gateway_octet() { + const auto range = marauder::ipv4HostRange(ip(10, 0, 5, 1), + ip(255, 255, 254, 0)); + TEST_ASSERT_EQUAL_HEX32(ip(10, 0, 4, 1), range.first); + TEST_ASSERT_EQUAL_HEX32(ip(10, 0, 5, 254), range.last); + TEST_ASSERT_EQUAL_HEX32(range.first, + marauder::nextIPv4Host(range.network, range)); +} + +void test_gateway_near_broadcast_does_not_shorten_range() { + const auto range = marauder::ipv4HostRange(ip(172, 16, 35, 126), + ip(255, 255, 255, 192)); + TEST_ASSERT_EQUAL_HEX32(ip(172, 16, 35, 65), range.first); + TEST_ASSERT_EQUAL_HEX32(ip(172, 16, 35, 126), range.last); +} + +void test_iteration_stops_after_last_host() { + const auto range = marauder::ipv4HostRange(ip(192, 168, 1, 10), + ip(255, 255, 255, 252)); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 9), + marauder::nextIPv4Host(range.network, range)); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 10), + marauder::nextIPv4Host(range.first, range)); + TEST_ASSERT_EQUAL_HEX32(0, marauder::nextIPv4Host(range.last, range)); +} + +void test_previous_host_rejects_underflow_and_accepts_current_host() { + const auto range = marauder::ipv4HostRange(ip(192, 168, 1, 10), + ip(255, 255, 255, 0)); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 10), + marauder::previousIPv4Host(ip(192, 168, 1, 10), 0, + range)); + TEST_ASSERT_EQUAL_HEX32(ip(192, 168, 1, 1), + marauder::previousIPv4Host(ip(192, 168, 1, 10), 9, + range)); + TEST_ASSERT_EQUAL_HEX32(0, + marauder::previousIPv4Host(ip(192, 168, 1, 10), 10, + range)); +} + +void test_noncontiguous_and_hostless_masks_are_rejected() { + TEST_ASSERT_FALSE( + marauder::ipv4HostRange(ip(10, 0, 0, 1), ip(255, 0, 255, 0)).valid); + TEST_ASSERT_FALSE( + marauder::ipv4HostRange(ip(10, 0, 0, 1), ip(255, 255, 255, 254)).valid); + TEST_ASSERT_FALSE( + marauder::ipv4HostRange(ip(10, 0, 0, 1), ip(255, 255, 255, 255)).valid); +} + +int main() { + UNITY_BEGIN(); + RUN_TEST(test_slash_24_range_uses_network_and_broadcast_boundaries); + RUN_TEST(test_slash_23_range_includes_hosts_below_gateway_octet); + RUN_TEST(test_gateway_near_broadcast_does_not_shorten_range); + RUN_TEST(test_iteration_stops_after_last_host); + RUN_TEST(test_previous_host_rejects_underflow_and_accepts_current_host); + RUN_TEST(test_noncontiguous_and_hostless_masks_are_rejected); + return UNITY_END(); +} From be00fdbc2b9392480700156763d1f993ef40bd69 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Thu, 20 Aug 2026 15:08:05 -0400 Subject: [PATCH 40/57] fix(build): scope T-Dongle partition layout --- .github/workflows/build_installer_manifests.yml | 4 ++++ .github/workflows/build_parallel.yml | 4 ++++ .github/workflows/nightly_build.yml | 4 ++++ .../partitions/t_dongle_c5.csv | 2 +- tools/test_t_dongle_hardware.py | 14 ++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) rename esp32_marauder/partitions.csv => installer/partitions/t_dongle_c5.csv (77%) diff --git a/.github/workflows/build_installer_manifests.yml b/.github/workflows/build_installer_manifests.yml index 93a8e233d..011bc25e7 100644 --- a/.github/workflows/build_installer_manifests.yml +++ b/.github/workflows/build_installer_manifests.yml @@ -235,6 +235,10 @@ jobs: done fi + - name: Configure LilyGo T-Dongle C5 partition table + if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5' + run: cp installer/partitions/t_dongle_c5.csv esp32_marauder/partitions.csv + - name: Build Marauder for ${{ matrix.board.name }} uses: ArminJo/arduino-test-compile@v3.3.0 with: diff --git a/.github/workflows/build_parallel.yml b/.github/workflows/build_parallel.yml index 010875415..6e1b4d135 100644 --- a/.github/workflows/build_parallel.yml +++ b/.github/workflows/build_parallel.yml @@ -244,6 +244,10 @@ jobs: sed -i 's/^\/\/#include <${{ matrix.board.tft_file }}>/#include <${{ matrix.board.tft_file }}>/' /home/runner/work/ESP32Marauder/ESP32Marauder/CustomTFT_eSPI/User_Setup_Select.h fi + - name: Configure LilyGo T-Dongle C5 partition table + if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5' + run: cp installer/partitions/t_dongle_c5.csv esp32_marauder/partitions.csv + - name: Build Marauder for ${{ matrix.board.name }} uses: ArminJo/arduino-test-compile@v3.3.0 with: diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 1d5fba23d..50318e33f 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -297,6 +297,10 @@ jobs: sed -i 's/^\/\/#include <${{ matrix.board.tft_file }}>/#include <${{ matrix.board.tft_file }}>/' /home/runner/work/ESP32Marauder/ESP32Marauder/CustomTFT_eSPI/User_Setup_Select.h fi + - name: Configure LilyGo T-Dongle C5 partition table + if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5' + run: cp installer/partitions/t_dongle_c5.csv esp32_marauder/partitions.csv + - name: Build Marauder for ${{ matrix.board.name }} uses: ArminJo/arduino-test-compile@v3.3.0 with: diff --git a/esp32_marauder/partitions.csv b/installer/partitions/t_dongle_c5.csv similarity index 77% rename from esp32_marauder/partitions.csv rename to installer/partitions/t_dongle_c5.csv index 4e9cf237f..f0282eb2e 100644 --- a/esp32_marauder/partitions.csv +++ b/installer/partitions/t_dongle_c5.csv @@ -1,4 +1,4 @@ -# LilyGo T-Dongle C5 16 MB layout (selected only with PartitionScheme=custom) +# LilyGo T-Dongle C5 16 MB layout # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, diff --git a/tools/test_t_dongle_hardware.py b/tools/test_t_dongle_hardware.py index 5482b0f0b..d50c20c53 100644 --- a/tools/test_t_dongle_hardware.py +++ b/tools/test_t_dongle_hardware.py @@ -84,6 +84,20 @@ def test_t_dongle_led_uses_guarded_reference_library(self): ).group("body") self.assertIn("if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5'", install_step) self.assertIn("repository: pololu/apa102-arduino", install_step) + partition_step = re.search( + r"- name: Configure LilyGo T-Dongle C5 partition table" + r"(?P.*?)(?=\n\s+- name:)", + workflow, + re.S, + ).group("body") + self.assertIn("if: matrix.board.flag == 'MARAUDER_T_DONGLE_C5'", partition_step) + self.assertIn( + "cp installer/partitions/t_dongle_c5.csv esp32_marauder/partitions.csv", + partition_step, + ) + + self.assertFalse((ROOT / "esp32_marauder" / "partitions.csv").exists()) + self.assertTrue((ROOT / "installer" / "partitions" / "t_dongle_c5.csv").is_file()) if __name__ == "__main__": From fe9b63bb2ff08175e17512d6a4a8dceb6845cc9d Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:23:04 -0400 Subject: [PATCH 41/57] ci: use 8 MB OTA layout for C5 DevKit --- .github/workflows/build_parallel.yml | 2 +- .github/workflows/nightly_build.yml | 2 +- tools/test_installer_manifest.py | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_parallel.yml b/.github/workflows/build_parallel.yml index 6e1b4d135..771275dfd 100644 --- a/.github/workflows/build_parallel.yml +++ b/.github/workflows/build_parallel.yml @@ -36,7 +36,7 @@ jobs: - { name: "Marauder CYD 3.5inch", flag: "MARAUDER_CYD_3_5_INCH", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_3_5_inch", tft: true, tft_file: "User_Setup_cyd_3_5_inch.h", build_dir: "d32", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } + - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=default_8MB,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=custom,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5NanoC6", flag: "MARAUDER_M5_NANO_C6", fbqn: "esp32:esp32:esp32c6:CDCOnBoot=cdc,PartitionScheme=min_spiffs", file_name: "m5nanoc6", tft: false, tft_file: "", build_dir: "esp32c6", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "Marauder Pancake", flag: "MARAUDER_PANCAKE", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=default_8MB,PSRAM=enabled", file_name: "pancake", tft: true, tft_file: "User_Setup_marauder_pancake.h", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5" } diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 50318e33f..4eb462e46 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -99,7 +99,7 @@ jobs: - { name: "Marauder CYD 3.5inch", flag: "MARAUDER_CYD_3_5_INCH", fbqn: "esp32:esp32:d32:PartitionScheme=min_spiffs", file_name: "cyd_3_5_inch", tft: true, tft_file: "User_Setup_cyd_3_5_inch.h", build_dir: "d32", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer", flag: "MARAUDER_CARDPUTER", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer", tft: true, tft_file: "User_Setup_marauder_m5cardputer.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5Cardputer ADV", flag: "MARAUDER_CARDPUTER_ADV", fbqn: "esp32:esp32:esp32s3:PartitionScheme=min_spiffs,FlashSize=8M,PSRAM=disabled", file_name: "m5cardputer_adv", tft: true, tft_file: "User_Setup_marauder_m5cardputer_adv.h", build_dir: "esp32s3", addr: "0x1000", idf_ver: "2.0.11", nimble_ver: "1.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=min_spiffs,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } + - { name: "ESP32-C5-DevKitC-1", flag: "MARAUDER_C5", fbqn: "esp32:esp32:esp32c5:FlashSize=8M,PartitionScheme=default_8MB,PSRAM=enabled", file_name: "esp32c5devkitc1", tft: false, tft_file: "", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "LilyGo T-Dongle C5", flag: "MARAUDER_T_DONGLE_C5", fbqn: "esp32:esp32:esp32c5:CDCOnBoot=cdc,FlashMode=qio,FlashSize=16M,PartitionScheme=custom,PSRAM=enabled", file_name: "t_dongle_c5", tft: true, tft_file: "User_Setup_marauder_t_dongle_c5.h", tft_repo: "H4W9/TFT_eSPI", tft_ref: "ESP32-C5", build_dir: "esp32c5", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } - { name: "M5NanoC6", flag: "MARAUDER_M5_NANO_C6", fbqn: "esp32:esp32:esp32c6:CDCOnBoot=cdc,PartitionScheme=min_spiffs", file_name: "m5nanoc6", tft: false, tft_file: "", build_dir: "esp32c6", addr: "0x2000", idf_ver: "3.3.4", nimble_ver: "2.3.8", esp_async: "bigbrodude6119/ESPAsyncWebServer", esp_async_ver: "master" } diff --git a/tools/test_installer_manifest.py b/tools/test_installer_manifest.py index 531f7e955..9fa191b5c 100644 --- a/tools/test_installer_manifest.py +++ b/tools/test_installer_manifest.py @@ -76,6 +76,9 @@ def test_registry_contains_unique_complete_build_targets(self) -> None: ) self.assertEqual(registry_flags - private_flags, workflow_flags) self.assertIn("MARAUDER_T_DONGLE_C5", workflow_flags) + c5_devkit = next(board for board in boards if board["flag"] == "MARAUDER_C5") + self.assertIn("FlashSize=8M", c5_devkit["fbqn"]) + self.assertIn("PartitionScheme=default_8MB", c5_devkit["fbqn"]) self.assertEqual( len(registry_flags), len(registry["targets"]), From bcbaf950619285d335f6b6948e83dc87c3c4e4ae Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:32:54 -0400 Subject: [PATCH 42/57] fix: rework network scanner display UI --- esp32_marauder/WiFiScan.cpp | 116 +++++++++++++++++++++++------------- esp32_marauder/WiFiScan.h | 6 +- 2 files changed, 80 insertions(+), 42 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 694695164..94812cf06 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -2093,7 +2093,7 @@ void WiFiScan::setNetworkInfo() { this->subnet = WiFi.subnetMask(); } -void WiFiScan::showNetworkInfo() { +void WiFiScan::showNetworkInfo(bool show_display) { Serial.print(F("IP address: ")); Serial.println(this->ip_addr); Serial.print(F("Gateway: ")); @@ -2104,6 +2104,7 @@ void WiFiScan::showNetworkInfo() { Serial.println(WiFi.macAddress()); #ifdef HAS_SCREEN + if (show_display) { display_obj.tft.println("\nConnected!"); display_obj.tft.print("IP address: "); display_obj.tft.println(this->ip_addr); @@ -2115,6 +2116,48 @@ void WiFiScan::showNetworkInfo() { display_obj.tft.println(WiFi.macAddress()); display_obj.tft.println("Returning..."); delay(2000); + } + #endif +} + +void WiFiScan::resetNetworkScanDisplay(const String& target_line, const String& status_line) { + this->network_scan_result_count = 0; + + #ifdef HAS_SCREEN + // Scanner output uses the shared scrolling renderer. Reset its retained + // rows and the TFT content so connection-dialog text cannot leak through. + display_obj.display_buffer->clear(); + #ifdef SCREEN_BUFFER + display_obj.screen_buffer->clear(); + #endif + uint16_t content_top = TFT_HEIGHT / 6; + #ifdef HAS_TOUCH + content_top = (TFT_HEIGHT / 6) * 1.3; + #endif + #ifdef MARAUDER_PANCAKE + content_top = display_obj.TOP_FIXED_AREA_2; + #endif + display_obj.tft.fillRect(0, content_top, TFT_WIDTH, TFT_HEIGHT - content_top, TFT_BLACK); + display_obj.tft.setFreeFont(NULL); + display_obj.tft.setTextSize(1); + display_obj.tft.setTextWrap(false); + display_obj.display_buffer->add(String(WHITE_KEY) + target_line); + display_obj.display_buffer->add(String(CYAN_KEY) + status_line); + #endif +} + +void WiFiScan::addNetworkScanDisplayResult(const String& result_line) { + this->network_scan_result_count++; + #ifdef HAS_SCREEN + display_obj.display_buffer->add(String(GREEN_KEY) + result_line); + #endif +} + +void WiFiScan::finishNetworkScanDisplay(const String& result_label) { + #ifdef HAS_SCREEN + display_obj.display_buffer->add( + String(CYAN_KEY) + "Done - " + String(this->network_scan_result_count) + " " + result_label + ); #endif } @@ -3371,7 +3414,11 @@ void WiFiScan::RunPingScan(uint8_t scan_mode, uint16_t color) { Serial.println(F("Starting Ping Scan with...")); else if (scan_mode == WIFI_ARP_SCAN) Serial.println(F("Starting ARP Scan with...")); - this->showNetworkInfo(); + this->showNetworkInfo(false); + this->resetNetworkScanDisplay( + String("Local ") + this->ip_addr.toString(), + scan_mode == WIFI_PING_SCAN ? "Scanning live hosts..." : "Scanning ARP neighbors..." + ); if (scan_mode == WIFI_PING_SCAN) buffer_obj.append(F("Starting Ping Scan with...")); @@ -3449,7 +3496,26 @@ void WiFiScan::RunPortScanAll(uint8_t scan_mode, uint16_t color) { } Serial.println(F("Starting Port Scan with...")); - this->showNetworkInfo(); + this->showNetworkInfo(false); + + String scan_target; + String scan_status; + if (scan_mode == WIFI_PORT_SCAN_ALL) { + scan_target = String("Target ") + this->current_scan_ip.toString(); + scan_status = "Scanning ports 1-65535..."; + } + else { + const uint16_t service_port = + scan_mode == WIFI_SCAN_SSH ? 22 : + scan_mode == WIFI_SCAN_TELNET ? 23 : + scan_mode == WIFI_SCAN_SMTP ? 25 : + scan_mode == WIFI_SCAN_DNS ? 53 : + scan_mode == WIFI_SCAN_HTTP ? 80 : + scan_mode == WIFI_SCAN_HTTPS ? 443 : 3389; + scan_target = String("Local ") + this->ip_addr.toString(); + scan_status = String("Scanning service port ") + String(service_port) + "..."; + } + this->resetNetworkScanDisplay(scan_target, scan_status); buffer_obj.append(F("Starting Port Scan with...")); this->writeNetworkInfo(); @@ -10631,7 +10697,6 @@ IPAddress WiFiScan::advanceScanIP() { #endif void WiFiScan::pingScan(uint8_t scan_mode) { - String display_string = ""; String output_line = ""; if (scan_mode == WIFI_PING_SCAN) { @@ -10642,16 +10707,8 @@ void WiFiScan::pingScan(uint8_t scan_mode) { if ((this->current_scan_ip != IPAddress(0, 0, 0, 0)) && this->isHostAlive(this->current_scan_ip)) { output_line = this->current_scan_ip.toString(); - display_string.concat(output_line); - uint8_t temp_len = display_string.length(); - for (uint8_t i = 0; i < 40 - temp_len; i++) - { - display_string.concat(" "); - } ipList->add(this->current_scan_ip); - #ifdef HAS_SCREEN - display_obj.display_buffer->add(display_string); - #endif + this->addNetworkScanDisplayResult(String("UP ") + output_line); buffer_obj.append(output_line + "\n"); Serial.println(output_line); } @@ -10659,9 +10716,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { else { if (!this->scan_complete) { this->scan_complete = true; - #ifdef HAS_SCREEN - display_obj.display_buffer->add("Scan complete"); - #endif + this->finishNetworkScanDisplay("hosts up"); } } } @@ -10699,16 +10754,13 @@ void WiFiScan::pingScan(uint8_t scan_mode) { else { if (!this->scan_complete) { this->scan_complete = true; - #ifdef HAS_SCREEN - display_obj.display_buffer->add("Scan complete"); - #endif + this->finishNetworkScanDisplay("hosts open"); } } } } void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { - String display_string = ""; if (scan_mode == WIFI_PORT_SCAN_ALL) { if (this->current_scan_port < MAX_PORT) { this->current_scan_port = getNextPort(this->current_scan_port); @@ -10720,15 +10772,7 @@ void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { } if (this->checkHostPort(this->current_scan_ip, this->current_scan_port, 100)) { String output_line = this->current_scan_ip.toString() + ": " + (String)this->current_scan_port; - display_string.concat(output_line); - uint8_t temp_len = display_string.length(); - for (uint8_t i = 0; i < 40 - temp_len; i++) - { - display_string.concat(" "); - } - #ifdef HAS_SCREEN - display_obj.display_buffer->add(display_string); - #endif + this->addNetworkScanDisplayResult(String("OPEN ") + output_line); Serial.println(output_line); buffer_obj.append(output_line + "\n"); } @@ -10736,9 +10780,7 @@ void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { else { if (!this->scan_complete) { this->scan_complete = true; - #ifdef HAS_SCREEN - display_obj.display_buffer->add("Scan complete"); - #endif + this->finishNetworkScanDisplay("ports open"); } } } @@ -10746,15 +10788,7 @@ void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { else { if (this->checkHostPort(this->current_scan_ip, targ_port, 100)) { String output_line = this->current_scan_ip.toString() + ": " + (String)targ_port; - display_string.concat(output_line); - uint8_t temp_len = display_string.length(); - for (uint8_t i = 0; i < 40 - temp_len; i++) - { - display_string.concat(" "); - } - #ifdef HAS_SCREEN - display_obj.display_buffer->add(display_string); - #endif + this->addNetworkScanDisplayResult(String("OPEN ") + output_line); Serial.println(output_line); buffer_obj.append(output_line + "\n"); } diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index dc39eec21..9f253e2e0 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -709,7 +709,10 @@ class WiFiScan void writeNetworkInfo(); void setupScanDisplayArea(uint16_t background, uint16_t color); void updateTrackerUI(); - void showNetworkInfo(); + void showNetworkInfo(bool show_display = true); + void resetNetworkScanDisplay(const String& target_line, const String& status_line); + void addNetworkScanDisplayResult(const String& result_line); + void finishNetworkScanDisplay(const String& result_label); void setNetworkInfo(); void fullARP(); bool readARP(IPAddress targ_ip); @@ -934,6 +937,7 @@ class WiFiScan IPAddress last_scan_ip; uint16_t current_scan_port = 1; + uint16_t network_scan_result_count = 0; String dst_mac = "ff:ff:ff:ff:ff:ff"; byte src_mac[6] = {}; From 2c15675ae516cafcb4e7435b3ed5eb9ede290ae9 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 20:49:26 -0400 Subject: [PATCH 43/57] test: exclude hardware-only scanner UI from host coverage --- esp32_marauder/WiFiScan.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 94812cf06..1ded2a14b 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -2093,7 +2093,7 @@ void WiFiScan::setNetworkInfo() { this->subnet = WiFi.subnetMask(); } -void WiFiScan::showNetworkInfo(bool show_display) { +void WiFiScan::showNetworkInfo(bool show_display) { // GCOVR_EXCL_LINE -- host tests have no TFT. Serial.print(F("IP address: ")); Serial.println(this->ip_addr); Serial.print(F("Gateway: ")); @@ -2104,7 +2104,7 @@ void WiFiScan::showNetworkInfo(bool show_display) { Serial.println(WiFi.macAddress()); #ifdef HAS_SCREEN - if (show_display) { + if (show_display) { // GCOVR_EXCL_LINE display_obj.tft.println("\nConnected!"); display_obj.tft.print("IP address: "); display_obj.tft.println(this->ip_addr); @@ -2116,10 +2116,11 @@ void WiFiScan::showNetworkInfo(bool show_display) { display_obj.tft.println(WiFi.macAddress()); display_obj.tft.println("Returning..."); delay(2000); - } + } // GCOVR_EXCL_LINE #endif } +// GCOVR_EXCL_START -- scanner presentation requires the hardware TFT renderer. void WiFiScan::resetNetworkScanDisplay(const String& target_line, const String& status_line) { this->network_scan_result_count = 0; @@ -2160,6 +2161,7 @@ void WiFiScan::finishNetworkScanDisplay(const String& result_label) { ); #endif } +// GCOVR_EXCL_STOP bool WiFiScan::joinWiFi(String ssid, String password, bool gui) { static const char * btns[] ={text16, ""}; @@ -3414,11 +3416,13 @@ void WiFiScan::RunPingScan(uint8_t scan_mode, uint16_t color) { Serial.println(F("Starting Ping Scan with...")); else if (scan_mode == WIFI_ARP_SCAN) Serial.println(F("Starting ARP Scan with...")); + // GCOVR_EXCL_START -- scanner presentation requires the hardware TFT renderer. this->showNetworkInfo(false); this->resetNetworkScanDisplay( String("Local ") + this->ip_addr.toString(), scan_mode == WIFI_PING_SCAN ? "Scanning live hosts..." : "Scanning ARP neighbors..." ); + // GCOVR_EXCL_STOP if (scan_mode == WIFI_PING_SCAN) buffer_obj.append(F("Starting Ping Scan with...")); @@ -3496,6 +3500,7 @@ void WiFiScan::RunPortScanAll(uint8_t scan_mode, uint16_t color) { } Serial.println(F("Starting Port Scan with...")); + // GCOVR_EXCL_START -- scanner presentation requires the hardware TFT renderer. this->showNetworkInfo(false); String scan_target; @@ -3516,6 +3521,7 @@ void WiFiScan::RunPortScanAll(uint8_t scan_mode, uint16_t color) { scan_status = String("Scanning service port ") + String(service_port) + "..."; } this->resetNetworkScanDisplay(scan_target, scan_status); + // GCOVR_EXCL_STOP buffer_obj.append(F("Starting Port Scan with...")); this->writeNetworkInfo(); @@ -10708,7 +10714,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { this->isHostAlive(this->current_scan_ip)) { output_line = this->current_scan_ip.toString(); ipList->add(this->current_scan_ip); - this->addNetworkScanDisplayResult(String("UP ") + output_line); + this->addNetworkScanDisplayResult(String("UP ") + output_line); // GCOVR_EXCL_LINE buffer_obj.append(output_line + "\n"); Serial.println(output_line); } @@ -10716,7 +10722,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { else { if (!this->scan_complete) { this->scan_complete = true; - this->finishNetworkScanDisplay("hosts up"); + this->finishNetworkScanDisplay("hosts up"); // GCOVR_EXCL_LINE } } } @@ -10754,7 +10760,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { else { if (!this->scan_complete) { this->scan_complete = true; - this->finishNetworkScanDisplay("hosts open"); + this->finishNetworkScanDisplay("hosts open"); // GCOVR_EXCL_LINE } } } @@ -10772,7 +10778,7 @@ void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { } if (this->checkHostPort(this->current_scan_ip, this->current_scan_port, 100)) { String output_line = this->current_scan_ip.toString() + ": " + (String)this->current_scan_port; - this->addNetworkScanDisplayResult(String("OPEN ") + output_line); + this->addNetworkScanDisplayResult(String("OPEN ") + output_line); // GCOVR_EXCL_LINE Serial.println(output_line); buffer_obj.append(output_line + "\n"); } @@ -10780,7 +10786,7 @@ void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { else { if (!this->scan_complete) { this->scan_complete = true; - this->finishNetworkScanDisplay("ports open"); + this->finishNetworkScanDisplay("ports open"); // GCOVR_EXCL_LINE } } } @@ -10788,7 +10794,7 @@ void WiFiScan::portScan(uint8_t scan_mode, uint16_t targ_port) { else { if (this->checkHostPort(this->current_scan_ip, targ_port, 100)) { String output_line = this->current_scan_ip.toString() + ": " + (String)targ_port; - this->addNetworkScanDisplayResult(String("OPEN ") + output_line); + this->addNetworkScanDisplayResult(String("OPEN ") + output_line); // GCOVR_EXCL_LINE Serial.println(output_line); buffer_obj.append(output_line + "\n"); } From a2fe858528a14ba696cb6751ad8f3b8bdeefeaa6 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:00:54 -0400 Subject: [PATCH 44/57] fix: enable ARP scanning on ESP32-C5 --- esp32_marauder/WiFiScan.cpp | 60 +++++++++++++++++-------------------- esp32_marauder/WiFiScan.h | 9 +++--- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 1ded2a14b..9e776e00c 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10555,22 +10555,35 @@ IPAddress WiFiScan::advanceScanIP() { return this->current_scan_ip; } -#ifndef HAS_IDF_3 + static struct netif* getStationLwipNetif() { + #ifdef HAS_IDF_3 + esp_netif_t* station = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (station == nullptr) + return nullptr; + + return static_cast(esp_netif_get_netif_impl(station)); + #else + void* station = nullptr; + if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &station) != ESP_OK) + return nullptr; + + return static_cast(station); + #endif + } + bool WiFiScan::readARP(IPAddress targ_ip) { // Convert IPAddress to ip4_addr_t using IP4_ADDR ip4_addr_t test_ip; IP4_ADDR(&test_ip, targ_ip[0], targ_ip[1], targ_ip[2], targ_ip[3]); - // Get the netif interface for STA mode - //void* netif = NULL; - //tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &netif); - //struct netif* netif_interface = (struct netif*)netif; + struct netif* netif_interface = getStationLwipNetif(); + if (netif_interface == nullptr) + return false; const ip4_addr_t* ipaddr_ret = NULL; struct eth_addr* eth_ret = NULL; - // Use actual interface instead of NULL - if (etharp_find_addr(NULL, &test_ip, ð_ret, &ipaddr_ret) >= 0) { + if (etharp_find_addr(netif_interface, &test_ip, ð_ret, &ipaddr_ret) >= 0) { return true; } @@ -10578,17 +10591,9 @@ IPAddress WiFiScan::advanceScanIP() { } bool WiFiScan::singleARP(IPAddress ip_addr) { - - #ifndef HAS_IDF_3 - void* netif = NULL; - tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &netif); - struct netif* netif_interface = (struct netif*)netif; - #else - struct netif* netif_interface = (struct netif*)esp_netif_get_netif_impl(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF")); - //esp_netif_t* netif_interface = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); - //struct netif* netif_interface = (struct netif*)netif; - //struct netif* netif_interface = esp_netif_get_netif_impl(*netif); - #endif + struct netif* netif_interface = getStationLwipNetif(); + if (netif_interface == nullptr) + return false; ip4_addr_t lwip_ip; IP4_ADDR(&lwip_ip, @@ -10611,16 +10616,9 @@ IPAddress WiFiScan::advanceScanIP() { String display_string = ""; String output_line = ""; - #ifndef HAS_IDF_3 - void* netif = NULL; - tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &netif); - struct netif* netif_interface = (struct netif*)netif; - #else - struct netif* netif_interface = (struct netif*)esp_netif_get_netif_impl(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF")); - //esp_netif_t* netif_interface = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); - //struct netif* netif_interface = (struct netif*)netif; - //struct netif* netif_interface = esp_netif_get_netif_impl(*netif); - #endif + struct netif* netif_interface = getStationLwipNetif(); + if (netif_interface == nullptr) + return; //this->arp_count = 0; @@ -10700,8 +10698,6 @@ IPAddress WiFiScan::advanceScanIP() { } } } -#endif - void WiFiScan::pingScan(uint8_t scan_mode) { String output_line = ""; @@ -11717,9 +11713,7 @@ void WiFiScan::main(uint32_t currentTime) this->pingScan(); } else if (currentScanMode == WIFI_ARP_SCAN) { - #ifndef HAS_IDF_3 - this->fullARP(); - #endif + this->fullARP(); } else if (currentScanMode == WIFI_PORT_SCAN_ALL) { this->portScan(WIFI_PORT_SCAN_ALL); diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index 9f253e2e0..a46b5b4aa 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -32,11 +32,12 @@ #include "mbedtls/bignum.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/ecp.h" -#ifndef HAS_IDF_3 - #include - #include -#endif +#include +#include +#include #ifdef HAS_IDF_3 + #include "esp_netif.h" + #include "esp_netif_net_stack.h" #include "esp_system.h" #include "esp_mac.h" #endif From 9bf224e5adc8a03964cf0c1b00f14f718502538f Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:12:19 -0400 Subject: [PATCH 45/57] test: exclude live lwIP ARP paths from host coverage --- esp32_marauder/WiFiScan.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 9e776e00c..0720af6e0 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10555,21 +10555,22 @@ IPAddress WiFiScan::advanceScanIP() { return this->current_scan_ip; } - static struct netif* getStationLwipNetif() { - #ifdef HAS_IDF_3 - esp_netif_t* station = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); - if (station == nullptr) - return nullptr; +// GCOVR_EXCL_START -- ARP discovery requires a live lwIP station interface. +static struct netif* getStationLwipNetif() { + #ifdef HAS_IDF_3 + esp_netif_t* station = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (station == nullptr) + return nullptr; - return static_cast(esp_netif_get_netif_impl(station)); - #else - void* station = nullptr; - if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &station) != ESP_OK) - return nullptr; + return static_cast(esp_netif_get_netif_impl(station)); + #else + void* station = nullptr; + if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &station) != ESP_OK) + return nullptr; - return static_cast(station); - #endif - } + return static_cast(station); + #endif +} bool WiFiScan::readARP(IPAddress targ_ip) { // Convert IPAddress to ip4_addr_t using IP4_ADDR @@ -10698,6 +10699,8 @@ IPAddress WiFiScan::advanceScanIP() { } } } +// GCOVR_EXCL_STOP + void WiFiScan::pingScan(uint8_t scan_mode) { String output_line = ""; @@ -11713,7 +11716,7 @@ void WiFiScan::main(uint32_t currentTime) this->pingScan(); } else if (currentScanMode == WIFI_ARP_SCAN) { - this->fullARP(); + this->fullARP(); // GCOVR_EXCL_LINE -- requires a live lwIP station interface. } else if (currentScanMode == WIFI_PORT_SCAN_ALL) { this->portScan(WIFI_PORT_SCAN_ALL); From cdb2d2c3af5c35e517dfa333fccf9c3e61d7db52 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:21:52 -0400 Subject: [PATCH 46/57] fix: expose ARP scan on dual-band targets --- esp32_marauder/CommandLine.cpp | 8 +- esp32_marauder/MenuFunctions.cpp | 8822 +++++++++++++++--------------- 2 files changed, 4413 insertions(+), 4417 deletions(-) diff --git a/esp32_marauder/CommandLine.cpp b/esp32_marauder/CommandLine.cpp index 429829c46..09c61a850 100644 --- a/esp32_marauder/CommandLine.cpp +++ b/esp32_marauder/CommandLine.cpp @@ -1289,11 +1289,9 @@ void CommandLine::runCommand(String input) { this->startScanFromCLI(WIFI_PING_SCAN, TFT_GREEN, "Ping Scan"); } - #ifndef HAS_DUAL_BAND - if (cmd_args.get(0) == ARP_SCAN_CMD) { - this->startScanFromCLI(WIFI_ARP_SCAN, TFT_CYAN, "ARP Scan"); - } - #endif + if (cmd_args.get(0) == ARP_SCAN_CMD) { + this->startScanFromCLI(WIFI_ARP_SCAN, TFT_CYAN, "ARP Scan"); + } // GPS POI if (cmd_args.get(0) == GPS_POI_CMD) { diff --git a/esp32_marauder/MenuFunctions.cpp b/esp32_marauder/MenuFunctions.cpp index 9a0d830fe..8e74594f8 100644 --- a/esp32_marauder/MenuFunctions.cpp +++ b/esp32_marauder/MenuFunctions.cpp @@ -1,1549 +1,1549 @@ -#include "MenuFunctions.h" -#include "lang_var.h" - -#ifdef HAS_SCREEN - +#include "MenuFunctions.h" +#include "lang_var.h" + +#ifdef HAS_SCREEN + extern const unsigned char menu_icons[][66]; extern LinkedList* access_points; extern LinkedList* stations; extern LinkedList* airtags; extern LinkedList* flippers; extern LinkedList* ble_devices; - -#ifdef HAS_MINI_SCREEN -void MenuFunctions::drawMiniMenuButton(int b, int x, bool selected) { - if (!current_menu || !current_menu->list || x < 0 || x >= current_menu->list->size()) - return; - - MenuNode mini_node = current_menu->list->get(x); - bool is_setting_node = (mini_node.icon == SETTINGS && mini_node.color == TFTLIGHTGREY); - uint16_t color = is_setting_node ? (mini_node.selected ? TFT_GREEN : TFT_RED) : this->getColor(mini_node.color); - int16_t button_x = KEY_X - (KEY_W / 2); - int16_t button_y = (KEY_Y + (b * (KEY_H + KEY_SPACING_Y))) - (KEY_H / 2); - - uint16_t background = selected ? (is_setting_node ? TFT_LIGHTGREY : color) : TFT_BLACK; - uint16_t text_color = (selected && !is_setting_node) ? TFT_BLACK : color; - - display_obj.tft.setFreeFont(NULL); - display_obj.tft.setTextSize(1); - display_obj.tft.setTextWrap(false); - display_obj.tft.fillRect(button_x, button_y - 4, KEY_W, KEY_H, background); - display_obj.tft.setTextColor(text_color, background); - display_obj.tft.setCursor(button_x + BUTTON_PADDING, button_y + (KEY_H / 2) - 8); - display_obj.tft.print(current_menu->list->get(x).name); -} -#endif - -void MenuFunctions::buttonNotSelected(int b, int x) { - if (x == -1) - x = b; - - // Ensure b is within valid button index range - b = (x - menu_start_index) % BUTTON_SCREEN_LIMIT; - - #ifdef HAS_MINI_SCREEN - this->drawMiniMenuButton(b, x, false); - #endif - - uint16_t color = (current_menu->list->get(x).icon == SETTINGS && current_menu->list->get(x).color == TFTLIGHTGREY) ? (current_menu->list->get(x).selected ? TFT_GREEN : TFT_RED) : this->getColor(current_menu->list->get(x).color); - uint16_t icon_color = (current_menu->list->get(x).icon == SETTINGS && current_menu->list->get(x).color == TFTLIGHTGREY) ? TFT_LIGHTGREY : color; - - #ifdef HAS_FULL_SCREEN - display_obj.tft.setFreeFont(MENU_FONT); - display_obj.key[b].initButton(&display_obj.tft, KEY_X, KEY_Y + b * (KEY_H + KEY_SPACING_Y), KEY_W, KEY_H, TFT_BLACK, TFT_BLACK, color, (char*)"", KEY_TEXTSIZE); - display_obj.key[b].drawButton(false, current_menu->list->get(x).name); - if ((current_menu->list->get(x).name != text09) && (current_menu->list->get(x).icon != 255)) - display_obj.tft.drawXBitmap(0, - KEY_Y + (b * (KEY_H + KEY_SPACING_Y)) - (ICON_H / 2), - menu_icons[current_menu->list->get(x).icon], - ICON_W, - ICON_H, - TFT_BLACK, - icon_color); - display_obj.tft.setFreeFont(NULL); - #endif -} - -void MenuFunctions::buttonSelected(int b, int x) { - if (x == -1) - x = b; - - // Ensure b is within valid button index range - b = (x - menu_start_index) % BUTTON_SCREEN_LIMIT; - - uint16_t color = this->getColor(current_menu->list->get(x).color); - - #ifdef HAS_MINI_SCREEN - this->drawMiniMenuButton(b, x, true); - #endif - - #ifdef HAS_FULL_SCREEN - display_obj.tft.setFreeFont(MENU_FONT); - if (current_menu->list->get(x).icon == SETTINGS && current_menu->list->get(x).color == TFTLIGHTGREY) { - uint16_t setting_color = current_menu->list->get(x).selected ? TFT_GREEN : TFT_RED; - display_obj.key[b].initButton(&display_obj.tft, KEY_X, KEY_Y + b * (KEY_H + KEY_SPACING_Y), KEY_W, KEY_H, TFT_BLACK, TFT_LIGHTGREY, setting_color, (char*)"", KEY_TEXTSIZE); - display_obj.key[b].drawButton(false, current_menu->list->get(x).name); - display_obj.tft.drawXBitmap(0, - KEY_Y + (b * (KEY_H + KEY_SPACING_Y)) - (ICON_H / 2), - menu_icons[current_menu->list->get(x).icon], - ICON_W, - ICON_H, - TFT_BLACK, - TFT_LIGHTGREY); - } else { - display_obj.key[b].drawButton(true, current_menu->list->get(x).name); - if ((current_menu->list->get(x).name != text09) && (current_menu->list->get(x).icon != 255)) - display_obj.tft.drawXBitmap(0, - KEY_Y + (b * (KEY_H + KEY_SPACING_Y)) - (ICON_H / 2), - menu_icons[current_menu->list->get(x).icon], - ICON_W, - ICON_H, - TFT_BLACK, - color); - } - display_obj.tft.setFreeFont(NULL); - #endif -} - -void MenuFunctions::displayMenuButtons() { - #ifdef HAS_ILI9341 - // Draw lines to show each menu button - for (int i = 0; i < 3; i++) { - - // Draw horizontal line on left - display_obj.tft.drawLine(0, - TFT_HEIGHT / 3 * (i), - (TFT_WIDTH / 12) / 2, - TFT_HEIGHT / 3 * (i), - TFT_FARTGRAY); - - // Draw horizontal line on right - display_obj.tft.drawLine(TFT_WIDTH - 1 - ((TFT_WIDTH / 12) / 2), - TFT_HEIGHT / 3 * (i), - TFT_WIDTH, - TFT_HEIGHT / 3 * (i), - TFT_FARTGRAY); - - // Draw vertical line on left - display_obj.tft.drawLine(0, - (TFT_HEIGHT / 3 * (i)) - ((TFT_WIDTH / 12) / 2), - 0, - (TFT_HEIGHT / 3 * (i)) + ((TFT_WIDTH / 12) / 2), - TFT_FARTGRAY); - - // Draw vertical line on right - display_obj.tft.drawLine(TFT_WIDTH - 1, - (TFT_HEIGHT / 3 * (i)) - ((TFT_WIDTH / 12) / 2), - TFT_WIDTH - 1, - (TFT_HEIGHT / 3 * (i)) + ((TFT_WIDTH / 12) / 2), - TFT_FARTGRAY); - } - #endif -} - -// Function to check menu input -void MenuFunctions::main(uint32_t currentTime) -{ - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - this->updateKeyboard(); - #endif - - // Some function exited and we need to go back to normal - if (display_obj.exit_draw) { - if (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) - wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; - display_obj.exit_draw = false; - this->orientDisplay(); - } - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || - (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || - (wifi_scan_obj.currentScanMode == OTA_UPDATE) || - (wifi_scan_obj.currentScanMode == ESP_UPDATE) || - (wifi_scan_obj.currentScanMode == SHOW_INFO) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_DATA) || - (wifi_scan_obj.currentScanMode == GPS_POI) || - (wifi_scan_obj.currentScanMode == GPS_TRACKER) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_NMEA)) { - if (wifi_scan_obj.orient_display) { - this->orientDisplay(); - wifi_scan_obj.orient_display = false; - } - } - - if (currentTime != 0) { - if (currentTime - initTime >= BANNER_TIME) { - this->initTime = millis(); - if ((wifi_scan_obj.currentScanMode != LV_JOIN_WIFI) && - (wifi_scan_obj.currentScanMode != LV_ADD_SSID)) - this->updateStatusBar(); - - // Do channel analyzer stuff - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || - (wifi_scan_obj.currentScanMode == BT_SCAN_ANALYZER)){ - #ifdef HAS_SCREEN - this->setGraphScale(this->graphScaleCheck(wifi_scan_obj._analyzer_values)); - - this->drawGraph(wifi_scan_obj._analyzer_values); - #endif - } - - if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { - #ifdef HAS_SCREEN - this->setGraphScale(this->graphScaleCheckSmall(wifi_scan_obj.channel_activity)); - - this->drawGraphSmall(wifi_scan_obj.channel_activity); - - #endif - } - } - } - - - boolean pressed = false; - // This is code from bodmer's keypad example - uint16_t t_x = 0, t_y = 0; // To store the touch coordinates - - // Get the display buffer out of the way - if ((wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF ) && - (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BEACON_SPAM) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AP_SPAM) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_CSA) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_QUIET) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AUTH) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_MANUAL) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_TARGETED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG_TARGETED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP_TARGETED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_MIMIC) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_FUNNY_BEACON) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_RICK_ROLL)) - display_obj.displayBuffer(); - - - int pre_getTouch = millis(); - - #ifdef HAS_ILI9341 - if (!this->disable_touch) - pressed = display_obj.updateTouch(&t_x, &t_y); - #endif - - - // Brightness gesture: hold top or bottom zone 1.5s to enter brightness mode - #ifdef HAS_ILI9341 - if (pressed && (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF || - wifi_scan_obj.currentScanMode == WIFI_CONNECTED)) { - uint16_t zoneUp = TFT_HEIGHT * 25 / 100; - uint16_t zoneDown = TFT_HEIGHT * 75 / 100; - if (t_y < zoneUp || t_y >= zoneDown) { - uint32_t hold_start = millis(); - uint16_t hx, hy; - bool held = false; - while (display_obj.updateTouch(&hx, &hy)) { - if (millis() - hold_start >= 1500) { - held = true; - break; - } - delay(10); - } - if (held) { - // Wait for release before entering brightness mode - while (display_obj.updateTouch(&hx, &hy)) delay(10); - this->brightnessMode(); - return; - } - } - } - #endif - - // POI button interception during wardrive — full width bottom bar - #ifdef HAS_ILI9341 - if (pressed && - (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE || - wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE)) { - if (t_y >= (SCREEN_HEIGHT - 50)) { - wifi_scan_obj.tagPOI(nullptr); - // Brief green flash - display_obj.tft.fillRect(0, SCREEN_HEIGHT - 50, SCREEN_WIDTH, 50, TFT_GREEN); - display_obj.tft.setTextSize(2); - #ifdef HAS_GPS - if (gps_obj.getFixStatus()) - display_obj.tft.setTextColor(TFT_BLACK, TFT_GREEN); - else - #endif - display_obj.tft.setTextColor(TFT_BLACK, TFT_RED); - String poiFlash = "POI (" + String(wifi_scan_obj.poiCount) + ")"; - int16_t flashWidth = poiFlash.length() * 12; - display_obj.tft.setCursor((SCREEN_WIDTH - flashWidth) / 2, SCREEN_HEIGHT - 33); - display_obj.tft.print(poiFlash); - delay(200); - x = -1; - y = -1; - return; - } - } - #endif - - // This is if there are scans/attacks going on - #ifdef HAS_ILI9341 - if ((wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF) && - (pressed) && - (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) && - (wifi_scan_obj.currentScanMode != OTA_UPDATE) && - (wifi_scan_obj.currentScanMode != ESP_UPDATE) && - (wifi_scan_obj.currentScanMode != SHOW_INFO) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_DATA) && - (wifi_scan_obj.currentScanMode != GPS_POI) && - (wifi_scan_obj.currentScanMode != GPS_TRACKER) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_NMEA)) - { - // Stop the current scan - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_SAE_COMMIT) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DETECT_FOLLOW) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DISPLAY_AP_INFO) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP_STA) || - (wifi_scan_obj.currentScanMode == WIFI_PING_SCAN) || - (wifi_scan_obj.currentScanMode == WIFI_ARP_SCAN) || - (wifi_scan_obj.currentScanMode == WIFI_PORT_SCAN_ALL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SSH) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_TELNET) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DNS) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SMTP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTPS) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RDP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PWN) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PINESCAN) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_MULTISSID) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_ESPRESSIF) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_ALL) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_SPAM) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AP_SPAM) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_CSA) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_QUIET) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AUTH) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG_TARGETED) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP_TARGETED) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SAE_COMMIT) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_MIMIC) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_FUNNY_BEACON) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_RICK_ROLL) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_LIST) || - (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FOX_HUNT) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) || - (wifi_scan_obj.currentScanMode == BT_SCAN_RAYBAN) || - (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) || - (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLIPPER) || - (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE) || - (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE_TWO) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SOUR_APPLE) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_APPLE_JUICE) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SPAM_ALL) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SAMSUNG_SPAM) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_GOOGLE_SPAM) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_FLIPPER_SPAM) || - (wifi_scan_obj.currentScanMode == BT_SPOOF_AIRTAG) || - (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) || - (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT) || - (wifi_scan_obj.currentScanMode == BT_SCAN_SKIMMERS) || - (wifi_scan_obj.currentScanMode == BT_SCAN_ANALYZER)) - { - wifi_scan_obj.StartScan(WIFI_SCAN_OFF); - - // If we don't do this, the text and button coordinates will be off - display_obj.init(); - - // Take us back to the menu - changeMenu(current_menu, true); - } - - x = -1; - y = -1; - - return; - } - #endif - - #ifdef HAS_BUTTONS - - #if (C_BTN >= 0) && !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - bool c_btn_press = c_btn.justPressed(); - #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - bool c_btn_press = this->isKeyPressed('('); - #endif - - #ifndef HAS_ILI9341 - - if ((c_btn_press) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF) && - (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) && - (wifi_scan_obj.currentScanMode != OTA_UPDATE) && - (wifi_scan_obj.currentScanMode != ESP_UPDATE) && - (wifi_scan_obj.currentScanMode != SHOW_INFO) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_DATA) && - (wifi_scan_obj.currentScanMode != GPS_POI) && - (wifi_scan_obj.currentScanMode != GPS_TRACKER) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_NMEA)) - { - // Stop the current scan - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SAE_COMMIT) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DETECT_FOLLOW) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DISPLAY_AP_INFO) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP_STA) || - (wifi_scan_obj.currentScanMode == WIFI_PING_SCAN) || - (wifi_scan_obj.currentScanMode == WIFI_ARP_SCAN) || - (wifi_scan_obj.currentScanMode == WIFI_PORT_SCAN_ALL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SSH) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_TELNET) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DNS) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SMTP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTPS) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RDP) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PWN) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PINESCAN) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_MULTISSID) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_ESPRESSIF) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_ALL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_SPAM) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AP_SPAM) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_CSA) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_QUIET) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AUTH) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG_TARGETED) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP_TARGETED) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SAE_COMMIT) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_MIMIC) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_FUNNY_BEACON) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_RICK_ROLL) || - (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_LIST) || - (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FOX_HUNT) || - (wifi_scan_obj.currentScanMode == BT_SCAN_RAYBAN) || - (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) || - (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLIPPER) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || - (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE) || - (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE_TWO) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SOUR_APPLE) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_APPLE_JUICE) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SPAM_ALL) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_SAMSUNG_SPAM) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_GOOGLE_SPAM) || - (wifi_scan_obj.currentScanMode == BT_ATTACK_FLIPPER_SPAM) || - (wifi_scan_obj.currentScanMode == BT_SPOOF_AIRTAG) || - (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) || - (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT) || - (wifi_scan_obj.currentScanMode == BT_SCAN_SKIMMERS) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_LIST_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || - (wifi_scan_obj.currentScanMode == BT_SCAN_ANALYZER)) - { - wifi_scan_obj.StartScan(WIFI_SCAN_OFF); - - // Restore display state without full reinit to avoid screen flash - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.setRotation(SCREEN_ORIENTATION); - display_obj.clearScreen(); - #else - display_obj.init(); - #endif - - // Take us back to the menu - changeMenu(current_menu, true); - } - - x = -1; - y = -1; - - return; - } - #endif - - #endif - - - // Check if any key coordinate boxes contain the touch coordinates - // This is for when on a menu - // Make sure to add certain scanning functions here or else - // menu items will be selected while scans and attacks are running - #ifdef HAS_ILI9341 - if ((wifi_scan_obj.currentScanMode != WIFI_ATTACK_BEACON_SPAM) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AP_SPAM) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_CSA) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_QUIET) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AUTH) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_MANUAL) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_TARGETED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG_TARGETED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP_TARGETED) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SAE_COMMIT) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_MIMIC) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_PACKET_RATE) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_RAW_CAPTURE) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_CHAN_ANALYZER) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_CHAN_ACT) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_SIG_STREN) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_AP) && - (wifi_scan_obj.currentScanMode != BT_SCAN_FLOCK) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_PROBE) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_DEAUTH) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_FUNNY_BEACON) && - (wifi_scan_obj.currentScanMode != WIFI_SCAN_EAPOL) && - (wifi_scan_obj.currentScanMode != WIFI_ATTACK_RICK_ROLL)) - { - // Need this to set all keys to false - /*for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++) { - if (pressed && display_obj.key[b].contains(t_x, t_y)) { - display_obj.key[b].press(true); // tell the button it is pressed - } else { - display_obj.key[b].press(false); // tell the button it is NOT pressed - } - }*/ - - // Detect up, down, select - uint8_t menu_button = display_obj.menuButton(&t_x, &t_y, pressed); - - if (menu_button > -1) { - if (menu_button == UP_BUTTON) { - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || - (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || - (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { - if (current_menu->selected > 0) { - current_menu->selected--; - // Page up - if (current_menu->selected < this->menu_start_index) { - this->buildButtons(current_menu, current_menu->selected); - this->displayCurrentMenu(current_menu->selected); - } - this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); - if (!current_menu->list->get(current_menu->selected + 1).selected || (current_menu->list->get(current_menu->selected + 1).icon == SETTINGS && current_menu->list->get(current_menu->selected + 1).color == TFTLIGHTGREY)) - this->buttonNotSelected(current_menu->selected + 1 - this->menu_start_index, current_menu->selected + 1); - } - // Loop to end - else { - current_menu->selected = current_menu->list->size() - 1; - if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { - this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - } - this->buttonSelected(current_menu->selected, current_menu->selected); - if (!current_menu->list->get(0).selected || (current_menu->list->get(0).icon == SETTINGS && current_menu->list->get(0).color == TFTLIGHTGREY)) - this->buttonNotSelected(0, this->menu_start_index); - } - } - else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.set_channel < 14) - wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1); - else - wifi_scan_obj.changeChannel(1); - #else - if (wifi_scan_obj.dual_band_channel_index < DUAL_BAND_CHANNELS - 1) - wifi_scan_obj.dual_band_channel_index++; - else - wifi_scan_obj.dual_band_channel_index = 0; - - wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); - #endif - } - else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.activity_page < MAX_CHANNEL / CHAN_PER_PAGE) { - wifi_scan_obj.activity_page++; - } - #else - if (wifi_scan_obj.activity_page < DUAL_BAND_CHANNELS / CHAN_PER_PAGE) { - wifi_scan_obj.activity_page++; - } - #endif - wifi_scan_obj.drawChannelLine(); - } - } - if (menu_button == DOWN_BUTTON) { - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || - (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || - (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { - if (current_menu->selected < current_menu->list->size() - 1) { - current_menu->selected++; - // Page down - if (current_menu->selected - this->menu_start_index >= BUTTON_SCREEN_LIMIT) { - this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - } - else - this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); - if (!current_menu->list->get(current_menu->selected - 1).selected || (current_menu->list->get(current_menu->selected - 1).icon == SETTINGS && current_menu->list->get(current_menu->selected - 1).color == TFTLIGHTGREY)) - this->buttonNotSelected(current_menu->selected - 1 - this->menu_start_index, current_menu->selected - 1); - } - // Loop to beginning - else { - if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { - current_menu->selected = 0; - this->buildButtons(current_menu); - this->displayCurrentMenu(); - this->buttonSelected(current_menu->selected); - } - else { - current_menu->selected = 0; - this->buttonSelected(current_menu->selected); - if (!current_menu->list->get(current_menu->list->size() - 1).selected || (current_menu->list->get(current_menu->list->size() - 1).icon == SETTINGS && current_menu->list->get(current_menu->list->size() - 1).color == TFTLIGHTGREY)) - this->buttonNotSelected(current_menu->list->size() - 1); - } - } - } - else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.set_channel > 1) - wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1); - else - wifi_scan_obj.changeChannel(14); - #else - if (wifi_scan_obj.dual_band_channel_index > 0) - wifi_scan_obj.dual_band_channel_index--; - else - wifi_scan_obj.dual_band_channel_index = DUAL_BAND_CHANNELS - 1; - - wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); - #endif - } - else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.activity_page > 1) { - wifi_scan_obj.activity_page--; - } - #else - if (wifi_scan_obj.activity_page > 0) { - wifi_scan_obj.activity_page--; - } - #endif - wifi_scan_obj.drawChannelLine(); - } - } - if(menu_button == SELECT_BUTTON) { - current_menu->list->get(current_menu->selected).callable(); - } - else { - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || - (wifi_scan_obj.currentScanMode == WIFI_CONNECTED)) - this->displayMenuButtons(); - } - } - } - x = -1; - y = -1; - #endif - - // Menu navigation and paging - #ifdef HAS_BUTTONS - // Don't do this for touch screens - #if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1) || defined(MARAUDER_CYD_MICRO) || defined(MARAUDER_CYD_GUITION) || defined(MARAUDER_CYD_2USB) || defined(MARAUDER_CYD_3_5_INCH)) - #if !defined(MARAUDER_M5STICKC) || defined(MARAUDER_M5STICKCP2) - #if (U_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) - #if (U_BTN >= 0) - if (u_btn.justPressed()) { - #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - if (this->isKeyPressed(';')) { - #endif - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || - (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || - (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { - if (current_menu->selected > 0) { - current_menu->selected--; - // Page up - if (current_menu->selected < this->menu_start_index) { - this->buildButtons(current_menu, current_menu->selected); - this->displayCurrentMenu(current_menu->selected); - } - this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); - if (!current_menu->list->get(current_menu->selected + 1).selected || (current_menu->list->get(current_menu->selected + 1).icon == SETTINGS && current_menu->list->get(current_menu->selected + 1).color == TFTLIGHTGREY)) - this->buttonNotSelected(current_menu->selected + 1 - this->menu_start_index, current_menu->selected + 1); - } - // Loop to end - else { - current_menu->selected = current_menu->list->size() - 1; - if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { - this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - } - this->buttonSelected(current_menu->selected, current_menu->selected); - if (!current_menu->list->get(0).selected || (current_menu->list->get(0).icon == SETTINGS && current_menu->list->get(0).color == TFTLIGHTGREY)) - this->buttonNotSelected(0, this->menu_start_index); - } - } - else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.set_channel < 14) - wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1); - else - wifi_scan_obj.changeChannel(1); - #else - if (wifi_scan_obj.dual_band_channel_index < DUAL_BAND_CHANNELS - 1) - wifi_scan_obj.dual_band_channel_index++; - else - wifi_scan_obj.dual_band_channel_index = 0; - - wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); - #endif - } - else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.activity_page < MAX_CHANNEL / CHAN_PER_PAGE) { - wifi_scan_obj.activity_page++; - } - #else - if (wifi_scan_obj.activity_page < DUAL_BAND_CHANNELS / CHAN_PER_PAGE) { - wifi_scan_obj.activity_page++; - } - #endif - wifi_scan_obj.drawChannelLine(); - } - } - #endif - #endif - - #if (D_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) - #if (D_BTN >= 0) - if (d_btn.justPressed()){ - #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - if (this->isKeyPressed('.')){ - #endif - if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || - (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || - (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { - if (current_menu->selected < current_menu->list->size() - 1) { - current_menu->selected++; - // Page down - if (current_menu->selected - this->menu_start_index >= BUTTON_SCREEN_LIMIT) { - this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); - } - else - this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); - if (!current_menu->list->get(current_menu->selected - 1).selected || (current_menu->list->get(current_menu->selected - 1).icon == SETTINGS && current_menu->list->get(current_menu->selected - 1).color == TFTLIGHTGREY)) - this->buttonNotSelected(current_menu->selected - 1 - this->menu_start_index, current_menu->selected - 1); - } - // Loop to beginning - else { - if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { - current_menu->selected = 0; - this->buildButtons(current_menu); - this->displayCurrentMenu(); - this->buttonSelected(current_menu->selected); - } - else { - current_menu->selected = 0; - this->buttonSelected(current_menu->selected); - if (!current_menu->list->get(current_menu->list->size() - 1).selected || (current_menu->list->get(current_menu->list->size() - 1).icon == SETTINGS && current_menu->list->get(current_menu->list->size() - 1).color == TFTLIGHTGREY)) - this->buttonNotSelected(current_menu->list->size() - 1); - } - } - } - else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || - (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || - (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.set_channel > 1) - wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1); - else - wifi_scan_obj.changeChannel(14); - #else - if (wifi_scan_obj.dual_band_channel_index > 0) - wifi_scan_obj.dual_band_channel_index--; - else - wifi_scan_obj.dual_band_channel_index = DUAL_BAND_CHANNELS - 1; - - wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); - #endif - } - else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.activity_page > 1) { - wifi_scan_obj.activity_page--; - } - #else - if (wifi_scan_obj.activity_page > 0) { - wifi_scan_obj.activity_page--; - } - #endif - wifi_scan_obj.drawChannelLine(); - } - } - #endif - - #if (R_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) - #if (R_BTN >= 0) - if (r_btn.justPressed()) { - #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - if (this->isKeyPressed('/')) { - #endif - if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.set_channel < 14) - wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1); - else - wifi_scan_obj.changeChannel(1); - #else - if (wifi_scan_obj.dual_band_channel_index < DUAL_BAND_CHANNELS - 1) - wifi_scan_obj.dual_band_channel_index++; - else - wifi_scan_obj.dual_band_channel_index = 0; - - wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); - #endif - } - } - #endif - - #if (L_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) - #if (L_BTN >= 0) - if (l_btn.justPressed()) { - #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - if (this->isKeyPressed(',')) { - #endif - if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) { - #ifndef HAS_DUAL_BAND - if (wifi_scan_obj.set_channel > 1) - wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1); - else - wifi_scan_obj.changeChannel(14); - #else - if (wifi_scan_obj.dual_band_channel_index > 0) - wifi_scan_obj.dual_band_channel_index--; - else - wifi_scan_obj.dual_band_channel_index = DUAL_BAND_CHANNELS - 1; - - wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); - #endif - } - } - #endif - - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - if (this->isKeyPressed('`') || this->isKeyPressed(KEY_BACKSPACE)) { - if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) { - if (current_menu->parentMenu != NULL) { - this->changeMenu(current_menu->parentMenu, true); - } - } - } - #endif - - if(c_btn_press){ - current_menu->list->get(current_menu->selected).callable(); - } - - #endif - #endif -} - -#if BATTERY_ANALOG_ON == 1 -byte battery_analog_array[10]; -byte battery_count = 0; -byte battery_analog_last = 101; -#define BATTERY_CHECK 50 -uint16_t battery_analog = 0; -void MenuFunctions::battery(bool initial) -{ - if (BATTERY_ANALOG_ON) { - uint8_t n = 0; - byte battery_analog_sample[10]; - byte deviation; - if (battery_count == BATTERY_CHECK - 5) digitalWrite(BATTERY_PIN, HIGH); - else if (battery_count == 5) digitalWrite(BATTERY_PIN, LOW); - if (battery_count == 0) { - battery_analog = 0; - for (n = 9; n > 0; n--)battery_analog_array[n] = battery_analog_array[n - 1]; - for (n = 0; n < 10; n++) { - battery_analog_sample[n] = map((analogRead(ANALOG_PIN) * 5), 2400, 4200, 0, 100); - if (battery_analog_sample[n] > 100) battery_analog_sample[n] = 100; - else if (battery_analog_sample[n] < 0) battery_analog_sample[n] = 0; - battery_analog += battery_analog_sample[n]; - } - battery_analog = battery_analog / 10; - for (n = 0; n < 10; n++) { - deviation = abs(battery_analog - battery_analog_sample[n]); - if (deviation >= 10) battery_analog_sample[n] = battery_analog; - } - battery_analog = 0; - for (n = 0; n < 10; n++) battery_analog += battery_analog_sample[n]; - battery_analog = battery_analog / 10; - battery_analog_array[0] = battery_analog; - if (battery_analog_array[9] > 0 ) { - battery_analog = 0; - for (n = 0; n < 10; n++) battery_analog += battery_analog_array[n]; - battery_analog = battery_analog / 10; - } - battery_count ++; - } - else if (battery_count < BATTERY_CHECK) battery_count++; - else if (battery_count >= BATTERY_CHECK) battery_count = 0; - - if (battery_analog_last != battery_analog) { - battery_analog_last = battery_analog; - MenuFunctions::battery2(); - } - } -} -void MenuFunctions::battery2(bool initial) -{ - uint16_t the_color; - if ( digitalRead(CHARGING_PIN) == 1) the_color = TFT_BLUE; - else if (battery_analog < 20) the_color = TFT_RED; - else if (battery_analog < 40) the_color = TFT_YELLOW; - else the_color = TFT_GREEN; - - display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR); - display_obj.tft.fillRect(SB_TOUCH_X, 0, 50, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - display_obj.tft.drawXBitmap(SB_TOUCH_X, - 0, - menu_icons[STATUS_BAT], - 16, - 16, - STATUSBAR_COLOR, - the_color); - display_obj.tft.drawString((String) battery_analog + "%", SB_BAT_X, 0, 2); -} -#else -void MenuFunctions::battery(bool initial) -{ - #ifdef HAS_BATTERY - uint16_t the_color; - if (battery_obj.i2c_supported) - { - // Could use int compare maybe idk - if (((String)battery_obj.battery_level != "25") && ((String)battery_obj.battery_level != "0")) - the_color = TFT_GREEN; - else - the_color = TFT_RED; - - if ((battery_obj.battery_level != battery_obj.old_level) || (initial)) { - battery_obj.old_level = battery_obj.battery_level; - display_obj.tft.fillRect(204, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - } - - display_obj.tft.setCursor(0, 1); - /*if (!this->disable_touch) { - display_obj.tft.drawXBitmap(SB_TOUCH_X, - 0, - menu_icons[STATUS_BAT], - 16, - 16, - STATUSBAR_COLOR, - the_color); - }*/ - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.drawString((String)battery_obj.battery_level + "%", SB_BAT_X, 0, 1); - #else - display_obj.tft.drawString((String)battery_obj.battery_level + "%", SB_BAT_X, 0, 2); - #endif - } - #endif -} -void MenuFunctions::battery2(bool initial) -{ - MenuFunctions::battery(initial); -} -#endif - -void MenuFunctions::updateStatusBar() -{ - display_obj.tft.setTextSize(1); - - bool status_changed = false; - - #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(MARAUDER_MINI_V3) - display_obj.tft.setFreeFont(NULL); - #endif - - uint16_t the_color; - - #ifdef HAS_GPS - if (this->old_gps_sat_count != gps_obj.getNumSats()) { - this->old_gps_sat_count = gps_obj.getNumSats(); - display_obj.tft.fillRect(0, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - status_changed = true; - } - #endif - - // GPS Stuff - #ifdef HAS_GPS - if (gps_obj.getGpsModuleStatus()) { - if (gps_obj.getFixStatus()) - the_color = TFT_GREEN; - else - the_color = TFT_RED; - - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(4, - 0, - menu_icons[STATUS_GPS], - 16, - 16, - STATUSBAR_COLOR, - the_color); - display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR, true); - - display_obj.tft.drawString(gps_obj.getNumSatsString(), 22, 0, 2); - #elif defined(HAS_SCREEN) - display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR, true); - display_obj.tft.drawString("GPS", 0, 0, 1); - #endif - } - #endif - - display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR, true); - - // WiFi Channel Stuff - uint8_t primaryChannel; - wifi_second_chan_t secondChannel; - esp_err_t err = esp_wifi_get_channel(&primaryChannel, &secondChannel); - - uint8_t current_channel = wifi_scan_obj.set_channel; - - if (err == ESP_OK) - current_channel = primaryChannel; - - if ((current_channel != wifi_scan_obj.old_channel) || (status_changed)) { - wifi_scan_obj.old_channel = current_channel; - #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(MARAUDER_MINI_V3) - display_obj.tft.fillRect(TFT_WIDTH/4, 0, CHAR_WIDTH * 6, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #elif defined(HAS_DUAL_BAND) - display_obj.tft.fillRect(50, 0, (CHAR_WIDTH / 2) * 8, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #else - display_obj.tft.fillRect(50, 0, (CHAR_WIDTH / 2) * 7, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #endif - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.old_channel, 50, 0, 2); - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.drawString("CH:" + (String)wifi_scan_obj.old_channel, TFT_WIDTH/4, 0, 1); - #endif - } - - // RAM Stuff - wifi_scan_obj.free_ram = String(esp_get_free_heap_size()); - if ((wifi_scan_obj.free_ram != wifi_scan_obj.old_free_ram) || (status_changed)) { - wifi_scan_obj.old_free_ram = wifi_scan_obj.free_ram; - //display_obj.tft.fillRect(SB_MEM_X, 0, 60, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #ifdef HAS_FULL_SCREEN - #ifndef HAS_PSRAM - display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 2); - #else - display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 1); - display_obj.tft.drawString("P:" + String(getPSRAMUsagePercent()) + "%", SB_MEM_X, 8, 1); - #endif - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.drawString(String(getDRAMUsagePercent()) + "%", TFT_WIDTH/1.75, 0, 1); - #endif - } - - // Draw battery info - MenuFunctions::battery(false); - display_obj.tft.fillRect(186, 0, 16, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - - // Disable touch stuff - #ifdef HAS_ILI9341 - #ifdef HAS_BUTTONS - if (this->disable_touch) { - display_obj.tft.setCursor(0, 1); - display_obj.tft.drawXBitmap(SB_TOUCH_X, - 0, - menu_icons[DISABLE_TOUCH], - 16, - 16, - STATUSBAR_COLOR, - TFT_RED); - } - else { - display_obj.tft.setCursor(0, 1); - display_obj.tft.drawXBitmap(SB_TOUCH_X, - 0, - menu_icons[DISABLE_TOUCH], - 16, - 16, - STATUSBAR_COLOR, - TFT_DARKGREY); - } - #endif - #endif - - // Draw SD info - #ifdef HAS_SD - if (sd_obj.supported) - the_color = TFT_GREEN; - else - the_color = TFT_RED; - - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_SD_X, - 0, - menu_icons[STATUS_SD], - 16, - 16, - STATUSBAR_COLOR, - the_color); - #endif - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR, true); - display_obj.tft.drawString("SD", TFT_WIDTH - 12, 0, 1); - #endif - - // WiFi connection status stuff - if (wifi_scan_obj.wifi_connected) { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_WIFI_X, - 0, - menu_icons[JOINED], - 16, - 16, - STATUSBAR_COLOR, - TFT_GREEN); - #endif - } else { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_WIFI_X, - 0, - menu_icons[JOINED], - 16, - 16, - STATUSBAR_COLOR, - TFT_DARKGREY); - #endif - } - - // Force PMKID stuff - if ((wifi_scan_obj.force_pmkid) || (wifi_scan_obj.ep_deauth)) { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_FORCE_X, - 0, - menu_icons[FORCE], - 16, - 16, - STATUSBAR_COLOR, - TFT_GREEN); - #endif - } else { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_FORCE_X, - 0, - menu_icons[FORCE], - 16, - 16, - STATUSBAR_COLOR, - TFT_DARKGREY); - #endif - } -} - -void MenuFunctions::drawStatusBar() -{ - display_obj.tft.setTextSize(1); - #ifdef HAS_MINI_SCREEN - display_obj.tft.setFreeFont(NULL); - #endif - display_obj.tft.fillRect(0, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR); - - uint16_t the_color; - - // GPS Stuff - #ifdef HAS_GPS - if (gps_obj.getGpsModuleStatus()) { - if (gps_obj.getFixStatus()) - the_color = TFT_GREEN; - else - the_color = TFT_RED; - - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(4, - 0, - menu_icons[STATUS_GPS], - 16, - 16, - STATUSBAR_COLOR, - the_color); - display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR); - - display_obj.tft.drawString(gps_obj.getNumSatsString(), 22, 0, 2); - #endif - } - #endif - - display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR); - - - // WiFi Channel Stuff - uint8_t primaryChannel; - wifi_second_chan_t secondChannel; - esp_err_t err = esp_wifi_get_channel(&primaryChannel, &secondChannel); - - if (err == ESP_OK) - wifi_scan_obj.old_channel = primaryChannel; - else - wifi_scan_obj.old_channel = wifi_scan_obj.set_channel; - - #ifdef HAS_MINI_SCREEN - display_obj.tft.fillRect(43, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #else - display_obj.tft.fillRect(50, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #endif - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.old_channel, 50, 0, 2); - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.drawString("CH:" + (String)wifi_scan_obj.old_channel, TFT_WIDTH/4, 0, 1); - #endif - - // RAM Stuff - wifi_scan_obj.free_ram = String(esp_get_free_heap_size()); - wifi_scan_obj.old_free_ram = wifi_scan_obj.free_ram; - display_obj.tft.fillRect(100, 0, 60, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - #ifdef HAS_FULL_SCREEN - #ifndef HAS_PSRAM - display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 2); - #else - display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 1); - display_obj.tft.drawString("P:" + String(getPSRAMUsagePercent()) + "%", SB_MEM_X, 8, 1); - #endif - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.drawString(String(getDRAMUsagePercent()) + "%", TFT_WIDTH/1.75, 0, 1); - #endif - - - MenuFunctions::battery(true); - display_obj.tft.fillRect(186, 0, 16, STATUS_BAR_WIDTH, STATUSBAR_COLOR); - - - // Disable touch stuff - #ifdef HAS_ILI9341 - #ifdef HAS_BUTTONS - if (this->disable_touch) { - display_obj.tft.setCursor(0, 1); - display_obj.tft.drawXBitmap(SB_TOUCH_X, - 0, - menu_icons[DISABLE_TOUCH], - 16, - 16, - STATUSBAR_COLOR, - TFT_RED); - } - else { - display_obj.tft.setCursor(0, 1); - display_obj.tft.drawXBitmap(SB_TOUCH_X, - 0, - menu_icons[DISABLE_TOUCH], - 16, - 16, - STATUSBAR_COLOR, - TFT_DARKGREY); - } - #endif - #endif - - // Draw SD info - #ifdef HAS_SD - if (sd_obj.supported) - the_color = TFT_GREEN; - else - the_color = TFT_RED; - - - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_SD_X, - 0, - menu_icons[STATUS_SD], - 16, - 16, - STATUSBAR_COLOR, - the_color); - #endif - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR); - display_obj.tft.drawString("SD", TFT_WIDTH - 12, 0, 1); - #endif - - // WiFi connection status stuff - if (wifi_scan_obj.wifi_connected) { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_WIFI_X, - 0, - menu_icons[JOINED], - 16, - 16, - STATUSBAR_COLOR, - TFT_GREEN); - #endif - } else { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_WIFI_X, - 0, - menu_icons[JOINED], - 16, - 16, - STATUSBAR_COLOR, - TFT_DARKGREY); - #endif - } - - // Force PMKID stuff - if ((wifi_scan_obj.force_pmkid) || (wifi_scan_obj.ep_deauth)) { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_FORCE_X, - 0, - menu_icons[FORCE], - 16, - 16, - STATUSBAR_COLOR, - TFT_GREEN); - #endif - } else { - #ifdef HAS_FULL_SCREEN - display_obj.tft.drawXBitmap(SB_FORCE_X, - 0, - menu_icons[FORCE], - 16, - 16, - STATUSBAR_COLOR, - TFT_DARKGREY); - #endif - } -} - -void MenuFunctions::orientDisplay() { - display_obj.init(); - - display_obj.tft.setRotation(SCREEN_ORIENTATION); // Portrait - - display_obj.tft.setCursor(0, 0); - - #ifdef HAS_ILI9341 - #ifndef HAS_CYD_TOUCH - display_obj.setCalData(); - #else - display_obj.touchscreen.setRotation(0); - #endif - #endif - - changeMenu(current_menu, true); -} - -const char* MenuFunctions::callSetting(const char* key) { - specSettingMenu.name = key; - - const char* setting_type = settings_obj.getSettingType(key); - - if (setting_type && strcmp(setting_type, "bool") == 0) { - return "bool"; - } - - return ""; -} - -/*void MenuFunctions::displaySetting(String key, Menu* menu, int index) { - specSettingMenu.name = key; - - bool setting_value = settings_obj.loadSetting(key); - - // Make a local copy of menu node - MenuNode node = menu->list->get(index); - - display_obj.tft.setTextWrap(false); - display_obj.tft.setFreeFont(NULL); - display_obj.tft.setCursor(0, 100); - display_obj.tft.setTextSize(1); - - // Set local copy value - if (!setting_value) { - display_obj.tft.setTextColor(TFT_RED); - display_obj.tft.println(F(text_table1[4])); - node.selected = false; - } - else { - display_obj.tft.setTextColor(TFT_GREEN); - display_obj.tft.println(F(text_table1[5])); - node.selected = true; - } - - // Put local copy back into menu - menu->list->set(index, node); - -}*/ - -void MenuFunctions::displaySetting(const char* key, Menu* menu, int index) { - specSettingMenu.name = String(key); - - bool setting_value = settings_obj.loadSetting(key); - - // Make a local copy of menu node - MenuNode node = menu->list->get(index); - - display_obj.tft.setTextWrap(false); - display_obj.tft.setFreeFont(NULL); - display_obj.tft.setCursor(0, 100); - display_obj.tft.setTextSize(1); - - // Set local copy value - if (!setting_value) { - display_obj.tft.setTextColor(TFT_RED); - display_obj.tft.println(F(text_table1[4])); - node.selected = false; - } else { - display_obj.tft.setTextColor(TFT_GREEN); - display_obj.tft.println(F(text_table1[5])); - node.selected = true; - } - - // Put local copy back into menu - menu->list->set(index, node); -} - -#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) -void MenuFunctions::updateKeyboard() -{ - M5CardputerKeyboard.updateKeyList(); - M5CardputerKeyboard.updateKeysState(); -} - -bool MenuFunctions::isKeyPressed(char c) -{ - bool pressed = M5CardputerKeyboard.isKeyPressed(c); - - if (pressed) - delay(200); - - return pressed; -} -#endif - -#ifdef HAS_DIRECT_UPLOAD - void MenuFunctions::buildUploadFileMenu() { - if (sd_obj.supported) { - this->setupSDFileList(); - - uploadLogsMenu.list->clear(); - delete uploadLogsMenu.list; - uploadLogsMenu.list = new LinkedList(); - uploadLogsMenu.name = "Logs"; - - uploadLogsMenu.parentMenu = &wifiGeneralMenu; - - this->addNodes(&uploadLogsMenu, "Back", TFTLIGHTGREY, 0, [this]() { - this->changeMenu(uploadLogsMenu.parentMenu, true); - }); - - this->addNodes(&uploadLogsMenu, "Delete Wardrive Logs", TFTORANGE, 0, [this]() { - this->changeMenu(&deleteAllMenu, true); - }); - - this->addNodes(&uploadLogsMenu, "Upload All", TFTGREEN, 0, [this]() { - this->changeMenu(&uploadAllMenu, true); - - }); - - for (int i = 0; i < sd_obj.sd_files->size(); i++) { - File current_file = sd_obj.getFile("/" + sd_obj.sd_files->get(i)); - if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { - if (!sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { - this->addNodes(&uploadLogsMenu, sd_obj.sd_files->get(i).c_str(), TFTCYAN, 0, [this, i]() { - sd_obj.selected_file_name = sd_obj.sd_files->get(i); - Serial.println(sd_obj.sd_files->get(i) + " selected"); - this->changeMenu(&actionMenu, true); - }); - } - } - } - - Serial.println("Built SD file menu with " + (String)sd_obj.sd_files->size() + " files"); - } else { - Serial.println("SD Card not detected. Skipping menu creation..."); - } - } + +#ifdef HAS_MINI_SCREEN +void MenuFunctions::drawMiniMenuButton(int b, int x, bool selected) { + if (!current_menu || !current_menu->list || x < 0 || x >= current_menu->list->size()) + return; + + MenuNode mini_node = current_menu->list->get(x); + bool is_setting_node = (mini_node.icon == SETTINGS && mini_node.color == TFTLIGHTGREY); + uint16_t color = is_setting_node ? (mini_node.selected ? TFT_GREEN : TFT_RED) : this->getColor(mini_node.color); + int16_t button_x = KEY_X - (KEY_W / 2); + int16_t button_y = (KEY_Y + (b * (KEY_H + KEY_SPACING_Y))) - (KEY_H / 2); + + uint16_t background = selected ? (is_setting_node ? TFT_LIGHTGREY : color) : TFT_BLACK; + uint16_t text_color = (selected && !is_setting_node) ? TFT_BLACK : color; + + display_obj.tft.setFreeFont(NULL); + display_obj.tft.setTextSize(1); + display_obj.tft.setTextWrap(false); + display_obj.tft.fillRect(button_x, button_y - 4, KEY_W, KEY_H, background); + display_obj.tft.setTextColor(text_color, background); + display_obj.tft.setCursor(button_x + BUTTON_PADDING, button_y + (KEY_H / 2) - 8); + display_obj.tft.print(current_menu->list->get(x).name); +} +#endif + +void MenuFunctions::buttonNotSelected(int b, int x) { + if (x == -1) + x = b; + + // Ensure b is within valid button index range + b = (x - menu_start_index) % BUTTON_SCREEN_LIMIT; + + #ifdef HAS_MINI_SCREEN + this->drawMiniMenuButton(b, x, false); + #endif + + uint16_t color = (current_menu->list->get(x).icon == SETTINGS && current_menu->list->get(x).color == TFTLIGHTGREY) ? (current_menu->list->get(x).selected ? TFT_GREEN : TFT_RED) : this->getColor(current_menu->list->get(x).color); + uint16_t icon_color = (current_menu->list->get(x).icon == SETTINGS && current_menu->list->get(x).color == TFTLIGHTGREY) ? TFT_LIGHTGREY : color; + + #ifdef HAS_FULL_SCREEN + display_obj.tft.setFreeFont(MENU_FONT); + display_obj.key[b].initButton(&display_obj.tft, KEY_X, KEY_Y + b * (KEY_H + KEY_SPACING_Y), KEY_W, KEY_H, TFT_BLACK, TFT_BLACK, color, (char*)"", KEY_TEXTSIZE); + display_obj.key[b].drawButton(false, current_menu->list->get(x).name); + if ((current_menu->list->get(x).name != text09) && (current_menu->list->get(x).icon != 255)) + display_obj.tft.drawXBitmap(0, + KEY_Y + (b * (KEY_H + KEY_SPACING_Y)) - (ICON_H / 2), + menu_icons[current_menu->list->get(x).icon], + ICON_W, + ICON_H, + TFT_BLACK, + icon_color); + display_obj.tft.setFreeFont(NULL); + #endif +} + +void MenuFunctions::buttonSelected(int b, int x) { + if (x == -1) + x = b; + + // Ensure b is within valid button index range + b = (x - menu_start_index) % BUTTON_SCREEN_LIMIT; + + uint16_t color = this->getColor(current_menu->list->get(x).color); + + #ifdef HAS_MINI_SCREEN + this->drawMiniMenuButton(b, x, true); + #endif + + #ifdef HAS_FULL_SCREEN + display_obj.tft.setFreeFont(MENU_FONT); + if (current_menu->list->get(x).icon == SETTINGS && current_menu->list->get(x).color == TFTLIGHTGREY) { + uint16_t setting_color = current_menu->list->get(x).selected ? TFT_GREEN : TFT_RED; + display_obj.key[b].initButton(&display_obj.tft, KEY_X, KEY_Y + b * (KEY_H + KEY_SPACING_Y), KEY_W, KEY_H, TFT_BLACK, TFT_LIGHTGREY, setting_color, (char*)"", KEY_TEXTSIZE); + display_obj.key[b].drawButton(false, current_menu->list->get(x).name); + display_obj.tft.drawXBitmap(0, + KEY_Y + (b * (KEY_H + KEY_SPACING_Y)) - (ICON_H / 2), + menu_icons[current_menu->list->get(x).icon], + ICON_W, + ICON_H, + TFT_BLACK, + TFT_LIGHTGREY); + } else { + display_obj.key[b].drawButton(true, current_menu->list->get(x).name); + if ((current_menu->list->get(x).name != text09) && (current_menu->list->get(x).icon != 255)) + display_obj.tft.drawXBitmap(0, + KEY_Y + (b * (KEY_H + KEY_SPACING_Y)) - (ICON_H / 2), + menu_icons[current_menu->list->get(x).icon], + ICON_W, + ICON_H, + TFT_BLACK, + color); + } + display_obj.tft.setFreeFont(NULL); + #endif +} + +void MenuFunctions::displayMenuButtons() { + #ifdef HAS_ILI9341 + // Draw lines to show each menu button + for (int i = 0; i < 3; i++) { + + // Draw horizontal line on left + display_obj.tft.drawLine(0, + TFT_HEIGHT / 3 * (i), + (TFT_WIDTH / 12) / 2, + TFT_HEIGHT / 3 * (i), + TFT_FARTGRAY); + + // Draw horizontal line on right + display_obj.tft.drawLine(TFT_WIDTH - 1 - ((TFT_WIDTH / 12) / 2), + TFT_HEIGHT / 3 * (i), + TFT_WIDTH, + TFT_HEIGHT / 3 * (i), + TFT_FARTGRAY); + + // Draw vertical line on left + display_obj.tft.drawLine(0, + (TFT_HEIGHT / 3 * (i)) - ((TFT_WIDTH / 12) / 2), + 0, + (TFT_HEIGHT / 3 * (i)) + ((TFT_WIDTH / 12) / 2), + TFT_FARTGRAY); + + // Draw vertical line on right + display_obj.tft.drawLine(TFT_WIDTH - 1, + (TFT_HEIGHT / 3 * (i)) - ((TFT_WIDTH / 12) / 2), + TFT_WIDTH - 1, + (TFT_HEIGHT / 3 * (i)) + ((TFT_WIDTH / 12) / 2), + TFT_FARTGRAY); + } + #endif +} + +// Function to check menu input +void MenuFunctions::main(uint32_t currentTime) +{ + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + this->updateKeyboard(); + #endif + + // Some function exited and we need to go back to normal + if (display_obj.exit_draw) { + if (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) + wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; + display_obj.exit_draw = false; + this->orientDisplay(); + } + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || + (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || + (wifi_scan_obj.currentScanMode == OTA_UPDATE) || + (wifi_scan_obj.currentScanMode == ESP_UPDATE) || + (wifi_scan_obj.currentScanMode == SHOW_INFO) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_DATA) || + (wifi_scan_obj.currentScanMode == GPS_POI) || + (wifi_scan_obj.currentScanMode == GPS_TRACKER) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_GPS_NMEA)) { + if (wifi_scan_obj.orient_display) { + this->orientDisplay(); + wifi_scan_obj.orient_display = false; + } + } + + if (currentTime != 0) { + if (currentTime - initTime >= BANNER_TIME) { + this->initTime = millis(); + if ((wifi_scan_obj.currentScanMode != LV_JOIN_WIFI) && + (wifi_scan_obj.currentScanMode != LV_ADD_SSID)) + this->updateStatusBar(); + + // Do channel analyzer stuff + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || + (wifi_scan_obj.currentScanMode == BT_SCAN_ANALYZER)){ + #ifdef HAS_SCREEN + this->setGraphScale(this->graphScaleCheck(wifi_scan_obj._analyzer_values)); + + this->drawGraph(wifi_scan_obj._analyzer_values); + #endif + } + + if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { + #ifdef HAS_SCREEN + this->setGraphScale(this->graphScaleCheckSmall(wifi_scan_obj.channel_activity)); + + this->drawGraphSmall(wifi_scan_obj.channel_activity); + + #endif + } + } + } + + + boolean pressed = false; + // This is code from bodmer's keypad example + uint16_t t_x = 0, t_y = 0; // To store the touch coordinates + + // Get the display buffer out of the way + if ((wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF ) && + (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BEACON_SPAM) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AP_SPAM) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_CSA) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_QUIET) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AUTH) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_MANUAL) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_TARGETED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG_TARGETED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP_TARGETED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_MIMIC) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_FUNNY_BEACON) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_RICK_ROLL)) + display_obj.displayBuffer(); + + + int pre_getTouch = millis(); + + #ifdef HAS_ILI9341 + if (!this->disable_touch) + pressed = display_obj.updateTouch(&t_x, &t_y); + #endif + + + // Brightness gesture: hold top or bottom zone 1.5s to enter brightness mode + #ifdef HAS_ILI9341 + if (pressed && (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF || + wifi_scan_obj.currentScanMode == WIFI_CONNECTED)) { + uint16_t zoneUp = TFT_HEIGHT * 25 / 100; + uint16_t zoneDown = TFT_HEIGHT * 75 / 100; + if (t_y < zoneUp || t_y >= zoneDown) { + uint32_t hold_start = millis(); + uint16_t hx, hy; + bool held = false; + while (display_obj.updateTouch(&hx, &hy)) { + if (millis() - hold_start >= 1500) { + held = true; + break; + } + delay(10); + } + if (held) { + // Wait for release before entering brightness mode + while (display_obj.updateTouch(&hx, &hy)) delay(10); + this->brightnessMode(); + return; + } + } + } + #endif + + // POI button interception during wardrive — full width bottom bar + #ifdef HAS_ILI9341 + if (pressed && + (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE || + wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE)) { + if (t_y >= (SCREEN_HEIGHT - 50)) { + wifi_scan_obj.tagPOI(nullptr); + // Brief green flash + display_obj.tft.fillRect(0, SCREEN_HEIGHT - 50, SCREEN_WIDTH, 50, TFT_GREEN); + display_obj.tft.setTextSize(2); + #ifdef HAS_GPS + if (gps_obj.getFixStatus()) + display_obj.tft.setTextColor(TFT_BLACK, TFT_GREEN); + else + #endif + display_obj.tft.setTextColor(TFT_BLACK, TFT_RED); + String poiFlash = "POI (" + String(wifi_scan_obj.poiCount) + ")"; + int16_t flashWidth = poiFlash.length() * 12; + display_obj.tft.setCursor((SCREEN_WIDTH - flashWidth) / 2, SCREEN_HEIGHT - 33); + display_obj.tft.print(poiFlash); + delay(200); + x = -1; + y = -1; + return; + } + } + #endif + + // This is if there are scans/attacks going on + #ifdef HAS_ILI9341 + if ((wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF) && + (pressed) && + (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) && + (wifi_scan_obj.currentScanMode != OTA_UPDATE) && + (wifi_scan_obj.currentScanMode != ESP_UPDATE) && + (wifi_scan_obj.currentScanMode != SHOW_INFO) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_DATA) && + (wifi_scan_obj.currentScanMode != GPS_POI) && + (wifi_scan_obj.currentScanMode != GPS_TRACKER) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_NMEA)) + { + // Stop the current scan + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_SAE_COMMIT) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DETECT_FOLLOW) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DISPLAY_AP_INFO) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP_STA) || + (wifi_scan_obj.currentScanMode == WIFI_PING_SCAN) || + (wifi_scan_obj.currentScanMode == WIFI_ARP_SCAN) || + (wifi_scan_obj.currentScanMode == WIFI_PORT_SCAN_ALL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SSH) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_TELNET) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DNS) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SMTP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTPS) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RDP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PWN) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PINESCAN) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_MULTISSID) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_ESPRESSIF) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_ALL) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_SPAM) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AP_SPAM) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_CSA) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_QUIET) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AUTH) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG_TARGETED) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP_TARGETED) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SAE_COMMIT) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_MIMIC) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_FUNNY_BEACON) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_RICK_ROLL) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_LIST) || + (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FOX_HUNT) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) || + (wifi_scan_obj.currentScanMode == BT_SCAN_RAYBAN) || + (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) || + (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLIPPER) || + (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE) || + (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE_TWO) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SOUR_APPLE) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_APPLE_JUICE) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SPAM_ALL) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SAMSUNG_SPAM) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_GOOGLE_SPAM) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_FLIPPER_SPAM) || + (wifi_scan_obj.currentScanMode == BT_SPOOF_AIRTAG) || + (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) || + (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT) || + (wifi_scan_obj.currentScanMode == BT_SCAN_SKIMMERS) || + (wifi_scan_obj.currentScanMode == BT_SCAN_ANALYZER)) + { + wifi_scan_obj.StartScan(WIFI_SCAN_OFF); + + // If we don't do this, the text and button coordinates will be off + display_obj.init(); + + // Take us back to the menu + changeMenu(current_menu, true); + } + + x = -1; + y = -1; + + return; + } + #endif + + #ifdef HAS_BUTTONS + + #if (C_BTN >= 0) && !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + bool c_btn_press = c_btn.justPressed(); + #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + bool c_btn_press = this->isKeyPressed('('); + #endif + + #ifndef HAS_ILI9341 + + if ((c_btn_press) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_OFF) && + (wifi_scan_obj.currentScanMode != WIFI_CONNECTED) && + (wifi_scan_obj.currentScanMode != OTA_UPDATE) && + (wifi_scan_obj.currentScanMode != ESP_UPDATE) && + (wifi_scan_obj.currentScanMode != SHOW_INFO) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_DATA) && + (wifi_scan_obj.currentScanMode != GPS_POI) && + (wifi_scan_obj.currentScanMode != GPS_TRACKER) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_GPS_NMEA)) + { + // Stop the current scan + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SAE_COMMIT) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DETECT_FOLLOW) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION_WAR_DRIVE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_STATION) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_WAR_DRIVE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DISPLAY_AP_INFO) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP_STA) || + (wifi_scan_obj.currentScanMode == WIFI_PING_SCAN) || + (wifi_scan_obj.currentScanMode == WIFI_ARP_SCAN) || + (wifi_scan_obj.currentScanMode == WIFI_PORT_SCAN_ALL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SSH) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_TELNET) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DNS) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SMTP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_HTTPS) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RDP) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PWN) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PINESCAN) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_MULTISSID) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_ESPRESSIF) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_ALL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_SPAM) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AP_SPAM) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_CSA) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_QUIET) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_AUTH) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_MANUAL) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_DEAUTH_TARGETED) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG_TARGETED) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BAD_MSG) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SLEEP_TARGETED) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_SAE_COMMIT) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_MIMIC) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_FUNNY_BEACON) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_RICK_ROLL) || + (wifi_scan_obj.currentScanMode == WIFI_ATTACK_BEACON_LIST) || + (wifi_scan_obj.currentScanMode == BT_SCAN_ALL) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FOX_HUNT) || + (wifi_scan_obj.currentScanMode == BT_SCAN_RAYBAN) || + (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) || + (wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLIPPER) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || + (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE) || + (wifi_scan_obj.currentScanMode == BT_SCAN_SIMPLE_TWO) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SOUR_APPLE) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_APPLE_JUICE) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SPAM_ALL) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_SAMSUNG_SPAM) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_GOOGLE_SPAM) || + (wifi_scan_obj.currentScanMode == BT_ATTACK_FLIPPER_SPAM) || + (wifi_scan_obj.currentScanMode == BT_SPOOF_AIRTAG) || + (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE) || + (wifi_scan_obj.currentScanMode == BT_SCAN_WAR_DRIVE_CONT) || + (wifi_scan_obj.currentScanMode == BT_SCAN_SKIMMERS) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_ACTIVE_LIST_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || + (wifi_scan_obj.currentScanMode == BT_SCAN_ANALYZER)) + { + wifi_scan_obj.StartScan(WIFI_SCAN_OFF); + + // Restore display state without full reinit to avoid screen flash + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.setRotation(SCREEN_ORIENTATION); + display_obj.clearScreen(); + #else + display_obj.init(); + #endif + + // Take us back to the menu + changeMenu(current_menu, true); + } + + x = -1; + y = -1; + + return; + } + #endif + + #endif + + + // Check if any key coordinate boxes contain the touch coordinates + // This is for when on a menu + // Make sure to add certain scanning functions here or else + // menu items will be selected while scans and attacks are running + #ifdef HAS_ILI9341 + if ((wifi_scan_obj.currentScanMode != WIFI_ATTACK_BEACON_SPAM) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AP_SPAM) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_CSA) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_QUIET) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_AUTH) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_MANUAL) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_DEAUTH_TARGETED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG_TARGETED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_BAD_MSG) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SLEEP_TARGETED) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_SAE_COMMIT) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_MIMIC) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_PACKET_RATE) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_RAW_CAPTURE) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_CHAN_ANALYZER) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_CHAN_ACT) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_SIG_STREN) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_AP) && + (wifi_scan_obj.currentScanMode != BT_SCAN_FLOCK) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_PROBE) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_DEAUTH) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_FUNNY_BEACON) && + (wifi_scan_obj.currentScanMode != WIFI_SCAN_EAPOL) && + (wifi_scan_obj.currentScanMode != WIFI_ATTACK_RICK_ROLL)) + { + // Need this to set all keys to false + /*for (uint8_t b = 0; b < BUTTON_ARRAY_LEN; b++) { + if (pressed && display_obj.key[b].contains(t_x, t_y)) { + display_obj.key[b].press(true); // tell the button it is pressed + } else { + display_obj.key[b].press(false); // tell the button it is NOT pressed + } + }*/ + + // Detect up, down, select + uint8_t menu_button = display_obj.menuButton(&t_x, &t_y, pressed); + + if (menu_button > -1) { + if (menu_button == UP_BUTTON) { + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || + (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || + (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { + if (current_menu->selected > 0) { + current_menu->selected--; + // Page up + if (current_menu->selected < this->menu_start_index) { + this->buildButtons(current_menu, current_menu->selected); + this->displayCurrentMenu(current_menu->selected); + } + this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); + if (!current_menu->list->get(current_menu->selected + 1).selected || (current_menu->list->get(current_menu->selected + 1).icon == SETTINGS && current_menu->list->get(current_menu->selected + 1).color == TFTLIGHTGREY)) + this->buttonNotSelected(current_menu->selected + 1 - this->menu_start_index, current_menu->selected + 1); + } + // Loop to end + else { + current_menu->selected = current_menu->list->size() - 1; + if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { + this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + } + this->buttonSelected(current_menu->selected, current_menu->selected); + if (!current_menu->list->get(0).selected || (current_menu->list->get(0).icon == SETTINGS && current_menu->list->get(0).color == TFTLIGHTGREY)) + this->buttonNotSelected(0, this->menu_start_index); + } + } + else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.set_channel < 14) + wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1); + else + wifi_scan_obj.changeChannel(1); + #else + if (wifi_scan_obj.dual_band_channel_index < DUAL_BAND_CHANNELS - 1) + wifi_scan_obj.dual_band_channel_index++; + else + wifi_scan_obj.dual_band_channel_index = 0; + + wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); + #endif + } + else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.activity_page < MAX_CHANNEL / CHAN_PER_PAGE) { + wifi_scan_obj.activity_page++; + } + #else + if (wifi_scan_obj.activity_page < DUAL_BAND_CHANNELS / CHAN_PER_PAGE) { + wifi_scan_obj.activity_page++; + } + #endif + wifi_scan_obj.drawChannelLine(); + } + } + if (menu_button == DOWN_BUTTON) { + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || + (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || + (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { + if (current_menu->selected < current_menu->list->size() - 1) { + current_menu->selected++; + // Page down + if (current_menu->selected - this->menu_start_index >= BUTTON_SCREEN_LIMIT) { + this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + } + else + this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); + if (!current_menu->list->get(current_menu->selected - 1).selected || (current_menu->list->get(current_menu->selected - 1).icon == SETTINGS && current_menu->list->get(current_menu->selected - 1).color == TFTLIGHTGREY)) + this->buttonNotSelected(current_menu->selected - 1 - this->menu_start_index, current_menu->selected - 1); + } + // Loop to beginning + else { + if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { + current_menu->selected = 0; + this->buildButtons(current_menu); + this->displayCurrentMenu(); + this->buttonSelected(current_menu->selected); + } + else { + current_menu->selected = 0; + this->buttonSelected(current_menu->selected); + if (!current_menu->list->get(current_menu->list->size() - 1).selected || (current_menu->list->get(current_menu->list->size() - 1).icon == SETTINGS && current_menu->list->get(current_menu->list->size() - 1).color == TFTLIGHTGREY)) + this->buttonNotSelected(current_menu->list->size() - 1); + } + } + } + else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.set_channel > 1) + wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1); + else + wifi_scan_obj.changeChannel(14); + #else + if (wifi_scan_obj.dual_band_channel_index > 0) + wifi_scan_obj.dual_band_channel_index--; + else + wifi_scan_obj.dual_band_channel_index = DUAL_BAND_CHANNELS - 1; + + wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); + #endif + } + else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.activity_page > 1) { + wifi_scan_obj.activity_page--; + } + #else + if (wifi_scan_obj.activity_page > 0) { + wifi_scan_obj.activity_page--; + } + #endif + wifi_scan_obj.drawChannelLine(); + } + } + if(menu_button == SELECT_BUTTON) { + current_menu->list->get(current_menu->selected).callable(); + } + else { + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || + (wifi_scan_obj.currentScanMode == WIFI_CONNECTED)) + this->displayMenuButtons(); + } + } + } + x = -1; + y = -1; + #endif + + // Menu navigation and paging + #ifdef HAS_BUTTONS + // Don't do this for touch screens + #if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1) || defined(MARAUDER_CYD_MICRO) || defined(MARAUDER_CYD_GUITION) || defined(MARAUDER_CYD_2USB) || defined(MARAUDER_CYD_3_5_INCH)) + #if !defined(MARAUDER_M5STICKC) || defined(MARAUDER_M5STICKCP2) + #if (U_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) + #if (U_BTN >= 0) + if (u_btn.justPressed()) { + #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + if (this->isKeyPressed(';')) { + #endif + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || + (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || + (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { + if (current_menu->selected > 0) { + current_menu->selected--; + // Page up + if (current_menu->selected < this->menu_start_index) { + this->buildButtons(current_menu, current_menu->selected); + this->displayCurrentMenu(current_menu->selected); + } + this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); + if (!current_menu->list->get(current_menu->selected + 1).selected || (current_menu->list->get(current_menu->selected + 1).icon == SETTINGS && current_menu->list->get(current_menu->selected + 1).color == TFTLIGHTGREY)) + this->buttonNotSelected(current_menu->selected + 1 - this->menu_start_index, current_menu->selected + 1); + } + // Loop to end + else { + current_menu->selected = current_menu->list->size() - 1; + if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { + this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + } + this->buttonSelected(current_menu->selected, current_menu->selected); + if (!current_menu->list->get(0).selected || (current_menu->list->get(0).icon == SETTINGS && current_menu->list->get(0).color == TFTLIGHTGREY)) + this->buttonNotSelected(0, this->menu_start_index); + } + } + else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.set_channel < 14) + wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1); + else + wifi_scan_obj.changeChannel(1); + #else + if (wifi_scan_obj.dual_band_channel_index < DUAL_BAND_CHANNELS - 1) + wifi_scan_obj.dual_band_channel_index++; + else + wifi_scan_obj.dual_band_channel_index = 0; + + wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); + #endif + } + else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.activity_page < MAX_CHANNEL / CHAN_PER_PAGE) { + wifi_scan_obj.activity_page++; + } + #else + if (wifi_scan_obj.activity_page < DUAL_BAND_CHANNELS / CHAN_PER_PAGE) { + wifi_scan_obj.activity_page++; + } + #endif + wifi_scan_obj.drawChannelLine(); + } + } + #endif + #endif + + #if (D_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) + #if (D_BTN >= 0) + if (d_btn.justPressed()){ + #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + if (this->isKeyPressed('.')){ + #endif + if ((wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) || + (wifi_scan_obj.currentScanMode == WIFI_CONNECTED) || + (wifi_scan_obj.currentScanMode == OTA_UPDATE)) { + if (current_menu->selected < current_menu->list->size() - 1) { + current_menu->selected++; + // Page down + if (current_menu->selected - this->menu_start_index >= BUTTON_SCREEN_LIMIT) { + this->buildButtons(current_menu, current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + this->displayCurrentMenu(current_menu->selected + 1 - BUTTON_SCREEN_LIMIT); + } + else + this->buttonSelected(current_menu->selected - this->menu_start_index, current_menu->selected); + if (!current_menu->list->get(current_menu->selected - 1).selected || (current_menu->list->get(current_menu->selected - 1).icon == SETTINGS && current_menu->list->get(current_menu->selected - 1).color == TFTLIGHTGREY)) + this->buttonNotSelected(current_menu->selected - 1 - this->menu_start_index, current_menu->selected - 1); + } + // Loop to beginning + else { + if (current_menu->selected >= BUTTON_SCREEN_LIMIT) { + current_menu->selected = 0; + this->buildButtons(current_menu); + this->displayCurrentMenu(); + this->buttonSelected(current_menu->selected); + } + else { + current_menu->selected = 0; + this->buttonSelected(current_menu->selected); + if (!current_menu->list->get(current_menu->list->size() - 1).selected || (current_menu->list->get(current_menu->list->size() - 1).icon == SETTINGS && current_menu->list->get(current_menu->list->size() - 1).color == TFTLIGHTGREY)) + this->buttonNotSelected(current_menu->list->size() - 1); + } + } + } + else if ((wifi_scan_obj.currentScanMode == WIFI_PACKET_MONITOR) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_EAPOL) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ANALYZER) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PACKET_RATE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_RAW_CAPTURE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP) || + (wifi_scan_obj.currentScanMode == BT_SCAN_FLOCK) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_PROBE) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_DEAUTH) || + (wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN)) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.set_channel > 1) + wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1); + else + wifi_scan_obj.changeChannel(14); + #else + if (wifi_scan_obj.dual_band_channel_index > 0) + wifi_scan_obj.dual_band_channel_index--; + else + wifi_scan_obj.dual_band_channel_index = DUAL_BAND_CHANNELS - 1; + + wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); + #endif + } + else if (wifi_scan_obj.currentScanMode == WIFI_SCAN_CHAN_ACT) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.activity_page > 1) { + wifi_scan_obj.activity_page--; + } + #else + if (wifi_scan_obj.activity_page > 0) { + wifi_scan_obj.activity_page--; + } + #endif + wifi_scan_obj.drawChannelLine(); + } + } + #endif + + #if (R_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) + #if (R_BTN >= 0) + if (r_btn.justPressed()) { + #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + if (this->isKeyPressed('/')) { + #endif + if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.set_channel < 14) + wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel + 1); + else + wifi_scan_obj.changeChannel(1); + #else + if (wifi_scan_obj.dual_band_channel_index < DUAL_BAND_CHANNELS - 1) + wifi_scan_obj.dual_band_channel_index++; + else + wifi_scan_obj.dual_band_channel_index = 0; + + wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); + #endif + } + } + #endif + + #if (L_BTN >= 0 || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV)) + #if (L_BTN >= 0) + if (l_btn.justPressed()) { + #elif defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + if (this->isKeyPressed(',')) { + #endif + if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) { + #ifndef HAS_DUAL_BAND + if (wifi_scan_obj.set_channel > 1) + wifi_scan_obj.changeChannel(wifi_scan_obj.set_channel - 1); + else + wifi_scan_obj.changeChannel(14); + #else + if (wifi_scan_obj.dual_band_channel_index > 0) + wifi_scan_obj.dual_band_channel_index--; + else + wifi_scan_obj.dual_band_channel_index = DUAL_BAND_CHANNELS - 1; + + wifi_scan_obj.changeChannel(wifi_scan_obj.dual_band_channels[wifi_scan_obj.dual_band_channel_index]); + #endif + } + } + #endif + + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + if (this->isKeyPressed('`') || this->isKeyPressed(KEY_BACKSPACE)) { + if (wifi_scan_obj.currentScanMode == WIFI_SCAN_OFF) { + if (current_menu->parentMenu != NULL) { + this->changeMenu(current_menu->parentMenu, true); + } + } + } + #endif + + if(c_btn_press){ + current_menu->list->get(current_menu->selected).callable(); + } + + #endif + #endif +} + +#if BATTERY_ANALOG_ON == 1 +byte battery_analog_array[10]; +byte battery_count = 0; +byte battery_analog_last = 101; +#define BATTERY_CHECK 50 +uint16_t battery_analog = 0; +void MenuFunctions::battery(bool initial) +{ + if (BATTERY_ANALOG_ON) { + uint8_t n = 0; + byte battery_analog_sample[10]; + byte deviation; + if (battery_count == BATTERY_CHECK - 5) digitalWrite(BATTERY_PIN, HIGH); + else if (battery_count == 5) digitalWrite(BATTERY_PIN, LOW); + if (battery_count == 0) { + battery_analog = 0; + for (n = 9; n > 0; n--)battery_analog_array[n] = battery_analog_array[n - 1]; + for (n = 0; n < 10; n++) { + battery_analog_sample[n] = map((analogRead(ANALOG_PIN) * 5), 2400, 4200, 0, 100); + if (battery_analog_sample[n] > 100) battery_analog_sample[n] = 100; + else if (battery_analog_sample[n] < 0) battery_analog_sample[n] = 0; + battery_analog += battery_analog_sample[n]; + } + battery_analog = battery_analog / 10; + for (n = 0; n < 10; n++) { + deviation = abs(battery_analog - battery_analog_sample[n]); + if (deviation >= 10) battery_analog_sample[n] = battery_analog; + } + battery_analog = 0; + for (n = 0; n < 10; n++) battery_analog += battery_analog_sample[n]; + battery_analog = battery_analog / 10; + battery_analog_array[0] = battery_analog; + if (battery_analog_array[9] > 0 ) { + battery_analog = 0; + for (n = 0; n < 10; n++) battery_analog += battery_analog_array[n]; + battery_analog = battery_analog / 10; + } + battery_count ++; + } + else if (battery_count < BATTERY_CHECK) battery_count++; + else if (battery_count >= BATTERY_CHECK) battery_count = 0; + + if (battery_analog_last != battery_analog) { + battery_analog_last = battery_analog; + MenuFunctions::battery2(); + } + } +} +void MenuFunctions::battery2(bool initial) +{ + uint16_t the_color; + if ( digitalRead(CHARGING_PIN) == 1) the_color = TFT_BLUE; + else if (battery_analog < 20) the_color = TFT_RED; + else if (battery_analog < 40) the_color = TFT_YELLOW; + else the_color = TFT_GREEN; + + display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR); + display_obj.tft.fillRect(SB_TOUCH_X, 0, 50, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + display_obj.tft.drawXBitmap(SB_TOUCH_X, + 0, + menu_icons[STATUS_BAT], + 16, + 16, + STATUSBAR_COLOR, + the_color); + display_obj.tft.drawString((String) battery_analog + "%", SB_BAT_X, 0, 2); +} +#else +void MenuFunctions::battery(bool initial) +{ + #ifdef HAS_BATTERY + uint16_t the_color; + if (battery_obj.i2c_supported) + { + // Could use int compare maybe idk + if (((String)battery_obj.battery_level != "25") && ((String)battery_obj.battery_level != "0")) + the_color = TFT_GREEN; + else + the_color = TFT_RED; + + if ((battery_obj.battery_level != battery_obj.old_level) || (initial)) { + battery_obj.old_level = battery_obj.battery_level; + display_obj.tft.fillRect(204, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + } + + display_obj.tft.setCursor(0, 1); + /*if (!this->disable_touch) { + display_obj.tft.drawXBitmap(SB_TOUCH_X, + 0, + menu_icons[STATUS_BAT], + 16, + 16, + STATUSBAR_COLOR, + the_color); + }*/ + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.drawString((String)battery_obj.battery_level + "%", SB_BAT_X, 0, 1); + #else + display_obj.tft.drawString((String)battery_obj.battery_level + "%", SB_BAT_X, 0, 2); + #endif + } + #endif +} +void MenuFunctions::battery2(bool initial) +{ + MenuFunctions::battery(initial); +} +#endif + +void MenuFunctions::updateStatusBar() +{ + display_obj.tft.setTextSize(1); + + bool status_changed = false; + + #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(MARAUDER_MINI_V3) + display_obj.tft.setFreeFont(NULL); + #endif + + uint16_t the_color; + + #ifdef HAS_GPS + if (this->old_gps_sat_count != gps_obj.getNumSats()) { + this->old_gps_sat_count = gps_obj.getNumSats(); + display_obj.tft.fillRect(0, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + status_changed = true; + } + #endif + + // GPS Stuff + #ifdef HAS_GPS + if (gps_obj.getGpsModuleStatus()) { + if (gps_obj.getFixStatus()) + the_color = TFT_GREEN; + else + the_color = TFT_RED; + + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(4, + 0, + menu_icons[STATUS_GPS], + 16, + 16, + STATUSBAR_COLOR, + the_color); + display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR, true); + + display_obj.tft.drawString(gps_obj.getNumSatsString(), 22, 0, 2); + #elif defined(HAS_SCREEN) + display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR, true); + display_obj.tft.drawString("GPS", 0, 0, 1); + #endif + } + #endif + + display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR, true); + + // WiFi Channel Stuff + uint8_t primaryChannel; + wifi_second_chan_t secondChannel; + esp_err_t err = esp_wifi_get_channel(&primaryChannel, &secondChannel); + + uint8_t current_channel = wifi_scan_obj.set_channel; + + if (err == ESP_OK) + current_channel = primaryChannel; + + if ((current_channel != wifi_scan_obj.old_channel) || (status_changed)) { + wifi_scan_obj.old_channel = current_channel; + #if defined(MARAUDER_MINI) || defined(MARAUDER_M5STICKC) || defined(MARAUDER_REV_FEATHER) || defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) || defined(MARAUDER_MINI_V3) + display_obj.tft.fillRect(TFT_WIDTH/4, 0, CHAR_WIDTH * 6, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #elif defined(HAS_DUAL_BAND) + display_obj.tft.fillRect(50, 0, (CHAR_WIDTH / 2) * 8, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #else + display_obj.tft.fillRect(50, 0, (CHAR_WIDTH / 2) * 7, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #endif + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.old_channel, 50, 0, 2); + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.drawString("CH:" + (String)wifi_scan_obj.old_channel, TFT_WIDTH/4, 0, 1); + #endif + } + + // RAM Stuff + wifi_scan_obj.free_ram = String(esp_get_free_heap_size()); + if ((wifi_scan_obj.free_ram != wifi_scan_obj.old_free_ram) || (status_changed)) { + wifi_scan_obj.old_free_ram = wifi_scan_obj.free_ram; + //display_obj.tft.fillRect(SB_MEM_X, 0, 60, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #ifdef HAS_FULL_SCREEN + #ifndef HAS_PSRAM + display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 2); + #else + display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 1); + display_obj.tft.drawString("P:" + String(getPSRAMUsagePercent()) + "%", SB_MEM_X, 8, 1); + #endif + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.drawString(String(getDRAMUsagePercent()) + "%", TFT_WIDTH/1.75, 0, 1); + #endif + } + + // Draw battery info + MenuFunctions::battery(false); + display_obj.tft.fillRect(186, 0, 16, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + + // Disable touch stuff + #ifdef HAS_ILI9341 + #ifdef HAS_BUTTONS + if (this->disable_touch) { + display_obj.tft.setCursor(0, 1); + display_obj.tft.drawXBitmap(SB_TOUCH_X, + 0, + menu_icons[DISABLE_TOUCH], + 16, + 16, + STATUSBAR_COLOR, + TFT_RED); + } + else { + display_obj.tft.setCursor(0, 1); + display_obj.tft.drawXBitmap(SB_TOUCH_X, + 0, + menu_icons[DISABLE_TOUCH], + 16, + 16, + STATUSBAR_COLOR, + TFT_DARKGREY); + } + #endif + #endif + + // Draw SD info + #ifdef HAS_SD + if (sd_obj.supported) + the_color = TFT_GREEN; + else + the_color = TFT_RED; + + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_SD_X, + 0, + menu_icons[STATUS_SD], + 16, + 16, + STATUSBAR_COLOR, + the_color); + #endif + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR, true); + display_obj.tft.drawString("SD", TFT_WIDTH - 12, 0, 1); + #endif + + // WiFi connection status stuff + if (wifi_scan_obj.wifi_connected) { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_WIFI_X, + 0, + menu_icons[JOINED], + 16, + 16, + STATUSBAR_COLOR, + TFT_GREEN); + #endif + } else { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_WIFI_X, + 0, + menu_icons[JOINED], + 16, + 16, + STATUSBAR_COLOR, + TFT_DARKGREY); + #endif + } + + // Force PMKID stuff + if ((wifi_scan_obj.force_pmkid) || (wifi_scan_obj.ep_deauth)) { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_FORCE_X, + 0, + menu_icons[FORCE], + 16, + 16, + STATUSBAR_COLOR, + TFT_GREEN); + #endif + } else { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_FORCE_X, + 0, + menu_icons[FORCE], + 16, + 16, + STATUSBAR_COLOR, + TFT_DARKGREY); + #endif + } +} + +void MenuFunctions::drawStatusBar() +{ + display_obj.tft.setTextSize(1); + #ifdef HAS_MINI_SCREEN + display_obj.tft.setFreeFont(NULL); + #endif + display_obj.tft.fillRect(0, 0, SCREEN_WIDTH, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR); + + uint16_t the_color; + + // GPS Stuff + #ifdef HAS_GPS + if (gps_obj.getGpsModuleStatus()) { + if (gps_obj.getFixStatus()) + the_color = TFT_GREEN; + else + the_color = TFT_RED; + + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(4, + 0, + menu_icons[STATUS_GPS], + 16, + 16, + STATUSBAR_COLOR, + the_color); + display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR); + + display_obj.tft.drawString(gps_obj.getNumSatsString(), 22, 0, 2); + #endif + } + #endif + + display_obj.tft.setTextColor(TFT_WHITE, STATUSBAR_COLOR); + + + // WiFi Channel Stuff + uint8_t primaryChannel; + wifi_second_chan_t secondChannel; + esp_err_t err = esp_wifi_get_channel(&primaryChannel, &secondChannel); + + if (err == ESP_OK) + wifi_scan_obj.old_channel = primaryChannel; + else + wifi_scan_obj.old_channel = wifi_scan_obj.set_channel; + + #ifdef HAS_MINI_SCREEN + display_obj.tft.fillRect(43, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #else + display_obj.tft.fillRect(50, 0, TFT_WIDTH * 0.21, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #endif + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawString("CH: " + (String)wifi_scan_obj.old_channel, 50, 0, 2); + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.drawString("CH:" + (String)wifi_scan_obj.old_channel, TFT_WIDTH/4, 0, 1); + #endif + + // RAM Stuff + wifi_scan_obj.free_ram = String(esp_get_free_heap_size()); + wifi_scan_obj.old_free_ram = wifi_scan_obj.free_ram; + display_obj.tft.fillRect(100, 0, 60, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + #ifdef HAS_FULL_SCREEN + #ifndef HAS_PSRAM + display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 2); + #else + display_obj.tft.drawString("D:" + String(getDRAMUsagePercent()) + "%", SB_MEM_X, 0, 1); + display_obj.tft.drawString("P:" + String(getPSRAMUsagePercent()) + "%", SB_MEM_X, 8, 1); + #endif + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.drawString(String(getDRAMUsagePercent()) + "%", TFT_WIDTH/1.75, 0, 1); + #endif + + + MenuFunctions::battery(true); + display_obj.tft.fillRect(186, 0, 16, STATUS_BAR_WIDTH, STATUSBAR_COLOR); + + + // Disable touch stuff + #ifdef HAS_ILI9341 + #ifdef HAS_BUTTONS + if (this->disable_touch) { + display_obj.tft.setCursor(0, 1); + display_obj.tft.drawXBitmap(SB_TOUCH_X, + 0, + menu_icons[DISABLE_TOUCH], + 16, + 16, + STATUSBAR_COLOR, + TFT_RED); + } + else { + display_obj.tft.setCursor(0, 1); + display_obj.tft.drawXBitmap(SB_TOUCH_X, + 0, + menu_icons[DISABLE_TOUCH], + 16, + 16, + STATUSBAR_COLOR, + TFT_DARKGREY); + } + #endif + #endif + + // Draw SD info + #ifdef HAS_SD + if (sd_obj.supported) + the_color = TFT_GREEN; + else + the_color = TFT_RED; + + + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_SD_X, + 0, + menu_icons[STATUS_SD], + 16, + 16, + STATUSBAR_COLOR, + the_color); + #endif + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.setTextColor(the_color, STATUSBAR_COLOR); + display_obj.tft.drawString("SD", TFT_WIDTH - 12, 0, 1); + #endif + + // WiFi connection status stuff + if (wifi_scan_obj.wifi_connected) { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_WIFI_X, + 0, + menu_icons[JOINED], + 16, + 16, + STATUSBAR_COLOR, + TFT_GREEN); + #endif + } else { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_WIFI_X, + 0, + menu_icons[JOINED], + 16, + 16, + STATUSBAR_COLOR, + TFT_DARKGREY); + #endif + } + + // Force PMKID stuff + if ((wifi_scan_obj.force_pmkid) || (wifi_scan_obj.ep_deauth)) { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_FORCE_X, + 0, + menu_icons[FORCE], + 16, + 16, + STATUSBAR_COLOR, + TFT_GREEN); + #endif + } else { + #ifdef HAS_FULL_SCREEN + display_obj.tft.drawXBitmap(SB_FORCE_X, + 0, + menu_icons[FORCE], + 16, + 16, + STATUSBAR_COLOR, + TFT_DARKGREY); + #endif + } +} + +void MenuFunctions::orientDisplay() { + display_obj.init(); + + display_obj.tft.setRotation(SCREEN_ORIENTATION); // Portrait + + display_obj.tft.setCursor(0, 0); + + #ifdef HAS_ILI9341 + #ifndef HAS_CYD_TOUCH + display_obj.setCalData(); + #else + display_obj.touchscreen.setRotation(0); + #endif + #endif + + changeMenu(current_menu, true); +} + +const char* MenuFunctions::callSetting(const char* key) { + specSettingMenu.name = key; + + const char* setting_type = settings_obj.getSettingType(key); + + if (setting_type && strcmp(setting_type, "bool") == 0) { + return "bool"; + } + + return ""; +} + +/*void MenuFunctions::displaySetting(String key, Menu* menu, int index) { + specSettingMenu.name = key; + + bool setting_value = settings_obj.loadSetting(key); + + // Make a local copy of menu node + MenuNode node = menu->list->get(index); + + display_obj.tft.setTextWrap(false); + display_obj.tft.setFreeFont(NULL); + display_obj.tft.setCursor(0, 100); + display_obj.tft.setTextSize(1); + + // Set local copy value + if (!setting_value) { + display_obj.tft.setTextColor(TFT_RED); + display_obj.tft.println(F(text_table1[4])); + node.selected = false; + } + else { + display_obj.tft.setTextColor(TFT_GREEN); + display_obj.tft.println(F(text_table1[5])); + node.selected = true; + } + + // Put local copy back into menu + menu->list->set(index, node); + +}*/ + +void MenuFunctions::displaySetting(const char* key, Menu* menu, int index) { + specSettingMenu.name = String(key); + + bool setting_value = settings_obj.loadSetting(key); + + // Make a local copy of menu node + MenuNode node = menu->list->get(index); + + display_obj.tft.setTextWrap(false); + display_obj.tft.setFreeFont(NULL); + display_obj.tft.setCursor(0, 100); + display_obj.tft.setTextSize(1); + + // Set local copy value + if (!setting_value) { + display_obj.tft.setTextColor(TFT_RED); + display_obj.tft.println(F(text_table1[4])); + node.selected = false; + } else { + display_obj.tft.setTextColor(TFT_GREEN); + display_obj.tft.println(F(text_table1[5])); + node.selected = true; + } + + // Put local copy back into menu + menu->list->set(index, node); +} + +#if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) +void MenuFunctions::updateKeyboard() +{ + M5CardputerKeyboard.updateKeyList(); + M5CardputerKeyboard.updateKeysState(); +} + +bool MenuFunctions::isKeyPressed(char c) +{ + bool pressed = M5CardputerKeyboard.isKeyPressed(c); + + if (pressed) + delay(200); + + return pressed; +} +#endif + +#ifdef HAS_DIRECT_UPLOAD + void MenuFunctions::buildUploadFileMenu() { + if (sd_obj.supported) { + this->setupSDFileList(); + + uploadLogsMenu.list->clear(); + delete uploadLogsMenu.list; + uploadLogsMenu.list = new LinkedList(); + uploadLogsMenu.name = "Logs"; + + uploadLogsMenu.parentMenu = &wifiGeneralMenu; + + this->addNodes(&uploadLogsMenu, "Back", TFTLIGHTGREY, 0, [this]() { + this->changeMenu(uploadLogsMenu.parentMenu, true); + }); + + this->addNodes(&uploadLogsMenu, "Delete Wardrive Logs", TFTORANGE, 0, [this]() { + this->changeMenu(&deleteAllMenu, true); + }); + + this->addNodes(&uploadLogsMenu, "Upload All", TFTGREEN, 0, [this]() { + this->changeMenu(&uploadAllMenu, true); + + }); + + for (int i = 0; i < sd_obj.sd_files->size(); i++) { + File current_file = sd_obj.getFile("/" + sd_obj.sd_files->get(i)); + if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { + if (!sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { + this->addNodes(&uploadLogsMenu, sd_obj.sd_files->get(i).c_str(), TFTCYAN, 0, [this, i]() { + sd_obj.selected_file_name = sd_obj.sd_files->get(i); + Serial.println(sd_obj.sd_files->get(i) + " selected"); + this->changeMenu(&actionMenu, true); + }); + } + } + } + + Serial.println("Built SD file menu with " + (String)sd_obj.sd_files->size() + " files"); + } else { + Serial.println("SD Card not detected. Skipping menu creation..."); + } + } #endif const char* MenuFunctions::foxSortLabel() const { @@ -1786,2878 +1786,2876 @@ void MenuFunctions::buildBluetoothFoxHuntMenu() { // Function to build the menus void MenuFunctions::RunSetup() -{ - extern LinkedList* access_points; - extern LinkedList* stations; - extern LinkedList* airtags; - extern LinkedList* ipList; - extern LinkedList* probe_req_ssids; - extern LinkedList* ssids; - extern LinkedList* ble_devices; - - this->disable_touch = false; - - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - M5CardputerKeyboard.begin(); - #endif - - // root menu stuff - mainMenu.list = new LinkedList(); // Get list in first menu ready - - // Main menu stuff - wifiMenu.list = new LinkedList(); // Get list in second menu ready -#ifdef HAS_BT - bluetoothMenu.list = new LinkedList(); // Get list in third menu ready -#endif - deviceMenu.list = new LinkedList(); - #ifdef HAS_GPS - if (gps_obj.getGpsModuleStatus()) { - gpsMenu.list = new LinkedList(); - gpsInfoMenu.list = new LinkedList(); - } - #endif - - // Device menu stuff - failedUpdateMenu.list = new LinkedList(); - confirmMenu.list = new LinkedList(); - updateMenu.list = new LinkedList(); - settingsMenu.list = new LinkedList(); - specSettingMenu.list = new LinkedList(); - infoMenu.list = new LinkedList(); - // WiFi menu stuff - wifiSnifferMenu.list = new LinkedList(); - wifiScannerMenu.list = new LinkedList(); - wifiAttackMenu.list = new LinkedList(); - /*#ifdef HAS_GPS - wardrivingMenu.list = new LinkedList(); - #endif*/ - wifiGeneralMenu.list = new LinkedList(); - wifiAPMenu.list = new LinkedList(); - wifiIPMenu.list = new LinkedList(); - apInfoMenu.list = new LinkedList(); - setMacMenu.list = new LinkedList(); - genAPMacMenu.list = new LinkedList(); +{ + extern LinkedList* access_points; + extern LinkedList* stations; + extern LinkedList* airtags; + extern LinkedList* ipList; + extern LinkedList* probe_req_ssids; + extern LinkedList* ssids; + extern LinkedList* ble_devices; + + this->disable_touch = false; + + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + M5CardputerKeyboard.begin(); + #endif + + // root menu stuff + mainMenu.list = new LinkedList(); // Get list in first menu ready + + // Main menu stuff + wifiMenu.list = new LinkedList(); // Get list in second menu ready +#ifdef HAS_BT + bluetoothMenu.list = new LinkedList(); // Get list in third menu ready +#endif + deviceMenu.list = new LinkedList(); + #ifdef HAS_GPS + if (gps_obj.getGpsModuleStatus()) { + gpsMenu.list = new LinkedList(); + gpsInfoMenu.list = new LinkedList(); + } + #endif + + // Device menu stuff + failedUpdateMenu.list = new LinkedList(); + confirmMenu.list = new LinkedList(); + updateMenu.list = new LinkedList(); + settingsMenu.list = new LinkedList(); + specSettingMenu.list = new LinkedList(); + infoMenu.list = new LinkedList(); + // WiFi menu stuff + wifiSnifferMenu.list = new LinkedList(); + wifiScannerMenu.list = new LinkedList(); + wifiAttackMenu.list = new LinkedList(); + /*#ifdef HAS_GPS + wardrivingMenu.list = new LinkedList(); + #endif*/ + wifiGeneralMenu.list = new LinkedList(); + wifiAPMenu.list = new LinkedList(); + wifiIPMenu.list = new LinkedList(); + apInfoMenu.list = new LinkedList(); + setMacMenu.list = new LinkedList(); + genAPMacMenu.list = new LinkedList(); wifiStationMenu.list = new LinkedList(); foxSortMenu.list = new LinkedList(); foxFilterMenu.list = new LinkedList(); - selectProbeSSIDsMenu.list = new LinkedList(); - - // WiFi HTML menu stuff - htmlMenu.list = new LinkedList(); - miniKbMenu.list = new LinkedList(); - #ifdef HAS_SD - sdDeleteMenu.list = new LinkedList(); - #endif - - // Bluetooth menu stuff - bluetoothSnifferMenu.list = new LinkedList(); - bluetoothAttackMenu.list = new LinkedList(); - - // Settings stuff - generateSSIDsMenu.list = new LinkedList(); - clearSSIDsMenu.list = new LinkedList(); - clearAPsMenu.list = new LinkedList(); - saveFileMenu.list = new LinkedList(); - - #ifdef HAS_DIRECT_UPLOAD - uploadLogsMenu.list = new LinkedList(); - uploadAllMenu.list = new LinkedList(); - deleteAllMenu.list = new LinkedList(); - actionMenu.list = new LinkedList(); - #endif - - saveSSIDsMenu.list = new LinkedList(); - loadSSIDsMenu.list = new LinkedList(); - saveAPsMenu.list = new LinkedList(); - loadAPsMenu.list = new LinkedList(); - saveATsMenu.list = new LinkedList(); - loadATsMenu.list = new LinkedList(); - - evilPortalMenu.list = new LinkedList(); - ssidsMenu.list = new LinkedList(); - - #ifdef HAS_GPS - gpsPOIMenu.list = new LinkedList(); - #endif - - foxHuntMenu.list = new LinkedList(); - - // Work menu names - mainMenu.name = text_table1[6]; - wifiMenu.name = text_table1[7]; - deviceMenu.name = text_table1[9]; - failedUpdateMenu.name = text_table1[11]; - confirmMenu.name = text_table1[13]; - updateMenu.name = text_table1[15]; - infoMenu.name = text_table1[17]; - settingsMenu.name = text_table1[18]; - bluetoothMenu.name = text_table1[19]; - wifiSnifferMenu.name = text_table1[20]; - wifiScannerMenu.name = "Scanners"; - wifiAttackMenu.name = text_table1[21]; - wifiGeneralMenu.name = text_table1[22]; - saveFileMenu.name = "Save/Load Files"; - saveSSIDsMenu.name = "Save SSIDs"; - loadSSIDsMenu.name = "Load SSIDs"; - saveAPsMenu.name = "Save APs"; - loadAPsMenu.name = "Load APs"; - saveATsMenu.name = "Save Airtags"; - loadATsMenu.name = "Load Airtags"; - - bluetoothSnifferMenu.name = text_table1[23]; - bluetoothAttackMenu.name = "Bluetooth Attacks"; - generateSSIDsMenu.name = text_table1[27]; - clearSSIDsMenu.name = text_table1[28]; - clearAPsMenu.name = text_table1[29]; - wifiAPMenu.name = "Select"; - wifiIPMenu.name = "Active IPs"; - apInfoMenu.name = "AP Info"; - setMacMenu.name = "Set MACs"; - genAPMacMenu.name = "Generate AP MAC"; - wifiStationMenu.name = "Select Stations"; - - #ifdef HAS_DIRECT_UPLOAD - uploadLogsMenu.name = "Upload Logs"; - uploadAllMenu.name = "Upload All?"; - deleteAllMenu.name = "Delete All?"; - actionMenu.name = "Destination"; - #endif - - #ifdef HAS_GPS - gpsMenu.name = "GPS"; - gpsInfoMenu.name = "GPS Data"; - //wardrivingMenu.name = "Wardriving"; - #endif - htmlMenu.name = "EP HTML List"; - miniKbMenu.name = "Mini Keyboard"; - - #ifdef HAS_SD - sdDeleteMenu.name = "Delete SD Files"; - #endif - - selectProbeSSIDsMenu.name = "Probe Requests"; - evilPortalMenu.name = "Evil Portal"; - ssidsMenu.name = "SSIDs"; - - #ifdef HAS_GPS - gpsPOIMenu.name = "GPS POI"; - #endif - - foxHuntMenu.name = "Fox Hunt"; - - // Build Main Menu - mainMenu.parentMenu = NULL; - this->addNodes(&mainMenu, text_table1[7], TFTGREEN, WIFI, [this]() { - this->changeMenu(&wifiMenu, true); - }); - #ifdef HAS_BT - this->addNodes(&mainMenu, text_table1[19], TFTCYAN, BLUETOOTH, [this]() { - this->changeMenu(&bluetoothMenu, true); - }); - #endif - #ifdef HAS_GPS - if (gps_obj.getGpsModuleStatus()) { - this->addNodes(&mainMenu, text1_66, TFTRED, GPS_MENU, [this]() { - this->changeMenu(&gpsMenu, true); - }); - } - #endif - this->addNodes(&mainMenu, text_table1[9], TFTBLUE, DEVICE, [this]() { - this->changeMenu(&deviceMenu, true); - }); - this->addNodes(&mainMenu, text_table1[30], TFTLIGHTGREY, REBOOT, []() { - ESP.restart(); - }); - - // Build WiFi Menu - wifiMenu.parentMenu = &mainMenu; // Main Menu is second menu parent - this->addNodes(&wifiMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiMenu.parentMenu, true); - }); - this->addNodes(&wifiMenu, text_table1[31], TFTYELLOW, SNIFFERS, [this]() { - this->changeMenu(&wifiSnifferMenu, true); - }); - this->addNodes(&wifiMenu, "Scanners", TFTORANGE, SCANNERS, [this]() { - this->changeMenu(&wifiScannerMenu, true); - }); - /*#ifdef HAS_GPS - this->addNodes(&wifiMenu, "Wardriving", TFTGREEN, NULL, BEACON_SNIFF, [this]() { - this->changeMenu(&wardrivingMenu, true); - }); - #endif*/ - this->addNodes(&wifiMenu, text_table1[32], TFTRED, ATTACKS, [this]() { - this->changeMenu(&wifiAttackMenu, true); - }); - this->addNodes(&wifiMenu, text_table1[33], TFTPURPLE, GENERAL_APPS, [this]() { - this->changeMenu(&wifiGeneralMenu, true); - }); - - // Build WiFi scanner Menu - wifiScannerMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent - this->addNodes(&wifiScannerMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiScannerMenu.parentMenu, true); - }); - this->addNodes(&wifiScannerMenu, "Ping Scan", TFTGREEN, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_PING_SCAN, TFT_CYAN); - }); - #ifndef HAS_DUAL_BAND - this->addNodes(&wifiScannerMenu, "ARP Scan", TFTCYAN, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ARP_SCAN, TFT_CYAN); - }); - #endif - this->addNodes(&wifiScannerMenu, "Port Scan All", TFTMAGENTA, BEACON_LIST, [this](){ - // Add the back button - wifiIPMenu.list->clear(); - this->addNodes(&wifiIPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiIPMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < ipList->size(); i++) { - // This is the menu node - this->addNodes(&wifiIPMenu, ipList->get(i).toString().c_str(), TFTBLUE, 255, [this, i](){ - Serial.println("Selected: " + ipList->get(i).toString()); - wifi_scan_obj.current_scan_ip = ipList->get(i); - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_PORT_SCAN_ALL, TFT_BLUE); - }); - } - this->changeMenu(&wifiIPMenu, true); - }); - this->addNodes(&wifiScannerMenu, "SSH Scan", TFTORANGE, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_SSH, TFT_CYAN); - }); - this->addNodes(&wifiScannerMenu, "Telnet Scan", TFTRED, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_TELNET, TFT_CYAN); - }); - this->addNodes(&wifiScannerMenu, "SMTP Scan", TFTWHITE, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_SMTP, TFT_CYAN); - }); - this->addNodes(&wifiScannerMenu, "DNS Scan", TFTLIME, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_DNS, TFT_CYAN); - }); - this->addNodes(&wifiScannerMenu, "HTTP Scan", TFTSKYBLUE, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_HTTP, TFT_CYAN); - }); - this->addNodes(&wifiScannerMenu, "HTTPS Scan", TFTYELLOW, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_HTTPS, TFT_CYAN); - }); - this->addNodes(&wifiScannerMenu, "RDP Scan", TFTPURPLE, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_RDP, TFT_CYAN); - }); - - // Build WiFi sniffer Menu - wifiSnifferMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent - this->addNodes(&wifiSnifferMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiSnifferMenu.parentMenu, true); - }); - this->addNodes(&wifiSnifferMenu, text_table1[42], TFTCYAN, PROBE_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_PROBE, TFT_CYAN); - }); - this->addNodes(&wifiSnifferMenu, text_table1[43], TFTMAGENTA, BEACON_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_AP, TFT_MAGENTA); - }); - this->addNodes(&wifiSnifferMenu, text_table1[44], TFTRED, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_DEAUTH, TFT_RED); - }); - this->addNodes(&wifiSnifferMenu, "Packet Count", TFTORANGE, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_PACKET_RATE, TFT_ORANGE); - wifi_scan_obj.renderPacketRate(); - }); - #ifdef HAS_ILI9341 - this->addNodes(&wifiSnifferMenu, text_table1[46], TFTVIOLET, EAPOL, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET); - }); - this->addNodes(&wifiSnifferMenu, text_table1[45], TFTBLUE, PACKET_MONITOR, [this]() { - wifi_scan_obj.StartScan(WIFI_PACKET_MONITOR, TFT_BLUE); - }); - #else // No touch - this->addNodes(&wifiSnifferMenu, text_table1[46], TFTVIOLET, EAPOL, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET); - }); - this->addNodes(&wifiSnifferMenu, text_table1[45], TFTBLUE, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_PACKET_MONITOR, TFT_BLUE); - }); - #endif - this->addNodes(&wifiSnifferMenu, "Channel Analyzer", TFTCYAN, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - this->renderGraphUI(WIFI_SCAN_CHAN_ANALYZER); - wifi_scan_obj.StartScan(WIFI_SCAN_CHAN_ANALYZER, TFT_CYAN); - }); - this->addNodes(&wifiSnifferMenu, "Channel Summary", TFTORANGE, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - this->renderGraphUI(WIFI_SCAN_CHAN_ACT); - wifi_scan_obj.StartScan(WIFI_SCAN_CHAN_ACT, TFT_CYAN); - }); - - this->addNodes(&wifiSnifferMenu, text_table1[58], TFTWHITE, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_RAW_CAPTURE, TFT_WHITE); - }); - - this->addNodes(&wifiSnifferMenu, text_table1[47], TFTRED, PWNAGOTCHI, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_PWN, TFT_RED); - }); - - this->addNodes(&wifiSnifferMenu, text_table1[63], TFTYELLOW, PINESCAN_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_PINESCAN, TFT_YELLOW); - }); - - this->addNodes(&wifiSnifferMenu, text_table1[64], TFTORANGE, MULTISSID_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_MULTISSID, TFT_ORANGE); - }); - this->addNodes(&wifiSnifferMenu, "Scan AP/STA", TFTLIME, BEACON_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_AP_STA, 0x97e0); - }); - /*this->addNodes(&wifiSnifferMenu, "Fox Hunt", TFTCYAN, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_SIG_STREN, TFT_CYAN); - });*/ - this->addNodes(&wifiSnifferMenu, "Fox Hunt", TFTCYAN, SCANNERS, [this]() { - this->buildWiFiFoxHuntMenu(); - }); - this->addNodes(&wifiSnifferMenu, "MAC Monitor", TFTMAGENTA, SCANNERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_DETECT_FOLLOW, TFT_MAGENTA); - }); - this->addNodes(&wifiSnifferMenu, "SAE Commit", TFTLIME, EAPOL, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_SAE_COMMIT, TFT_GREEN); - }); - - // Build Wardriving menu - #ifdef HAS_GPS - /*wardrivingMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent - this->addNodes(&wardrivingMenu, text09, TFTLIGHTGREY, NULL, 0, [this]() { - this->changeMenu(wardrivingMenu.parentMenu, true); - });*/ - if (gps_obj.getGpsModuleStatus()) { - this->addNodes(&wifiSnifferMenu, "Wardrive", TFTGREEN, BEACON_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_WAR_DRIVE, TFT_GREEN); - }); - } - #endif - /*#ifdef HAS_GPS - if (gps_obj.getGpsModuleStatus()) { - this->addNodes(&wardrivingMenu, "Station Wardrive", TFTORANGE, NULL, PROBE_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_STATION_WAR_DRIVE, TFT_ORANGE); - }); - } - #endif*/ - - // Build WiFi attack menu - wifiAttackMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent - this->addNodes(&wifiAttackMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAttackMenu.parentMenu, true); - }); - this->addNodes(&wifiAttackMenu, text_table1[50], TFTRED, BEACON_LIST, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_LIST, TFT_RED); - }); - this->addNodes(&wifiAttackMenu, text_table1[51], TFTORANGE, BEACON_SPAM, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_SPAM, TFT_ORANGE); - }); - this->addNodes(&wifiAttackMenu, text1_67, TFTCYAN, FUNNY_BEACON, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_FUNNY_BEACON, TFT_CYAN); - }); - this->addNodes(&wifiAttackMenu, text_table1[52], TFTYELLOW, RICK_ROLL, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_RICK_ROLL, TFT_YELLOW); - }); - this->addNodes(&wifiAttackMenu, text_table1[53], TFTRED, PROBE_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_AUTH, TFT_RED); - }); - this->addNodes(&wifiAttackMenu, "Evil Portal", TFTORANGE, BEACON_SNIFF, [this]() { - - wifiAPMenu.list->clear(); - ssidsMenu.list->clear(); - - wifiAPMenu.parentMenu = &evilPortalMenu; - ssidsMenu.parentMenu = &evilPortalMenu; - - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - this->addNodes(&ssidsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(ssidsMenu.parentMenu, true); - }); - - // Get AP list ready - for (int i = 0; i < access_points->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - if (evil_portal_obj.setAP(access_points->get(i).essid)) { - AccessPoint new_ap = access_points->get(i); - new_ap.selected = true; - access_points->set(i, new_ap); - - evil_portal_obj.ap_index = i; - - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE); - wifi_scan_obj.setMac(); - } - else - this->changeMenu(&evilPortalMenu, true); - }); - } - - for (int i = 0; i < ssids->size(); i++) { - // This is the menu node - this->addNodes(&ssidsMenu, ssids->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - if (evil_portal_obj.setAP(ssids->get(i).essid)) { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE); - wifi_scan_obj.setMac(); - } - else - this->changeMenu(&evilPortalMenu, true); - }); - } - this->changeMenu(&evilPortalMenu, true); - }); - this->addNodes(&wifiAttackMenu, text_table1[54], TFTRED, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH, TFT_RED); - }); - this->addNodes(&wifiAttackMenu, text_table1[57], TFTMAGENTA, BEACON_LIST, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_AP_SPAM, TFT_MAGENTA); - }); - this->addNodes(&wifiAttackMenu, text_table1[62], TFTRED, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH_TARGETED, TFT_ORANGE); - }); - - this->addNodes(&wifiAttackMenu, "Karma", TFTORANGE, KEYBOARD_ICO, [this](){ - // Add the back button - selectProbeSSIDsMenu.list->clear(); - this->addNodes(&selectProbeSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(&wifiAttackMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < probe_req_ssids->size(); i++) { - // This is the menu node - this->addNodes(&selectProbeSSIDsMenu, probe_req_ssids->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - if (evil_portal_obj.setAP(probe_req_ssids->get(i).essid)) { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE); - wifi_scan_obj.setMac(); - } - else - this->changeMenu(&wifiAttackMenu, true); - }); - } - this->changeMenu(&selectProbeSSIDsMenu, true); - }); - - this->addNodes(&wifiAttackMenu, "Bad Msg", TFTRED, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_BAD_MSG, TFT_RED); - }); - this->addNodes(&wifiAttackMenu, "Bad Msg Targeted", TFTYELLOW, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_BAD_MSG_TARGETED, TFT_YELLOW); - }); - this->addNodes(&wifiAttackMenu, "Assoc Sleep", TFTRED, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_SLEEP, TFT_RED); - }); - this->addNodes(&wifiAttackMenu, "Assoc Sleep Targ", TFTMAGENTA, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_SLEEP_TARGETED, TFT_MAGENTA); - }); - this->addNodes(&wifiAttackMenu, "SAE Commit Flood", TFTLIME, EAPOL, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_SAE_COMMIT, TFT_GREEN); - }); - this->addNodes(&wifiAttackMenu, "Channel Switch", TFTORANGE, BEACON_LIST, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_CSA, TFT_GREEN); - }); - this->addNodes(&wifiAttackMenu, "Quiet Time", TFTRED, BEACON_LIST, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_ATTACK_QUIET, TFT_GREEN); - }); - - evilPortalMenu.parentMenu = &wifiAttackMenu; - this->addNodes(&evilPortalMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(evilPortalMenu.parentMenu, true); - }); - this->addNodes(&evilPortalMenu, "Access Points", TFTGREEN, BEACON_SNIFF, [this]() { - this->changeMenu(&wifiAPMenu, true); - }); - this->addNodes(&evilPortalMenu, "User SSIDs", TFTCYAN, PROBE_SNIFF, [this]() { - this->changeMenu(&ssidsMenu, true); - }); - - // Build WiFi General menu - wifiGeneralMenu.parentMenu = &wifiMenu; - this->addNodes(&wifiGeneralMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiGeneralMenu.parentMenu, true); - }); - this->addNodes(&wifiGeneralMenu, text_table1[27], TFTSKYBLUE, GENERATE, [this]() { - this->changeMenu(&generateSSIDsMenu, true); - wifi_scan_obj.RunGenerateSSIDs(); - }); - - //Add Select probe ssid - this->addNodes(&wifiGeneralMenu, text_table1[65], TFTCYAN, KEYBOARD_ICO, [this]() { - selectProbeSSIDsMenu.list->clear(); - - // Add the back button - this->addNodes(&selectProbeSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(&wifiGeneralMenu, true); - - // TODO: TBD - Should probe_req_ssids have it´s own life and override ap.config and/or ssids -list for EP? - // If so, then we should not add selected ssids to ssids list - - // Add selected ssid names to ssids list when clicking back button - if (probe_req_ssids->size() > 0) { - - //TODO: TBD - Clear ssids list before adding new ones?? - - for (int i = 0; i < probe_req_ssids->size(); i++) { - ProbeReqSsid cur_probe_ssid = probe_req_ssids->get(i); - if (cur_probe_ssid.selected) { - bool ssidExists = false; - for (int i = 0; i < ssids->size(); i++) { - if (ssids->get(i).essid == cur_probe_ssid.essid) { - ssidExists = true; - break; - } - } - if (!ssidExists) { - wifi_scan_obj.addSSID(cur_probe_ssid.essid); - } - } - } - } - }); - - // Populate the menu with buttons - for (int i = 0; i < probe_req_ssids->size(); i++) { - ProbeReqSsid cur_ssid = probe_req_ssids->get(i); - // This is the menu node - String button_name = "[" + String(cur_ssid.requests) + "]" + cur_ssid.essid; - this->addNodes( - &selectProbeSSIDsMenu, - button_name.c_str(), - TFTCYAN, - 255, - [this, i]() { - ProbeReqSsid new_ssid = probe_req_ssids->get(i); - new_ssid.selected = !probe_req_ssids->get(i).selected; - - // Change selection status of menu node - MenuNode new_node = current_menu->list->get(i + 1); - new_node.selected = !current_menu->list->get(i + 1).selected; - current_menu->list->set(i + 1, new_node); - - probe_req_ssids->set(i, new_ssid); - }, - probe_req_ssids->get(i).selected); - } - this->changeMenu(&selectProbeSSIDsMenu, true); - }); - - clearSSIDsMenu.parentMenu = &wifiGeneralMenu; - - #ifdef HAS_ILI9341 - this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, KEYBOARD_ICO, [this](){ - char ssidBuf[64] = {0}; - bool keep_going = true; - while (keep_going) { - display_obj.clearScreen(); - if (keyboardInput(ssidBuf, sizeof(ssidBuf), "Enter SSID")) { - if (ssidBuf[0] != 0) - wifi_scan_obj.addSSID(String(ssidBuf)); - for (int i = 0; i < 64; i++) - ssidBuf[i] = NULL; - } - else - keep_going = false; - } - - this->changeMenu(current_menu); - }); - #endif - #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) - this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, KEYBOARD_ICO, [this](){ - this->changeMenu(&miniKbMenu, true); - #ifdef HAS_MINI_KB - this->miniKeyboard(&miniKbMenu); - #endif - }); - #endif - this->addNodes(&wifiGeneralMenu, text_table1[28], TFTSILVER, CLEAR_ICO, [this]() { - this->changeMenu(&clearSSIDsMenu, true); - wifi_scan_obj.RunClearSSIDs(); - }); - this->addNodes(&wifiGeneralMenu, text_table1[29], TFTDARKGREY, CLEAR_ICO, [this]() { - this->changeMenu(&clearAPsMenu, true); - wifi_scan_obj.RunClearAPs(); - }); - this->addNodes(&wifiGeneralMenu, text_table1[60], TFTBLUE, CLEAR_ICO, [this]() { - this->changeMenu(&clearAPsMenu, true); - wifi_scan_obj.RunClearStations(); - }); - //#else // Mini EP HTML select - this->addNodes(&wifiGeneralMenu, "Select EP HTML File", TFTCYAN, KEYBOARD_ICO, [this](){ - // Add the back button - htmlMenu.list->clear(); - this->addNodes(&htmlMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(htmlMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < evil_portal_obj.html_files->size(); i++) { - // This is the menu node - this->addNodes(&htmlMenu, evil_portal_obj.html_files->get(i).c_str(), TFTCYAN, 255, [this, i](){ - evil_portal_obj.selected_html_index = i; - evil_portal_obj.target_html_name = evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index); - Serial.println("Set Evil Portal HTML as " + evil_portal_obj.target_html_name); - evil_portal_obj.using_serial_html = false; - this->changeMenu(htmlMenu.parentMenu, true); - return; - }); - } - this->changeMenu(&htmlMenu, true); - }); - - //#if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) - miniKbMenu.parentMenu = &wifiGeneralMenu; - #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - this->addNodes(&miniKbMenu, "a", TFTCYAN, 0, [this]() { - this->changeMenu(miniKbMenu.parentMenu, true); - }); - #endif - //#endif - - htmlMenu.parentMenu = &wifiGeneralMenu; - this->addNodes(&htmlMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(htmlMenu.parentMenu, true); - }); - - // Select APs on Mini - this->addNodes(&wifiGeneralMenu, "Select APs", TFTNAVY, KEYBOARD_ICO, [this](){ - wifiAPMenu.parentMenu = &wifiGeneralMenu; - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - this->addNodes(&wifiAPMenu, "Select ALL", TFTGREEN, 255, [this](){ - - for (int x = 0; x < access_points->size(); x++) { - AccessPoint new_ap = access_points->get(x); - new_ap.selected = !access_points->get(x).selected; - access_points->set(x, new_ap); - - MenuNode new_node = current_menu->list->get(x + 2); - new_node.selected = !current_menu->list->get(x + 2).selected; - current_menu->list->set(x + 2, new_node); - } - - this->changeMenu(current_menu, true); - - }); - - // Populate the menu with buttons - for (int i = 0; i < access_points->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - AccessPoint new_ap = access_points->get(i); - new_ap.selected = !access_points->get(i).selected; - - // Change selection status of menu node - MenuNode new_node = current_menu->list->get(i + 2); - new_node.selected = !current_menu->list->get(i + 2).selected; - current_menu->list->set(i + 2, new_node); - - access_points->set(i, new_ap); - }, access_points->get(i).selected); - } - this->changeMenu(&wifiAPMenu, true); - }); - - this->addNodes(&wifiGeneralMenu, "View AP Info", TFTCYAN, KEYBOARD_ICO, [this](){ - wifiAPMenu.parentMenu = &wifiGeneralMenu; - - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < access_points->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - this->changeMenu(&apInfoMenu, true); - wifi_scan_obj.RunAPInfo(i); - }); - } - this->changeMenu(&wifiAPMenu, true); - }); - - apInfoMenu.parentMenu = &wifiAPMenu; - this->addNodes(&apInfoMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(apInfoMenu.parentMenu, true); - }); - - wifiAPMenu.parentMenu = &wifiGeneralMenu; - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - wifiIPMenu.parentMenu = &wifiScannerMenu; - this->addNodes(&wifiIPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiIPMenu.parentMenu, true); - }); - - - // Select Stations on Mini v2 - this->addNodes(&wifiGeneralMenu, "Select Stations", TFTCYAN, KEYBOARD_ICO, [this](){ - wifiAPMenu.parentMenu = &wifiGeneralMenu; - - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - int menu_limit = access_points->size(); - - - for (int i = 0; i < menu_limit; i++) { - wifiStationMenu.list->clear(); - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - - wifiStationMenu.list->clear(); - - wifiStationMenu.parentMenu = &wifiAPMenu; - - // Add back button to the APs - this->addNodes(&wifiStationMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiStationMenu.parentMenu, true); - }); - - this->addNodes(&wifiStationMenu, "Select ALL", TFTGREEN, 255, [this, i](){ - - for (int y = 0; y < access_points->get(i).stations->size(); y++) { - int cur_ap_sta_inx = access_points->get(i).stations->get(y); - Station new_sta = stations->get(cur_ap_sta_inx); - new_sta.selected = !stations->get(cur_ap_sta_inx).selected; - - // Change selection status of menu node - MenuNode new_node = current_menu->list->get(y + 2); - new_node.selected = !current_menu->list->get(y + 2).selected; - current_menu->list->set(y + 2, new_node); - - stations->set(cur_ap_sta_inx, new_sta); - } - - this->changeMenu(current_menu, true); - - }); - - // Add the AP's stations to the specific AP menu - for (int x = 0; x < access_points->get(i).stations->size(); x++) { - int cur_ap_sta = access_points->get(i).stations->get(x); - - this->addNodes(&wifiStationMenu, macToString(stations->get(cur_ap_sta)).c_str(), TFTCYAN, 255, [this, i, cur_ap_sta, x](){ - Station new_sta = stations->get(cur_ap_sta); - new_sta.selected = !stations->get(cur_ap_sta).selected; - - // Change selection status of menu node - MenuNode new_node = current_menu->list->get(x + 2); - new_node.selected = !current_menu->list->get(x + 2).selected; - current_menu->list->set(x + 2, new_node); - - stations->set(cur_ap_sta, new_sta); - }, stations->get(cur_ap_sta).selected); - } - - // Final change menu to the menu of Stations - this->changeMenu(&wifiStationMenu, true); - - }, false); - } - this->changeMenu(&wifiAPMenu, true); - }); - - this->addNodes(&wifiGeneralMenu, "Join WiFi", TFTWHITE, KEYBOARD_ICO, [this](){ - - wifiAPMenu.parentMenu = &wifiGeneralMenu; - - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < access_points->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - // Join WiFi using mini keyboard - #ifdef HAS_MINI_KB - this->changeMenu(&miniKbMenu, true); - String password = this->miniKeyboard(&miniKbMenu, true); - if (password != "") { - Serial.println("Using SSID: " + (String)access_points->get(i).essid + " Password: " + (String)password); - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; - wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - wifi_scan_obj.joinWiFi(access_points->get(i).essid, password); - this->changeMenu(current_menu, true); - } - #endif - - // Join WiFi using touch screen keyboard - #ifdef HAS_TOUCH - char passwordBuf[64] = {0}; // or prefill with existing SSID - if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { - wifi_scan_obj.joinWiFi(access_points->get(i).essid, String(passwordBuf), true); - } - - this->changeMenu(&wifiGeneralMenu, true); - #endif - }); - } - this->changeMenu(&wifiAPMenu, true); - }); - - this->addNodes(&wifiGeneralMenu, "Join Saved WiFi", TFTWHITE, KEYBOARD_ICO, [this](){ - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - if ((ssid != "") && (pw != "")) { - wifi_scan_obj.joinWiFi(ssid, pw, false); - this->changeMenu(&wifiGeneralMenu, true); - } - else { - wifiAPMenu.parentMenu = &wifiGeneralMenu; - - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < access_points->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - // Join WiFi using mini keyboard - #ifdef HAS_MINI_KB - this->changeMenu(&miniKbMenu, true); - String password = this->miniKeyboard(&miniKbMenu, true); - if (password != "") { - Serial.println("Using SSID: " + (String)access_points->get(i).essid + " Password: " + (String)password); - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; - wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - wifi_scan_obj.joinWiFi(access_points->get(i).essid, password); - this->changeMenu(current_menu, true); - } - #endif - - // Join WiFi using touch screen keyboard - #ifdef HAS_TOUCH - char passwordBuf[64] = {0}; // or prefill with existing SSID - if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { - wifi_scan_obj.joinWiFi(access_points->get(i).essid, String(passwordBuf), true); - } - - this->changeMenu(&wifiGeneralMenu, true); - #endif - }); - } - this->changeMenu(&wifiAPMenu, true); - } - }); - - this->addNodes(&wifiGeneralMenu, "Start AP", TFTGREEN, KEYBOARD_ICO, [this](){ - ssidsMenu.parentMenu = &wifiGeneralMenu; - - // Add the back button - ssidsMenu.list->clear(); - this->addNodes(&ssidsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(ssidsMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < ssids->size(); i++) { - // This is the menu node - this->addNodes(&ssidsMenu, ssids->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ - // Join WiFi using mini keyboard - #ifdef HAS_MINI_KB - this->changeMenu(&miniKbMenu, true); - String password = this->miniKeyboard(&miniKbMenu, true); - if (password != "") { - Serial.println("Using SSID: " + (String)ssids->get(i).essid + " Password: " + (String)password); - wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; - wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); - wifi_scan_obj.startWiFi(ssids->get(i).essid, password); - this->changeMenu(current_menu, true); - } - #endif - - // Join WiFi using touch screen keyboard - #ifdef HAS_TOUCH - char passwordBuf[64] = {0}; // or prefill with existing SSID - if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { - Serial.println("Using SSID: " + (String)ssids->get(i).essid + " Password: " + String(passwordBuf)); - wifi_scan_obj.startWiFi(ssids->get(i).essid, String(passwordBuf)); - } - - this->changeMenu(&wifiGeneralMenu, false); - #endif - }); - } - this->changeMenu(&ssidsMenu, true); - }); - - this->addNodes(&wifiGeneralMenu, "Host AP Info", TFTGREEN, BEACON_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(WIFI_SCAN_DISPLAY_AP_INFO, TFT_GREEN); - }); - - wifiStationMenu.parentMenu = &ssidsMenu; - this->addNodes(&wifiStationMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiStationMenu.parentMenu, true); - }); - - this->addNodes(&wifiGeneralMenu, "Set MACs", TFTLIGHTGREY, 0, [this]() { - this->changeMenu(&setMacMenu, true); - }); - - this->addNodes(&wifiGeneralMenu, "Shutdown WiFi", TFTRED, 0, [this]() { - WiFi.softAPdisconnect(true); // Also shut down the SoftAP if it is running - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - this->changeMenu(current_menu, true); - }); - - #ifdef HAS_DIRECT_UPLOAD - this->addNodes(&wifiGeneralMenu, "Upload Wardrive Logs", TFTGREEN, 0, [this]() { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(false); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.println("Loading..."); - - this->buildUploadFileMenu(); - - this->changeMenu(&uploadLogsMenu, true); - }); - - uploadAllMenu.parentMenu = &uploadLogsMenu; - this->addNodes(&uploadAllMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(uploadAllMenu.parentMenu, true); - }); - this->addNodes(&uploadAllMenu, "WiGLE", TFTLIGHTGREY, 0, [this]() { - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - if ((ssid == "") && (pw == "")) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("WiFi Credentials Empty."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - display_obj.clearScreen(); - display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); - if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("Could not connect to WiFi."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - delay(1000); - for (int i = 0; i < sd_obj.sd_files->size(); i++) { - if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { - if (!sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { - Serial.println("Uploading " + sd_obj.sd_files->get(i) + "..."); - if (wifi_scan_obj.uploadFile("/" + sd_obj.sd_files->get(i), true, WIGLE_UPLOAD)) { - display_obj.clearScreen(); - display_obj.showCenterText("WiGLE OK", TFT_HEIGHT / 2); - } else { - display_obj.clearScreen(); - display_obj.showCenterText("WiGLE failed", TFT_HEIGHT / 2); - } - } - } - } - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - } - } - - delay(2000); - - this->changeMenu(uploadAllMenu.parentMenu, true); - }); - this->addNodes(&uploadAllMenu, "WDGWars", TFTLIGHTGREY, 0, [this]() { - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - - if ((ssid == "") && (pw == "")) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("WiFi Credentials Empty."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - display_obj.clearScreen(); - display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); - if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("Could not connect to WiFi."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - delay(1000); - for (int i = 0; i < sd_obj.sd_files->size(); i++) { - if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { - if (!sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { - Serial.println("Uploading " + sd_obj.sd_files->get(i) + "..."); - if (wifi_scan_obj.uploadFile("/" + sd_obj.sd_files->get(i), true, WDG_UPLOAD)) { - display_obj.clearScreen(); - display_obj.showCenterText("WDG OK", TFT_HEIGHT / 2); - } else { - display_obj.clearScreen(); - display_obj.showCenterText("WDG failed", TFT_HEIGHT / 2); - } - } - } - } - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - } - } - - delay(2000); - - this->changeMenu(uploadAllMenu.parentMenu, true); - }); - this->addNodes(&uploadAllMenu, "Both", TFTLIGHTGREY, 0, [this]() { - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - - if ((ssid == "") && (pw == "")) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("WiFi Credentials Empty."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - display_obj.clearScreen(); - display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); - if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("Could not connect to WiFi."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - delay(1000); - for (int i = 0; i < sd_obj.sd_files->size(); i++) { - if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { - if (!sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { - Serial.println("Uploading " + sd_obj.sd_files->get(i) + "..."); - if (wifi_scan_obj.uploadFile("/" + sd_obj.sd_files->get(i), true, BOTH_UPLOAD)) { - display_obj.clearScreen(); - display_obj.showCenterText("Upload OK", TFT_HEIGHT / 2); - } else { - display_obj.clearScreen(); - display_obj.showCenterText("Upload failed", TFT_HEIGHT / 2); - } - } - } - } - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - } - } - - delay(2000); - - this->changeMenu(uploadAllMenu.parentMenu, true); - }); - - deleteAllMenu.parentMenu = &uploadLogsMenu; - this->addNodes(&deleteAllMenu, "No", TFTLIGHTGREY, 0, [this]() { - this->changeMenu(deleteAllMenu.parentMenu, true); - }); - this->addNodes(&deleteAllMenu, "Yes", TFTRED, 0, [this]() { - display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK); - - display_obj.clearScreen(); - - display_obj.showCenterText("Deleting logs...", TFT_HEIGHT / 2, true); - - for (int i = 0; i < sd_obj.sd_files->size(); i++) { - if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { - if (sd_obj.removeFile("/" + sd_obj.sd_files->get(i))) { - Serial.println("Removed file: " + sd_obj.sd_files->get(i)); - sd_obj.removeFile("/" + sd_obj.sd_files->get(i) + ".wdg"); - sd_obj.removeFile("/" + sd_obj.sd_files->get(i) + ".wigle"); - } - else { - Serial.println("Could not remove file: " + sd_obj.sd_files->get(i)); - } - } - } - display_obj.clearScreen(); - - display_obj.showCenterText("Logs removed", TFT_HEIGHT / 2, true); - - delay(2000); - - this->buildUploadFileMenu(); - - this->changeMenu(&uploadLogsMenu, true); - }); - - actionMenu.parentMenu = &uploadLogsMenu; - this->addNodes(&actionMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(actionMenu.parentMenu, true); - }); - this->addNodes(&actionMenu, "WiGLE", TFTLIGHTGREY, 0, [this]() { - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - - if ((ssid == "") && (pw == "")) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("WiFi Credentials Empty."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - display_obj.clearScreen(); - display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); - if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.println("Could not connect to WiFi."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - delay(1000); - Serial.println("Uploading " + sd_obj.selected_file_name + "..."); - if (wifi_scan_obj.uploadFile("/" + sd_obj.selected_file_name, true, WIGLE_UPLOAD)) { - display_obj.clearScreen(); - display_obj.showCenterText("WiGLE OK", TFT_HEIGHT / 2, true); - } else { - display_obj.clearScreen(); - display_obj.showCenterText("WiGLE failed", TFT_HEIGHT / 2, true); - } - - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - } - } - - delay(2000); - - this->changeMenu(&actionMenu, true); - }); - this->addNodes(&actionMenu, "WDGWars", TFTLIGHTGREY, 0, [this]() { - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - - if ((ssid == "") && (pw == "")) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("WiFi Credentials Empty."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - display_obj.clearScreen(); - display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); - if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("Could not connect to WiFi."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - delay(1000); - Serial.println("Uploading " + sd_obj.selected_file_name + "..."); - if (wifi_scan_obj.uploadFile("/" + sd_obj.selected_file_name, true, WDG_UPLOAD)) { - display_obj.clearScreen(); - display_obj.showCenterText("WDG OK", TFT_HEIGHT / 2, true); - } else { - display_obj.clearScreen(); - display_obj.showCenterText("WDG failed", TFT_HEIGHT / 2, true); - } - - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - } - } - - delay(2000); - - this->changeMenu(&actionMenu, true); - }); - this->addNodes(&actionMenu, "Both", TFTLIGHTGREY, 0, [this]() { - String ssid = settings_obj.loadSetting("ClientSSID"); - String pw = settings_obj.loadSetting("ClientPW"); - - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - - if ((ssid == "") && (pw == "")) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("WiFi Credentials Empty."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - display_obj.clearScreen(); - display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); - if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(true); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.println("Could not connect to WiFi."); - display_obj.tft.println("Returning..."); - display_obj.tft.setTextWrap(false); - } - else { - delay(1000); - Serial.println("Uploading " + sd_obj.selected_file_name + "..."); - if (wifi_scan_obj.uploadFile("/" + sd_obj.selected_file_name, true, BOTH_UPLOAD)) { - display_obj.clearScreen(); - display_obj.showCenterText("Upload OK", TFT_HEIGHT / 2, true); - } else { - display_obj.clearScreen(); - display_obj.showCenterText("Upload failed", TFT_HEIGHT / 2, true); - } - - WiFi.disconnect(true); - delay(100); - wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); - } - } - - delay(2000); - - this->changeMenu(&actionMenu, true); - }); - #endif - - - // Menu for generating and setting MAC addrs for AP and STA - setMacMenu.parentMenu = &wifiGeneralMenu; - this->addNodes(&setMacMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(setMacMenu.parentMenu, true); - }); - - // Generate random MAC for AP - this->addNodes(&setMacMenu, "Generate AP MAC", TFTLIME, 0, [this]() { - this->changeMenu(&genAPMacMenu, true); - wifi_scan_obj.RunGenerateRandomMac(true); - }); - - // Generate random MAC for AP - this->addNodes(&setMacMenu, "Generate STA MAC", TFTCYAN, 0, [this]() { - this->changeMenu(&genAPMacMenu, true); - wifi_scan_obj.RunGenerateRandomMac(false); - }); - - // Clone AP MAC to ESP32 for button folks - //#ifndef HAS_ILI9341 - this->addNodes(&setMacMenu, "Clone AP MAC", TFTRED, CLEAR_ICO, [this](){ - wifiAPMenu.parentMenu = &wifiGeneralMenu; - - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < access_points->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTLIME, 255, [this, i](){ - this->changeMenu(&genAPMacMenu, true); - wifi_scan_obj.RunSetMac(access_points->get(i).bssid, true); - }); - } - this->changeMenu(&wifiAPMenu, true); - }); - - this->addNodes(&setMacMenu, "Clone STA MAC", TFTMAGENTA, CLEAR_ICO, [this](){ - wifiAPMenu.parentMenu = &wifiGeneralMenu; - - // Add the back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - // Populate the menu with buttons - for (int i = 0; i < stations->size(); i++) { - // This is the menu node - this->addNodes(&wifiAPMenu, macToString(stations->get(i).mac).c_str(), TFTMAGENTA, 255, [this, i](){ - this->changeMenu(&genAPMacMenu, true); - wifi_scan_obj.RunSetMac(stations->get(i).mac, false); - }); - } - this->changeMenu(&wifiAPMenu, true); - }); - //#endif - - // Menu for generating and setting access point MAC (just goes bacK) - genAPMacMenu.parentMenu = &wifiGeneralMenu; - this->addNodes(&genAPMacMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(genAPMacMenu.parentMenu, true); - }); - - // Build generate ssids menu - generateSSIDsMenu.parentMenu = &wifiGeneralMenu; - this->addNodes(&generateSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(generateSSIDsMenu.parentMenu, true); - }); - - // Build clear ssids menu - - this->addNodes(&clearSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(clearSSIDsMenu.parentMenu, true); - }); - clearAPsMenu.parentMenu = &wifiGeneralMenu; - this->addNodes(&clearAPsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(clearAPsMenu.parentMenu, true); - }); - -#ifdef HAS_BT - // Build Bluetooth Menu - bluetoothMenu.parentMenu = &mainMenu; // Second Menu is third menu parent - this->addNodes(&bluetoothMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(bluetoothMenu.parentMenu, true); - }); - this->addNodes(&bluetoothMenu, text_table1[31], TFTYELLOW, SNIFFERS, [this]() { - this->changeMenu(&bluetoothSnifferMenu, true); - }); - this->addNodes(&bluetoothMenu, "Bluetooth Attacks", TFTRED, ATTACKS, [this]() { - this->changeMenu(&bluetoothAttackMenu, true); - }); - - // Build bluetooth sniffer Menu - bluetoothSnifferMenu.parentMenu = &bluetoothMenu; // Second Menu is third menu parent - this->addNodes(&bluetoothSnifferMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(bluetoothSnifferMenu.parentMenu, true); - }); - this->addNodes(&bluetoothSnifferMenu, text_table1[34], TFTGREEN, BLUETOOTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_ALL, TFT_GREEN); - }); - this->addNodes(&bluetoothSnifferMenu, "Flipper Sniff", TFTORANGE, FLIPPER, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_FLIPPER, TFT_ORANGE); - }); - this->addNodes(&bluetoothSnifferMenu, "FindMy Sniff", TFTWHITE, BLUETOOTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_AIRTAG, TFT_WHITE); - }); - this->addNodes(&bluetoothSnifferMenu, "FindMy Monitor", TFTWHITE, BLUETOOTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_AIRTAG_MON, TFT_WHITE); - }); - this->addNodes(&bluetoothSnifferMenu, text_table1[35], TFTMAGENTA, CC_SKIMMERS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_SKIMMERS, TFT_MAGENTA); - }); - this->addNodes(&bluetoothSnifferMenu, "Bluetooth Analyzer", TFTCYAN, PACKET_MONITOR, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - this->renderGraphUI(BT_SCAN_ANALYZER); - wifi_scan_obj.StartScan(BT_SCAN_ANALYZER, TFT_CYAN); - }); - this->addNodes(&bluetoothSnifferMenu, "Flock Sniff", TFTORANGE, FLOCK, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_FLOCK, TFT_ORANGE); - }); - this->addNodes(&bluetoothSnifferMenu, "Meta Detect", TFTWHITE, BLUETOOTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SCAN_RAYBAN, TFT_CYAN); - }); - this->addNodes(&bluetoothSnifferMenu, "Fox Hunt", TFTCYAN, SCANNERS, [this]() { - this->buildBluetoothFoxHuntMenu(); - }); - - // Bluetooth Attack menu - bluetoothAttackMenu.parentMenu = &bluetoothMenu; // Second Menu is third menu parent - this->addNodes(&bluetoothAttackMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(bluetoothAttackMenu.parentMenu, true); - }); - this->addNodes(&bluetoothAttackMenu, "Sour Apple", TFTGREEN, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_SOUR_APPLE, TFT_GREEN); - }); - this->addNodes(&bluetoothAttackMenu, "Apple Juice", TFTYELLOW, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_APPLE_JUICE, TFT_YELLOW); - }); - this->addNodes(&bluetoothAttackMenu, "Swiftpair Spam", TFTCYAN, KEYBOARD_ICO, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_SWIFTPAIR_SPAM, TFT_CYAN); - }); - this->addNodes(&bluetoothAttackMenu, "Samsung BLE Spam", TFTRED, GENERAL_APPS, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_SAMSUNG_SPAM, TFT_RED); - }); - this->addNodes(&bluetoothAttackMenu, "Google BLE Spam", TFTPURPLE, LANGUAGE, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_GOOGLE_SPAM, TFT_PURPLE); - }); - this->addNodes(&bluetoothAttackMenu, "Flipper BLE Spam", TFTORANGE, FLIPPER, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_FLIPPER_SPAM, TFT_ORANGE); - }); - this->addNodes(&bluetoothAttackMenu, "BLE Spam All", TFTMAGENTA, DEAUTH_SNIFF, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_SPAM_ALL, TFT_MAGENTA); - }); - -#endif - - //#ifndef HAS_ILI9341 - #ifdef HAS_BT - this->addNodes(&bluetoothAttackMenu, "Spoof Airtag", TFTWHITE, ATTACKS, [this](){ - wifiAPMenu.parentMenu = &bluetoothAttackMenu; - - // Clear nodes and add back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - // Add buttons for all airtags - // Find out how big our menu is going to be - int menu_limit; - if (airtags->size() <= BUTTON_ARRAY_LEN) - menu_limit = airtags->size(); - else - menu_limit = BUTTON_ARRAY_LEN; - - // Create the menu nodes for all of the list items - for (int i = 0; i < menu_limit; i++) { - this->addNodes(&wifiAPMenu, airtags->get(i).mac.c_str(), TFTWHITE, BLUETOOTH, [this, i](){ - AirTag new_at = airtags->get(i); - new_at.selected = true; - - airtags->set(i, new_at); - - // Set all other airtags to "Not Selected" - for (int x = 0; x < airtags->size(); x++) { - if (x != i) { - AirTag new_atx = airtags->get(x); - new_atx.selected = false; - airtags->set(x, new_atx); - } - } - - // Start the spoof - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_SPOOF_AIRTAG, TFT_WHITE); - - }); - } - this->changeMenu(&wifiAPMenu, true); - }); - - #ifdef HAS_NIMBLE_2 - this->addNodes(&bluetoothAttackMenu, "FindMy Sound", TFTCYAN, ATTACKS, [this](){ - wifiAPMenu.parentMenu = &bluetoothAttackMenu; - - // Clear nodes and add back button - wifiAPMenu.list->clear(); - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - /*this->addNodes(&wifiAPMenu, "Live", TFTMAGENTA, 0, [this]() { - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.StartScan(BT_ATTACK_FINDMY_LIVE, TFT_RED); - });*/ - - int menu_limit = airtags->size(); - - // Create the menu nodes for all of the list items - for (int i = 0; i < menu_limit; i++) { - uint8_t node_color = rssiToMenuColor(airtags->get(i).rssi); - String node_name = String(airtags->get(i).rssi) + " " + airtags->get(i).mac; - this->addNodes(&wifiAPMenu, node_name.c_str(), node_color, BLUETOOTH, [this, i](){ - AirTag new_at = airtags->get(i); - new_at.selected = true; - new_at.connectable = true; - - airtags->set(i, new_at); - - // Set all other airtags to "Not Selected" - for (int x = 0; x < airtags->size(); x++) { - if (x != i) { - AirTag new_atx = airtags->get(x); - new_atx.selected = false; - airtags->set(x, new_atx); - } - } - - // Start the spoof - display_obj.clearScreen(); - this->drawStatusBar(); - wifi_scan_obj.executeFindMySound(true); - delay(2000); - this->changeMenu(&wifiAPMenu, true); - }); - } - this->changeMenu(&wifiAPMenu, true); - }); - #endif - - wifiAPMenu.parentMenu = &bluetoothAttackMenu; - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - - wifiAPMenu.parentMenu = &bluetoothAttackMenu; - this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(wifiAPMenu.parentMenu, true); - }); - #endif - - //#endif - - // Device menu - deviceMenu.parentMenu = &mainMenu; - this->addNodes(&deviceMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(deviceMenu.parentMenu, true); - }); - - #ifdef HAS_SD - if (sd_obj.supported) { - - sdDeleteMenu.parentMenu = &deviceMenu; - - this->addNodes(&deviceMenu, "Update Firmware", TFTORANGE, SD_UPDATE, [this]() { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(false); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.println("Loading..."); - - // Clear menu and lists - this->buildSDFileMenu(true); - - this->changeMenu(&sdDeleteMenu, true); - }); - } - #endif - - this->addNodes(&deviceMenu, "Save/Load Files", TFTCYAN, SD_UPDATE, [this]() { - this->changeMenu(&saveFileMenu, true); - }); - - #ifndef HAS_MINI_SCREEN - this->addNodes(&deviceMenu, "Brightness", TFTYELLOW, BRIGHTNESS, [this]() { - this->brightnessMode(); - }); - #endif - - this->addNodes(&deviceMenu, text_table1[17], TFTWHITE, DEVICE_INFO, [this]() { - wifi_scan_obj.currentScanMode = SHOW_INFO; - this->changeMenu(&infoMenu, true); - wifi_scan_obj.RunInfo(); - }); - this->addNodes(&deviceMenu, text08, TFTBLUE, SETTINGS, [this]() { - this->changeMenu(&settingsMenu, true); - }); - - #ifdef HAS_SD - if (sd_obj.supported) { - - sdDeleteMenu.parentMenu = &deviceMenu; - - this->addNodes(&deviceMenu, "Delete SD Files", TFTCYAN, SD_UPDATE, [this]() { - display_obj.clearScreen(); - display_obj.tft.setTextWrap(false); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.println("Loading..."); - - // Clear menu and lists - this->buildSDFileMenu(); - - this->changeMenu(&sdDeleteMenu, true); - }); - } - #endif - - // Save Files Menu - saveFileMenu.parentMenu = &deviceMenu; - this->addNodes(&saveFileMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(saveFileMenu.parentMenu, true); - }); - this->addNodes(&saveFileMenu, "Save SSIDs", TFTCYAN, SD_UPDATE, [this]() { - this->changeMenu(&saveSSIDsMenu, true); - wifi_scan_obj.RunSaveSSIDList(true); - }); - this->addNodes(&saveFileMenu, "Load SSIDs", TFTSKYBLUE, SD_UPDATE, [this]() { - this->changeMenu(&loadSSIDsMenu, true); - wifi_scan_obj.RunLoadSSIDList(); - }); - this->addNodes(&saveFileMenu, "Save APs", TFTNAVY, SD_UPDATE, [this]() { - this->changeMenu(&saveAPsMenu, true); - wifi_scan_obj.RunSaveAPList(); - }); - this->addNodes(&saveFileMenu, "Load APs", TFTBLUE, SD_UPDATE, [this]() { - this->changeMenu(&loadAPsMenu, true); - wifi_scan_obj.RunLoadAPList(); - }); - this->addNodes(&saveFileMenu, "Save Airtags", TFTWHITE, SD_UPDATE, [this]() { - this->changeMenu(&saveAPsMenu, true); - wifi_scan_obj.RunSaveATList(); - }); - this->addNodes(&saveFileMenu, "Load Airtags", TFTWHITE, SD_UPDATE, [this]() { - this->changeMenu(&loadAPsMenu, true); - wifi_scan_obj.RunLoadATList(); - }); - - saveSSIDsMenu.parentMenu = &saveFileMenu; - this->addNodes(&saveSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(saveSSIDsMenu.parentMenu, true); - }); - - loadSSIDsMenu.parentMenu = &saveFileMenu; - this->addNodes(&loadSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(loadSSIDsMenu.parentMenu, true); - }); - - saveAPsMenu.parentMenu = &saveFileMenu; - this->addNodes(&saveAPsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(saveAPsMenu.parentMenu, true); - }); - - loadAPsMenu.parentMenu = &saveFileMenu; - this->addNodes(&loadAPsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(loadAPsMenu.parentMenu, true); - }); - - saveATsMenu.parentMenu = &saveFileMenu; - this->addNodes(&saveATsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(saveATsMenu.parentMenu, true); - }); - - loadATsMenu.parentMenu = &saveFileMenu; - this->addNodes(&loadATsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(loadATsMenu.parentMenu, true); - }); - - // GPS Menu - #ifdef HAS_GPS - if (gps_obj.getGpsModuleStatus()) { - gpsMenu.parentMenu = &mainMenu; // Main Menu is second menu parent - - this->addNodes(&gpsMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(gpsMenu.parentMenu, true); - }); - - this->addNodes(&gpsMenu, "GPS Data", TFTRED, GPS_MENU, [this]() { - wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_DATA; - this->changeMenu(&gpsInfoMenu, true); - wifi_scan_obj.StartScan(WIFI_SCAN_GPS_DATA, TFT_CYAN); - }); - - this->addNodes(&gpsMenu, "NMEA Stream", TFTORANGE, GPS_MENU, [this]() { - wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_NMEA; - this->changeMenu(&gpsInfoMenu, true); - wifi_scan_obj.StartScan(WIFI_SCAN_GPS_NMEA, TFT_ORANGE); - }); - - this->addNodes(&gpsMenu, "GPS Tracker", TFTGREEN, GPS_MENU, [this]() { - wifi_scan_obj.currentScanMode = GPS_TRACKER; - this->changeMenu(&gpsInfoMenu, true); - wifi_scan_obj.StartScan(GPS_TRACKER, TFT_CYAN); - }); - - this->addNodes(&gpsMenu, "GPS POI", TFTCYAN, GPS_MENU, [this]() { - wifi_scan_obj.StartScan(GPS_POI, TFT_CYAN); - wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; - this->changeMenu(&gpsPOIMenu, true); - }); - - // GPS POI Menu - gpsPOIMenu.parentMenu = &gpsMenu; - this->addNodes(&gpsPOIMenu, text09, TFTLIGHTGREY, 0, [this]() { - wifi_scan_obj.currentScanMode = GPS_POI; - wifi_scan_obj.StartScan(WIFI_SCAN_OFF); - this->changeMenu(gpsPOIMenu.parentMenu, true); - }); - this->addNodes(&gpsPOIMenu, "Mark POI", TFTCYAN, GPS_MENU, [this]() { - wifi_scan_obj.currentScanMode = GPS_POI; - display_obj.tft.setCursor(0, TFT_HEIGHT / 2); - display_obj.clearScreen(); - if (wifi_scan_obj.RunGPSInfo(true, false, true)) - display_obj.showCenterText("POI Logged", TFT_HEIGHT / 2); - else - display_obj.showCenterText("POI Log Failed", TFT_HEIGHT / 2); - wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; - delay(2000); - this->changeMenu(&gpsPOIMenu, true); - }); - - // GPS Info Menu - gpsInfoMenu.parentMenu = &gpsMenu; - this->addNodes(&gpsInfoMenu, text09, TFTLIGHTGREY, 0, [this]() { - if(wifi_scan_obj.currentScanMode != GPS_TRACKER) - wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; - wifi_scan_obj.StartScan(WIFI_SCAN_OFF); - this->changeMenu(gpsInfoMenu.parentMenu, true); - }); - } - #endif - - // Settings menu - // Device menu - settingsMenu.parentMenu = &deviceMenu; - this->addNodes(&settingsMenu, text09, TFTLIGHTGREY, 0, [this]() { - changeMenu(settingsMenu.parentMenu, true); - }); - for (int i = 0; i < settings_obj.getNumberSettings(); i++) { - String settingName = settings_obj.setting_index_to_name(i); - const char* type = this->callSetting(settingName.c_str()); - if (type && strcmp(type, "bool") == 0) { - this->addNodes(&settingsMenu, settingName.c_str(), TFTLIGHTGREY, SETTINGS, [this, i, settingName]() { - settings_obj.toggleSetting(settingName.c_str()); - this->callSetting(settingName.c_str()); - this->changeMenu(&specSettingMenu, true); - this->displaySetting(settingName.c_str(), &settingsMenu, i + 1); - wifi_scan_obj.force_pmkid = settings_obj.loadSetting(text_table4[5]); - wifi_scan_obj.force_probe = settings_obj.loadSetting(text_table4[6]); - wifi_scan_obj.save_pcap = settings_obj.loadSetting(text_table4[7]); - wifi_scan_obj.ep_deauth = settings_obj.loadSetting("EPDeauth"); - wifi_scan_obj.channel_hop = settings_obj.loadSetting("ChanHop"); - }, settings_obj.loadSetting(settingName.c_str())); - } - } - - Serial.println("Finished settings nodes"); - - // Specific setting menu - specSettingMenu.parentMenu = &settingsMenu; - addNodes(&specSettingMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(specSettingMenu.parentMenu, true); - }); - - // Web Update - updateMenu.parentMenu = &deviceMenu; - - // Failed update menu - failedUpdateMenu.parentMenu = &deviceMenu; - this->addNodes(&failedUpdateMenu, text09, TFTLIGHTGREY, 0, [this]() { - wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; - this->changeMenu(failedUpdateMenu.parentMenu, true); - }); - - // Device info menu - infoMenu.parentMenu = &deviceMenu; - this->addNodes(&infoMenu, text09, TFTLIGHTGREY, 0, [this]() { - wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; - this->changeMenu(infoMenu.parentMenu, true); - }); - - Serial.println("Changing to main menu..."); - - // Set the current menu to the mainMenu - this->changeMenu(&mainMenu, true); - - this->initTime = millis(); -} - -//#if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) -#ifdef HAS_MINI_KB - String MenuFunctions::miniKeyboard(Menu * targetMenu, bool do_pass) { - // Prepare a char array and reset temp SSID string - extern LinkedList* ssids; - - String ret_val = ""; - - bool pressed = true; - - wifi_scan_obj.current_mini_kb_ssid = ""; - - #ifdef HAS_MINI_KB - if (c_btn.isHeld()) { - while (!c_btn.justReleased()) - delay(1); - } - #endif - - int str_len = wifi_scan_obj.alfa.length() + 1; - - char char_array[str_len]; - - wifi_scan_obj.alfa.toCharArray(char_array, str_len); - - #ifdef HAS_TOUCH - uint16_t t_x = 0, t_y = 0; - - #endif - - // Button loop until hold center button - #ifdef HAS_BUTTONS - //#if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1) || defined(MARAUDER_CYD_MICRO)) - while(true) { - // Keyboard functions for switch hardware - #ifdef HAS_MINI_KB - // Cycle char previous - #ifdef HAS_L - if ((l_btn.justPressed()) || (l_btn.isHeld())) { - pressed = true; - if (this->mini_kb_index > 0) - this->mini_kb_index--; - else - this->mini_kb_index = str_len - 2; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu); - - while (!l_btn.justReleased()) { - l_btn.justPressed(); - if (!l_btn.isHeld()) - delay(1); - else - break; - } - } - #endif - - // Cycle char next - #ifdef HAS_R - if ((r_btn.justPressed()) || (r_btn.isHeld())) { - pressed = true; - if (this->mini_kb_index < str_len - 2) - this->mini_kb_index++; - else - this->mini_kb_index = 0; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); - - while (!r_btn.justReleased()) { - r_btn.justPressed(); - if (!r_btn.isHeld()) - delay(1); - else - break; - } - } - #endif - - //// 5-WAY SWITCH STUFF - // Add character - #if (defined(HAS_D) && defined(HAS_R)) - if (d_btn.justPressed()) { - pressed = true; - wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); - while (!d_btn.justReleased()) - delay(1); - } - #endif - - // Remove character - #if (defined(HAS_U) && defined(HAS_L)) - if (u_btn.justPressed()) { - pressed = true; - wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); - while (!u_btn.justReleased()) - delay(1); - } - #endif - - //// PARTIAL SWITCH STUFF - // Advance char or add char - #if (defined(HAS_D) && !defined(HAS_R)) - if (d_btn.justPressed()) { - bool was_held = false; - pressed = true; - while(!d_btn.justReleased()) { - d_btn.justPressed(); - - // Add letter to string - if (d_btn.isHeld()) { - wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); - was_held = true; - break; - } - } - if (!was_held) { - if (this->mini_kb_index < str_len - 2) - this->mini_kb_index++; - else - this->mini_kb_index = 0; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); - } - } - #endif - - // Prev char or remove char - #if (defined(HAS_U) && !defined(HAS_L)) - if (u_btn.justPressed()) { - bool was_held = false; - pressed = true; - while(!u_btn.justReleased()) { - u_btn.justPressed(); - - // Remove letter from string - if (u_btn.isHeld()) { - wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); - was_held = true; - break; - } - } - if (!was_held) { - if (this->mini_kb_index > 0) - this->mini_kb_index--; - else - this->mini_kb_index = str_len - 2; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu); - } - } - #endif - - // Add SSID - #if defined(HAS_C) && !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - if (c_btn.justPressed()) { - while (!c_btn.justReleased()) { - c_btn.justPressed(); // Need to continue updating button hold status. My shitty library. - - // Exit - if (c_btn.isHeld()) { - this->changeMenu(targetMenu->parentMenu); - return wifi_scan_obj.current_mini_kb_ssid; - } - delay(1); - } - - if (!do_pass) { - // If we have a string, add it to list of SSIDs - if (wifi_scan_obj.current_mini_kb_ssid != "") { - pressed = true; - ssid s = {wifi_scan_obj.current_mini_kb_ssid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false}; - ssids->unshift(s); - wifi_scan_obj.current_mini_kb_ssid = ""; - } - } - } - #endif - #endif - - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - for (int i = 0; i < 95; i++) { - if ((M5CardputerKeyboard._ascii_list[i] != '(') && - (M5CardputerKeyboard._ascii_list[i] != '`')) { - if (this->isKeyPressed(M5CardputerKeyboard._ascii_list[i])) { - pressed = true; - wifi_scan_obj.current_mini_kb_ssid.concat(M5CardputerKeyboard._ascii_list[i]); - } - if (this->isKeyPressed(KEY_BACKSPACE)) { - pressed = true; - wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); - } - } - } - - if (!do_pass) { - if (this->isKeyPressed('`')) { - this->changeMenu(targetMenu->parentMenu, true); - return wifi_scan_obj.current_mini_kb_ssid; - } - - if (this->isKeyPressed('(')) { - if (!do_pass) { - if (wifi_scan_obj.current_mini_kb_ssid != "") { - pressed = true; - ssid s = {wifi_scan_obj.current_mini_kb_ssid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false}; - ssids->unshift(s); - wifi_scan_obj.current_mini_kb_ssid = ""; - } - } - } - } - else { - if (this->isKeyPressed('(')) { - this->changeMenu(targetMenu->parentMenu, true); - return wifi_scan_obj.current_mini_kb_ssid; - } - - if (this->isKeyPressed('`')) { - this->changeMenu(targetMenu->parentMenu, true); - return ""; - } - } - - #endif - - // Keyboard functions for touch hardware - #ifdef HAS_TOUCH - bool touched = display_obj.updateTouch(&t_x, &t_y); - - uint8_t menu_button = display_obj.menuButton(&t_x, &t_y, touched); - - // Cycle char previous - if (menu_button == UP_BUTTON) { - pressed = true; - if (this->mini_kb_index > 0) - this->mini_kb_index--; - else - this->mini_kb_index = str_len - 2; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu); - while (display_obj.updateTouch(&t_x, &t_y) > 0) - delay(1); - display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); - } - - // Cycle char next - if (menu_button == DOWN_BUTTON) { - pressed = true; - if (this->mini_kb_index < str_len - 2) - this->mini_kb_index++; - else - this->mini_kb_index = 0; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); - while (display_obj.updateTouch(&t_x, &t_y) > 0) - delay(1); - display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); - } - - //// 5-WAY SWITCH STUFF - // Add character when select button is pressed - if (menu_button == SELECT_BUTTON) { - pressed = true; - wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); - while (display_obj.updateTouch(&t_x, &t_y) > 0) - delay(1); - display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); - } - - // Remove character when select button is held - if ((display_obj.isTouchHeld()) && (display_obj.menuButton(&t_x, &t_y, touched, true) == SELECT_BUTTON)) { - pressed = true; - wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); - while (display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)) < 0) - delay(1); - } - - //// PARTIAL SWITCH STUFF - // Advance char or add char - #if (defined(HAS_D) && !defined(HAS_R)) - if (d_btn.justPressed()) { - bool was_held = false; - pressed = true; - while(!d_btn.justReleased()) { - d_btn.justPressed(); - - // Add letter to string - if (d_btn.isHeld()) { - wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); - was_held = true; - break; - } - } - if (!was_held) { - if (this->mini_kb_index < str_len - 2) - this->mini_kb_index++; - else - this->mini_kb_index = 0; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); - } - } - #endif - - // Prev char or remove char - #if (defined(HAS_U) && !defined(HAS_L)) - if (u_btn.justPressed()) { - bool was_held = false; - pressed = true; - while(!u_btn.justReleased()) { - u_btn.justPressed(); - - // Remove letter from string - if (u_btn.isHeld()) { - wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); - was_held = true; - break; - } - } - if (!was_held) { - if (this->mini_kb_index > 0) - this->mini_kb_index--; - else - this->mini_kb_index = str_len - 2; - - targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); - this->buildButtons(targetMenu); - } - } - #endif - - // Exit if UP button is held - if ((display_obj.isTouchHeld()) && (display_obj.menuButton(&t_x, &t_y, touched, true) == UP_BUTTON)) { - display_obj.clearScreen(); - while (display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)) < 0) - delay(1); - - // Reset the touch keys so we don't activate the keys when we go back - display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); - this->changeMenu(targetMenu->parentMenu, true); - return wifi_scan_obj.current_mini_kb_ssid; - } - - // If the screen is touched but none of the keys are used, don't refresh display - if (menu_button < 0) - pressed = false; - - #endif - - // Display info on screen - if (pressed) { - this->displayCurrentMenu(); - display_obj.tft.setTextWrap(false); - display_obj.tft.fillRect(0, SCREEN_HEIGHT / 3, SCREEN_WIDTH, STATUS_BAR_WIDTH, TFT_BLACK); - display_obj.tft.fillRect(0, SCREEN_HEIGHT / 3 + TEXT_HEIGHT * 2, SCREEN_WIDTH, STATUS_BAR_WIDTH, TFT_BLACK); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.println(wifi_scan_obj.current_mini_kb_ssid + "\n"); - display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); - - display_obj.tft.println(ssids->get(0).essid); - - display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK); - #ifdef HAS_MINI_KB - #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.println("U/D - Rem/Add Char"); - display_obj.tft.println("L/R - Prev/Nxt Char"); - #endif - if (!do_pass) { - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.println("Enter - Save"); - display_obj.tft.println("Esc - Exit"); - #else - display_obj.tft.println("C - Save"); - display_obj.tft.println("C(Hold) - Exit"); - #endif - } - else { - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.println("Enter - Enter"); - #else - display_obj.tft.println("C(Hold) - Enter"); - #endif - } - #endif - - #ifdef HAS_TOUCH - display_obj.tft.println("U/D - Prev/Nxt Char"); - display_obj.tft.println("C - Add Char"); - display_obj.tft.println("C(Hold) - Rem Char"); - display_obj.tft.println("U(Hold) - Enter"); - #endif - pressed = false; - } - } - //#endif - #endif - } -#endif - -void MenuFunctions::setupSDFileList(bool update) { - sd_obj.sd_files->clear(); - - delete sd_obj.sd_files; - - sd_obj.sd_files = new LinkedList(); - - if (!update) - sd_obj.listDirToLinkedList(sd_obj.sd_files); - else - sd_obj.listDirToLinkedList(sd_obj.sd_files, "/", ".bin"); -} - -void MenuFunctions::buildSDFileMenu(bool update) { - this->setupSDFileList(update); - - sdDeleteMenu.list->clear(); - delete sdDeleteMenu.list; - sdDeleteMenu.list = new LinkedList(); - - if (!update) - sdDeleteMenu.name = "SD Files"; - else - sdDeleteMenu.name = "Bin Files"; - - this->addNodes(&sdDeleteMenu, text09, TFTLIGHTGREY, 0, [this]() { - this->changeMenu(sdDeleteMenu.parentMenu, true); - }); - - if (!update) { - this->addNodes(&sdDeleteMenu, "Delete Selected", TFTORANGE, 0, [this]() { - for (int x = 0; x < sd_obj.sd_files->size(); x++) { - if (current_menu->list->get(x + 2).selected) { - if (sd_obj.removeFile("/" + sd_obj.sd_files->get(x))) { - Serial.println("Deleted /" + sd_obj.sd_files->get(x)); - display_obj.clearScreen(); - display_obj.tft.setTextWrap(false); - display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.println("Deleting /" + sd_obj.sd_files->get(x) + "..."); - } - } - } - this->buildSDFileMenu(); - this->changeMenu(&sdDeleteMenu, true); - }); - } - - if (!update) { - for (int x = 0; x < sd_obj.sd_files->size(); x++) { - this->addNodes(&sdDeleteMenu, sd_obj.sd_files->get(x).c_str(), TFTCYAN, SD_UPDATE, [this, x]() { - // Change selection status of menu node - MenuNode new_node = current_menu->list->get(x + 2); - new_node.selected = !current_menu->list->get(x + 2).selected; - current_menu->list->set(x + 2, new_node); - }); - } - } - else { - for (int x = 0; x < sd_obj.sd_files->size(); x++) { - this->addNodes(&sdDeleteMenu, sd_obj.sd_files->get(x).c_str(), TFTCYAN, SD_UPDATE, [this, x]() { - wifi_scan_obj.currentScanMode = OTA_UPDATE; - this->changeMenu(&failedUpdateMenu, true); - sd_obj.runUpdate("/" + sd_obj.sd_files->get(x)); - }); - } - } -} - - -// Function to add MenuNodes to a menu -void MenuFunctions::addNodes(Menu * menu, const char* name, uint8_t color, int place, std::function callable, bool selected) -{ - //Serial.println("Building node: " + name); - menu->list->add(MenuNode{String(name), false, color, place, selected, callable}); -} - -void MenuFunctions::setGraphScale(float scale) { - this->_graph_scale = scale; -} - -float MenuFunctions::calculateGraphScale(uint8_t value) { - if ((value * this->_graph_scale < GRAPH_VERT_LIM) && (value * this->_graph_scale > GRAPH_VERT_LIM * 0.75)) { - return this->_graph_scale; // No scaling needed if the value is within the limit - } - - if (value < GRAPH_VERT_LIM) - return 1.0; - - // Calculate the multiplier proportionally - return (0.75 * GRAPH_VERT_LIM) / value; -} - -float MenuFunctions::calculateGraphScale(int16_t value) { - if ((value * this->_graph_scale < GRAPH_VERT_LIM) && (value * this->_graph_scale > GRAPH_VERT_LIM * 0.75)) { - return this->_graph_scale; // No scaling needed if the value is within the limit - } - - if (value < GRAPH_VERT_LIM) - return 1.0; - - // Calculate the multiplier proportionally - return (0.75 * GRAPH_VERT_LIM) / value; -} - -float MenuFunctions::graphScaleCheck(const int16_t array[SCREEN_WIDTH]) { - int16_t maxValue = 0; - - // Iterate through the array to find the highest value - for (int16_t i = 0; i < SCREEN_WIDTH; i++) { - if (array[i] > maxValue) { - maxValue = array[i]; - } - } - - // If the highest value exceeds GRAPH_VERT_LIM, call calculateMultiplier - if (maxValue > GRAPH_VERT_LIM) { - return this->calculateGraphScale(maxValue); - } - - // If the highest value does not exceed GRAPH_VERT_LIM, return 1.0 - return 1.0; -} - -float MenuFunctions::graphScaleCheckSmall(const uint8_t array[CHAN_PER_PAGE]) { - uint8_t maxValue = 0; - - // Iterate through the array to find the highest value - for (uint8_t i = 0; i < CHAN_PER_PAGE; i++) { - if (array[i] > maxValue) { - maxValue = array[i]; - } - } - - // If the highest value exceeds GRAPH_VERT_LIM, call calculateMultiplier - if (maxValue > GRAPH_VERT_LIM) { - return this->calculateGraphScale(maxValue); - } - - // If the highest value does not exceed GRAPH_VERT_LIM, return 1.0 - return 1.0; -} - -void MenuFunctions::drawMaxLine(int16_t value, uint16_t color) { - display_obj.tft.drawLine(0, TFT_HEIGHT - (value * this->_graph_scale), TFT_WIDTH, TFT_HEIGHT - (value * this->_graph_scale), color); - display_obj.tft.setCursor(0, TFT_HEIGHT - (value * this->_graph_scale)); - display_obj.tft.setTextColor(color, TFT_BLACK); - display_obj.tft.setTextSize(1); - display_obj.tft.println((String)(value / BASE_MULTIPLIER)); -} - -void MenuFunctions::drawMaxLine(uint8_t value, uint16_t color) { - //display_obj.tft.drawLine(0, TFT_HEIGHT - (value * this->_graph_scale), TFT_WIDTH, TFT_HEIGHT - (value * this->_graph_scale), color); - display_obj.tft.setCursor(0, TFT_HEIGHT - (value * this->_graph_scale)); - display_obj.tft.setTextColor(color, TFT_BLACK); - display_obj.tft.setTextSize(1); - display_obj.tft.println((String)value); -} - -void MenuFunctions::drawGraphSmall(uint8_t *values) { - uint8_t maxValue = 0; - //(i + (CHAN_PER_PAGE * (this->activity_page - 1))) - - int bar_width = SCREEN_WIDTH / (CHAN_PER_PAGE * 2); - //display_obj.tft.fillRect(0, TFT_HEIGHT / 2 + 1, SCREEN_WIDTH, (TFT_HEIGHT / 2) + 1, TFT_BLACK); - - #ifndef HAS_DUAL_BAND - for (int i = 1; i < CHAN_PER_PAGE + 1; i++) { - int targ_val = i + (CHAN_PER_PAGE * (wifi_scan_obj.activity_page - 1)) - 1; - int x_mult = (i * 2) - 1; - int x_coord = (SCREEN_WIDTH / (CHAN_PER_PAGE * 2)) * (x_mult - 1); - - if (values[targ_val] > maxValue) { - maxValue = values[targ_val]; - } - - if (values[targ_val] * this->_graph_scale <= GRAPH_VERT_LIM) { - display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT / 2 + 1, bar_width, SCREEN_HEIGHT / 2 + 1, TFT_BLACK); - display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT - (values[targ_val] * this->_graph_scale), bar_width, values[targ_val] * this->_graph_scale, TFT_CYAN); - } - - display_obj.tft.drawLine(x_coord - 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), x_coord - 2, SCREEN_HEIGHT, TFT_WHITE); - } - #else - for (int i = 1; i < CHAN_PER_PAGE + 1; i++) { - int targ_val = i + (CHAN_PER_PAGE * (wifi_scan_obj.activity_page - 1)) - 1; - int x_mult = (i * 2) - 1; - int x_coord = (SCREEN_WIDTH / (CHAN_PER_PAGE * 2)) * (x_mult - 1); - - if (values[targ_val] > maxValue) { - maxValue = values[targ_val]; - } - - if (values[targ_val] * this->_graph_scale <= GRAPH_VERT_LIM) { - display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT / 2 + 1, bar_width + 3, SCREEN_HEIGHT / 2 + 1, TFT_BLACK); - display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT - (values[targ_val] * this->_graph_scale), bar_width, values[targ_val] * this->_graph_scale, TFT_CYAN); - } - - display_obj.tft.drawLine(x_coord - 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), x_coord - 2, SCREEN_HEIGHT, TFT_WHITE); - } - #endif - - this->drawMaxLine(maxValue, TFT_GREEN); // Draw max -} - -void MenuFunctions::drawGraph(int16_t *values) { - #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - int width = TFT_WIDTH; - #else - int width = SCREEN_WIDTH; - #endif - - int16_t maxValue = 0; - int total = 0; - for (int i = width - 1; i >= 0; i--) { - if (values[i] >= 0) { - total = total + values[i]; - if (values[i] > maxValue) { - maxValue = values[i]; - } - #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - GRAPH_VERT_LIM, TFT_BLACK); - display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - (values[i] * this->_graph_scale), TFT_CYAN); - #else - display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - GRAPH_VERT_LIM, TFT_BLACK); - display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - (values[i] * this->_graph_scale), TFT_CYAN); - display_obj.tft.setCursor(0, 0); - display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); - #endif - } - else { - int16_t ch_val = values[i] * -1; - #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) - display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - GRAPH_VERT_LIM, TFT_BLACK); - display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - GRAPH_VERT_LIM, TFT_RED); - display_obj.tft.setCursor(i, TFT_HEIGHT - GRAPH_VERT_LIM); - #else - display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - GRAPH_VERT_LIM, TFT_BLACK); - display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - GRAPH_VERT_LIM, TFT_RED); - display_obj.tft.setCursor(i, TFT_WIDTH - GRAPH_VERT_LIM); - #endif - display_obj.tft.setTextColor(TFT_BLACK, TFT_RED); - display_obj.tft.setTextSize(1); - display_obj.tft.println((String)ch_val); - } - } - - this->drawMaxLine(maxValue, TFT_GREEN); // Draw max - this->drawMaxLine((int16_t)(total / TFT_WIDTH), TFT_ORANGE); // Draw average -} - -void MenuFunctions::renderGraphUI(uint8_t scan_mode) { - display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); - if (scan_mode == WIFI_SCAN_CHAN_ANALYZER) - display_obj.tft.drawCentreString("Frames/" + (String)BANNER_TIME + "ms", SCREEN_WIDTH / 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), 1); - else if (scan_mode == BT_SCAN_ANALYZER) - display_obj.tft.drawCentreString("BLE Beacons/" + (String)BANNER_TIME + "ms", SCREEN_WIDTH / 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), 1); - display_obj.tft.drawLine(0, SCREEN_HEIGHT - GRAPH_VERT_LIM - 1, SCREEN_WIDTH, SCREEN_HEIGHT - GRAPH_VERT_LIM - 1, TFT_WHITE); - display_obj.tft.setCursor(0, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 8)); - display_obj.tft.setTextSize(1); - display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); - display_obj.tft.println("Max"); - display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK); - display_obj.tft.println("Average"); - display_obj.tft.setTextColor(TFT_RED, TFT_BLACK); - if (scan_mode != BT_SCAN_ANALYZER) - display_obj.tft.println("Channel Marker"); -} - -uint16_t MenuFunctions::getColor(uint16_t color) { - if (color == TFTWHITE) return TFT_WHITE; - else if (color == TFTCYAN) return TFT_CYAN; - else if (color == TFTBLUE) return TFT_BLUE; - else if (color == TFTRED) return TFT_RED; - else if (color == TFTGREEN) return TFT_GREEN; - else if (color == TFTGREY) return TFT_LIGHTGREY; - else if (color == TFTGRAY) return TFT_LIGHTGREY; - else if (color == TFTMAGENTA) return TFT_MAGENTA; - else if (color == TFTVIOLET) return TFT_VIOLET; - else if (color == TFTORANGE) return TFT_ORANGE; - else if (color == TFTYELLOW) return TFT_YELLOW; - else if (color == TFTLIGHTGREY) return TFT_LIGHTGREY; - else if (color == TFTPURPLE) return TFT_PURPLE; - else if (color == TFTNAVY) return TFT_NAVY; - else if (color == TFTSILVER) return TFT_SILVER; - else if (color == TFTDARKGREY) return TFT_DARKGREY; - else if (color == TFTSKYBLUE) return TFT_SKYBLUE; - else if (color == TFTLIME) return 0x97e0; - else return color; -} - -// Function to change menu -void MenuFunctions::changeMenu(Menu* menu, bool simple_change) { - if (!simple_change) { - //display_obj.initScrollValues(); - //display_obj.setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA); - display_obj.init(); - - #ifdef HAS_ILI9341 - extern void backlightOn(); - backlightOn(); - #endif - } - current_menu = menu; - - current_menu->selected = 0; - - buildButtons(menu); - - displayCurrentMenu(); - - //#ifdef MARAUDER_V8 - // digitalWrite(TFT_BL, HIGH); - //#endif -} - -void MenuFunctions::buildButtons(Menu *menu, int starting_index, const char* button_name) { - if (menu->list == NULL || menu->list->size() == 0) - return; - - if (starting_index >= menu->list->size()) - starting_index = menu->list->size() - BUTTON_SCREEN_LIMIT; - if (starting_index < 0) - starting_index = 0; - - this->menu_start_index = starting_index; - - uint8_t visible_buttons = min(BUTTON_SCREEN_LIMIT, menu->list->size() - starting_index); - - for (uint8_t i = 0; i < visible_buttons; i++) { - MenuNode node = menu->list->get(starting_index + i); - uint16_t color = (node.icon == SETTINGS && node.color == TFTLIGHTGREY) ? (node.selected ? TFT_GREEN : TFT_RED) : this->getColor(node.color); - - char buf[64]; - - if (button_name != nullptr && button_name[0] != '\0') { - strncpy(buf, button_name, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - } else { - node.name.toCharArray(buf, sizeof(buf)); - } - - display_obj.key[i].initButton(&display_obj.tft, - KEY_X, - KEY_Y + i * (KEY_H + KEY_SPACING_Y), - KEY_W, - KEY_H, - TFT_BLACK, - TFT_BLACK, - color, - buf, - KEY_TEXTSIZE); - - #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) - display_obj.key[i].setLabelDatum(BUTTON_PADDING - (KEY_W / 2), 4, ML_DATUM); - #else - display_obj.key[i].setLabelDatum(BUTTON_PADDING - (KEY_W / 2), 2, ML_DATUM); - #endif - } - - for (int i = BUTTON_ARRAY_LEN; i < BUTTON_ARRAY_LEN + 3; i++) { - uint16_t x = TFT_WIDTH / 2; - uint16_t y = TFT_HEIGHT / 3 * (i - BUTTON_ARRAY_LEN) + ((TFT_HEIGHT / 3) / 2); - uint16_t w = TFT_WIDTH; - uint16_t h = TFT_HEIGHT / 3 - 1; - - display_obj.key[i].initButton(&display_obj.tft, - x, - y, - w, - h, - TFT_LIGHTGREY, - TFT_BLACK, - TFT_BLACK, - "Chicken", - 1); - } -} - -void MenuFunctions::displayCurrentMenu(int start_index) -{ - //Serial.println(F("Displaying current menu...")); - display_obj.clearScreen(); - display_obj.updateBanner(current_menu->name); - display_obj.tft.setTextColor(TFT_LIGHTGREY, TFT_DARKGREY); - this->drawStatusBar(); - - if (current_menu->list != NULL) - { - #ifdef HAS_FULL_SCREEN - display_obj.tft.setFreeFont(MENU_FONT); - #endif - - #ifdef HAS_MINI_SCREEN - display_obj.tft.setFreeFont(NULL); - display_obj.tft.setTextSize(1); - #endif - - for (uint16_t i = start_index; i < min(start_index + BUTTON_SCREEN_LIMIT, current_menu->list->size()); i++) - { - if (!current_menu || !current_menu->list || i >= current_menu->list->size()) - continue; - uint16_t color = this->getColor(current_menu->list->get(i).color); - #ifdef HAS_FULL_SCREEN - bool is_setting_node = (current_menu->list->get(i).icon == SETTINGS && current_menu->list->get(i).color == TFTLIGHTGREY); - if (is_setting_node && current_menu->selected == i) { - uint16_t setting_color = current_menu->list->get(i).selected ? TFT_GREEN : TFT_RED; - display_obj.key[i - start_index].initButton(&display_obj.tft, KEY_X, KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y), KEY_W, KEY_H, TFT_BLACK, TFT_LIGHTGREY, setting_color, (char*)"", KEY_TEXTSIZE); - display_obj.key[i - start_index].drawButton(false, current_menu->list->get(i).name); - display_obj.tft.drawXBitmap(0, - KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2), - menu_icons[current_menu->list->get(i).icon], - ICON_W, - ICON_H, - TFT_BLACK, - TFT_LIGHTGREY); - } else if ((!is_setting_node && current_menu->list->get(i).selected) || (current_menu->selected == i)) { - display_obj.key[i - start_index].drawButton(true, current_menu->list->get(i).name); - if ((current_menu->list->get(i).name != text09) && (current_menu->list->get(i).icon != 255)) - display_obj.tft.drawXBitmap(0, - KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2), - menu_icons[current_menu->list->get(i).icon], - ICON_W, - ICON_H, - TFT_BLACK, - color); - } else { - display_obj.key[i - start_index].drawButton(false, current_menu->list->get(i).name); - if ((current_menu->list->get(i).name != text09) && (current_menu->list->get(i).icon != 255)) - display_obj.tft.drawXBitmap(0, - KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2), - menu_icons[current_menu->list->get(i).icon], - ICON_W, - ICON_H, - TFT_BLACK, - is_setting_node ? TFT_LIGHTGREY : color); - } - - #endif - - #ifdef HAS_MINI_SCREEN - if ((current_menu->selected == i) || ((current_menu->list->get(i).icon != SETTINGS || current_menu->list->get(i).color != TFTLIGHTGREY) && current_menu->list->get(i).selected)) - this->drawMiniMenuButton(i - start_index, i, true); - else - this->drawMiniMenuButton(i - start_index, i, false); - #endif - } - display_obj.tft.setFreeFont(NULL); - } - - this->displayMenuButtons(); -} - -// ============================================================ -// BRIGHTNESS ADJUSTMENT MODE -// Hold top/bottom zone 1.5s to enter. TAP TOP = brighter, TAP BOTTOM = dimmer. -// TAP MIDDLE or wait 3s = save & exit. -// ============================================================ -#ifndef HAS_MINI_SCREEN - void MenuFunctions::brightnessMode() { - extern void brightnessSave(uint8_t level); - extern uint8_t getBrightnessLevel(); - - const uint8_t levels[] = {26, 51, 77, 102, 128, 153, 179, 204, 230, 255}; - const uint8_t numLevels = 10; - uint8_t level = getBrightnessLevel(); - - // LEDC write compatibility (2.x vs 3.x board package) - #if ESP_ARDUINO_VERSION_MAJOR >= 3 - #define BL_PREVIEW(duty) ledcWrite(TFT_BL, (duty)) - #else - #define BL_PREVIEW(duty) ledcWrite(0, (duty)) - #endif - - display_obj.tft.fillScreen(TFT_BLACK); - display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); - display_obj.tft.drawCentreString("BRIGHTNESS", TFT_WIDTH/2, 30, 2); - - display_obj.tft.setTextColor(TFT_DARKGREY, TFT_BLACK); - display_obj.tft.drawCentreString("TAP TOP = BRIGHTER", TFT_WIDTH/2, 10, 1); - display_obj.tft.drawCentreString("TAP BOTTOM = DIMMER", TFT_WIDTH/2, TFT_HEIGHT - 20, 1); - display_obj.tft.setTextColor(TFT_RED, TFT_BLACK); - display_obj.tft.drawCentreString("TAP MIDDLE or WAIT 3s = SAVE", TFT_WIDTH/2, TFT_HEIGHT/2 + 50, 1); - - auto drawBar = [&]() { - uint16_t barX = 30, barY = TFT_HEIGHT/2 - 25, barW = TFT_WIDTH - 60, barH = 30; - display_obj.tft.drawRect(barX, barY, barW, barH, TFT_WHITE); - uint16_t fillW = (barW - 4) * (level + 1) / numLevels; - display_obj.tft.fillRect(barX + 2, barY + 2, barW - 4, barH - 4, TFT_BLACK); - display_obj.tft.fillRect(barX + 2, barY + 2, fillW, barH - 4, TFT_CYAN); - display_obj.tft.fillRect(0, barY + barH + 5, TFT_WIDTH, 20, TFT_BLACK); - display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); - String pct = String(levels[level] * 100 / 255) + "%"; - display_obj.tft.drawCentreString(pct, TFT_WIDTH/2, barY + barH + 8, 2); - }; - drawBar(); - - uint16_t zoneUp = TFT_HEIGHT * 25 / 100; - uint16_t zoneDown = TFT_HEIGHT * 75 / 100; - uint32_t lastTouch = millis(); - - while (true) { - // Auto-save after 3s of no touch - if (millis() - lastTouch >= 3000) { - brightnessSave(level); - break; - } - - uint16_t tx, ty; - if (display_obj.updateTouch(&tx, &ty)) { - lastTouch = millis(); - // Wait for release - while (display_obj.updateTouch(&tx, &ty)) delay(10); - - if (ty < zoneUp) { - if (level < numLevels - 1) { - level++; - BL_PREVIEW(levels[level]); - drawBar(); - } - } else if (ty >= zoneDown) { - if (level > 0) { - level--; - BL_PREVIEW(levels[level]); - drawBar(); - } - } else { - // Middle = save now - brightnessSave(level); - break; - } - delay(150); - } - delay(30); - } - - #undef BL_PREVIEW - this->changeMenu(current_menu, true); - } -#endif - -#endif - - - + selectProbeSSIDsMenu.list = new LinkedList(); + + // WiFi HTML menu stuff + htmlMenu.list = new LinkedList(); + miniKbMenu.list = new LinkedList(); + #ifdef HAS_SD + sdDeleteMenu.list = new LinkedList(); + #endif + + // Bluetooth menu stuff + bluetoothSnifferMenu.list = new LinkedList(); + bluetoothAttackMenu.list = new LinkedList(); + + // Settings stuff + generateSSIDsMenu.list = new LinkedList(); + clearSSIDsMenu.list = new LinkedList(); + clearAPsMenu.list = new LinkedList(); + saveFileMenu.list = new LinkedList(); + + #ifdef HAS_DIRECT_UPLOAD + uploadLogsMenu.list = new LinkedList(); + uploadAllMenu.list = new LinkedList(); + deleteAllMenu.list = new LinkedList(); + actionMenu.list = new LinkedList(); + #endif + + saveSSIDsMenu.list = new LinkedList(); + loadSSIDsMenu.list = new LinkedList(); + saveAPsMenu.list = new LinkedList(); + loadAPsMenu.list = new LinkedList(); + saveATsMenu.list = new LinkedList(); + loadATsMenu.list = new LinkedList(); + + evilPortalMenu.list = new LinkedList(); + ssidsMenu.list = new LinkedList(); + + #ifdef HAS_GPS + gpsPOIMenu.list = new LinkedList(); + #endif + + foxHuntMenu.list = new LinkedList(); + + // Work menu names + mainMenu.name = text_table1[6]; + wifiMenu.name = text_table1[7]; + deviceMenu.name = text_table1[9]; + failedUpdateMenu.name = text_table1[11]; + confirmMenu.name = text_table1[13]; + updateMenu.name = text_table1[15]; + infoMenu.name = text_table1[17]; + settingsMenu.name = text_table1[18]; + bluetoothMenu.name = text_table1[19]; + wifiSnifferMenu.name = text_table1[20]; + wifiScannerMenu.name = "Scanners"; + wifiAttackMenu.name = text_table1[21]; + wifiGeneralMenu.name = text_table1[22]; + saveFileMenu.name = "Save/Load Files"; + saveSSIDsMenu.name = "Save SSIDs"; + loadSSIDsMenu.name = "Load SSIDs"; + saveAPsMenu.name = "Save APs"; + loadAPsMenu.name = "Load APs"; + saveATsMenu.name = "Save Airtags"; + loadATsMenu.name = "Load Airtags"; + + bluetoothSnifferMenu.name = text_table1[23]; + bluetoothAttackMenu.name = "Bluetooth Attacks"; + generateSSIDsMenu.name = text_table1[27]; + clearSSIDsMenu.name = text_table1[28]; + clearAPsMenu.name = text_table1[29]; + wifiAPMenu.name = "Select"; + wifiIPMenu.name = "Active IPs"; + apInfoMenu.name = "AP Info"; + setMacMenu.name = "Set MACs"; + genAPMacMenu.name = "Generate AP MAC"; + wifiStationMenu.name = "Select Stations"; + + #ifdef HAS_DIRECT_UPLOAD + uploadLogsMenu.name = "Upload Logs"; + uploadAllMenu.name = "Upload All?"; + deleteAllMenu.name = "Delete All?"; + actionMenu.name = "Destination"; + #endif + + #ifdef HAS_GPS + gpsMenu.name = "GPS"; + gpsInfoMenu.name = "GPS Data"; + //wardrivingMenu.name = "Wardriving"; + #endif + htmlMenu.name = "EP HTML List"; + miniKbMenu.name = "Mini Keyboard"; + + #ifdef HAS_SD + sdDeleteMenu.name = "Delete SD Files"; + #endif + + selectProbeSSIDsMenu.name = "Probe Requests"; + evilPortalMenu.name = "Evil Portal"; + ssidsMenu.name = "SSIDs"; + + #ifdef HAS_GPS + gpsPOIMenu.name = "GPS POI"; + #endif + + foxHuntMenu.name = "Fox Hunt"; + + // Build Main Menu + mainMenu.parentMenu = NULL; + this->addNodes(&mainMenu, text_table1[7], TFTGREEN, WIFI, [this]() { + this->changeMenu(&wifiMenu, true); + }); + #ifdef HAS_BT + this->addNodes(&mainMenu, text_table1[19], TFTCYAN, BLUETOOTH, [this]() { + this->changeMenu(&bluetoothMenu, true); + }); + #endif + #ifdef HAS_GPS + if (gps_obj.getGpsModuleStatus()) { + this->addNodes(&mainMenu, text1_66, TFTRED, GPS_MENU, [this]() { + this->changeMenu(&gpsMenu, true); + }); + } + #endif + this->addNodes(&mainMenu, text_table1[9], TFTBLUE, DEVICE, [this]() { + this->changeMenu(&deviceMenu, true); + }); + this->addNodes(&mainMenu, text_table1[30], TFTLIGHTGREY, REBOOT, []() { + ESP.restart(); + }); + + // Build WiFi Menu + wifiMenu.parentMenu = &mainMenu; // Main Menu is second menu parent + this->addNodes(&wifiMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiMenu.parentMenu, true); + }); + this->addNodes(&wifiMenu, text_table1[31], TFTYELLOW, SNIFFERS, [this]() { + this->changeMenu(&wifiSnifferMenu, true); + }); + this->addNodes(&wifiMenu, "Scanners", TFTORANGE, SCANNERS, [this]() { + this->changeMenu(&wifiScannerMenu, true); + }); + /*#ifdef HAS_GPS + this->addNodes(&wifiMenu, "Wardriving", TFTGREEN, NULL, BEACON_SNIFF, [this]() { + this->changeMenu(&wardrivingMenu, true); + }); + #endif*/ + this->addNodes(&wifiMenu, text_table1[32], TFTRED, ATTACKS, [this]() { + this->changeMenu(&wifiAttackMenu, true); + }); + this->addNodes(&wifiMenu, text_table1[33], TFTPURPLE, GENERAL_APPS, [this]() { + this->changeMenu(&wifiGeneralMenu, true); + }); + + // Build WiFi scanner Menu + wifiScannerMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent + this->addNodes(&wifiScannerMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiScannerMenu.parentMenu, true); + }); + this->addNodes(&wifiScannerMenu, "Ping Scan", TFTGREEN, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_PING_SCAN, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "ARP Scan", TFTCYAN, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ARP_SCAN, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "Port Scan All", TFTMAGENTA, BEACON_LIST, [this](){ + // Add the back button + wifiIPMenu.list->clear(); + this->addNodes(&wifiIPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiIPMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < ipList->size(); i++) { + // This is the menu node + this->addNodes(&wifiIPMenu, ipList->get(i).toString().c_str(), TFTBLUE, 255, [this, i](){ + Serial.println("Selected: " + ipList->get(i).toString()); + wifi_scan_obj.current_scan_ip = ipList->get(i); + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_PORT_SCAN_ALL, TFT_BLUE); + }); + } + this->changeMenu(&wifiIPMenu, true); + }); + this->addNodes(&wifiScannerMenu, "SSH Scan", TFTORANGE, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_SSH, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "Telnet Scan", TFTRED, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_TELNET, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "SMTP Scan", TFTWHITE, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_SMTP, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "DNS Scan", TFTLIME, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_DNS, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "HTTP Scan", TFTSKYBLUE, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_HTTP, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "HTTPS Scan", TFTYELLOW, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_HTTPS, TFT_CYAN); + }); + this->addNodes(&wifiScannerMenu, "RDP Scan", TFTPURPLE, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_RDP, TFT_CYAN); + }); + + // Build WiFi sniffer Menu + wifiSnifferMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent + this->addNodes(&wifiSnifferMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiSnifferMenu.parentMenu, true); + }); + this->addNodes(&wifiSnifferMenu, text_table1[42], TFTCYAN, PROBE_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_PROBE, TFT_CYAN); + }); + this->addNodes(&wifiSnifferMenu, text_table1[43], TFTMAGENTA, BEACON_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_AP, TFT_MAGENTA); + }); + this->addNodes(&wifiSnifferMenu, text_table1[44], TFTRED, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_DEAUTH, TFT_RED); + }); + this->addNodes(&wifiSnifferMenu, "Packet Count", TFTORANGE, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_PACKET_RATE, TFT_ORANGE); + wifi_scan_obj.renderPacketRate(); + }); + #ifdef HAS_ILI9341 + this->addNodes(&wifiSnifferMenu, text_table1[46], TFTVIOLET, EAPOL, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET); + }); + this->addNodes(&wifiSnifferMenu, text_table1[45], TFTBLUE, PACKET_MONITOR, [this]() { + wifi_scan_obj.StartScan(WIFI_PACKET_MONITOR, TFT_BLUE); + }); + #else // No touch + this->addNodes(&wifiSnifferMenu, text_table1[46], TFTVIOLET, EAPOL, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_EAPOL, TFT_VIOLET); + }); + this->addNodes(&wifiSnifferMenu, text_table1[45], TFTBLUE, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_PACKET_MONITOR, TFT_BLUE); + }); + #endif + this->addNodes(&wifiSnifferMenu, "Channel Analyzer", TFTCYAN, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + this->renderGraphUI(WIFI_SCAN_CHAN_ANALYZER); + wifi_scan_obj.StartScan(WIFI_SCAN_CHAN_ANALYZER, TFT_CYAN); + }); + this->addNodes(&wifiSnifferMenu, "Channel Summary", TFTORANGE, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + this->renderGraphUI(WIFI_SCAN_CHAN_ACT); + wifi_scan_obj.StartScan(WIFI_SCAN_CHAN_ACT, TFT_CYAN); + }); + + this->addNodes(&wifiSnifferMenu, text_table1[58], TFTWHITE, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_RAW_CAPTURE, TFT_WHITE); + }); + + this->addNodes(&wifiSnifferMenu, text_table1[47], TFTRED, PWNAGOTCHI, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_PWN, TFT_RED); + }); + + this->addNodes(&wifiSnifferMenu, text_table1[63], TFTYELLOW, PINESCAN_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_PINESCAN, TFT_YELLOW); + }); + + this->addNodes(&wifiSnifferMenu, text_table1[64], TFTORANGE, MULTISSID_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_MULTISSID, TFT_ORANGE); + }); + this->addNodes(&wifiSnifferMenu, "Scan AP/STA", TFTLIME, BEACON_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_AP_STA, 0x97e0); + }); + /*this->addNodes(&wifiSnifferMenu, "Fox Hunt", TFTCYAN, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_SIG_STREN, TFT_CYAN); + });*/ + this->addNodes(&wifiSnifferMenu, "Fox Hunt", TFTCYAN, SCANNERS, [this]() { + this->buildWiFiFoxHuntMenu(); + }); + this->addNodes(&wifiSnifferMenu, "MAC Monitor", TFTMAGENTA, SCANNERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_DETECT_FOLLOW, TFT_MAGENTA); + }); + this->addNodes(&wifiSnifferMenu, "SAE Commit", TFTLIME, EAPOL, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_SAE_COMMIT, TFT_GREEN); + }); + + // Build Wardriving menu + #ifdef HAS_GPS + /*wardrivingMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent + this->addNodes(&wardrivingMenu, text09, TFTLIGHTGREY, NULL, 0, [this]() { + this->changeMenu(wardrivingMenu.parentMenu, true); + });*/ + if (gps_obj.getGpsModuleStatus()) { + this->addNodes(&wifiSnifferMenu, "Wardrive", TFTGREEN, BEACON_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_WAR_DRIVE, TFT_GREEN); + }); + } + #endif + /*#ifdef HAS_GPS + if (gps_obj.getGpsModuleStatus()) { + this->addNodes(&wardrivingMenu, "Station Wardrive", TFTORANGE, NULL, PROBE_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_STATION_WAR_DRIVE, TFT_ORANGE); + }); + } + #endif*/ + + // Build WiFi attack menu + wifiAttackMenu.parentMenu = &wifiMenu; // Main Menu is second menu parent + this->addNodes(&wifiAttackMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAttackMenu.parentMenu, true); + }); + this->addNodes(&wifiAttackMenu, text_table1[50], TFTRED, BEACON_LIST, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_LIST, TFT_RED); + }); + this->addNodes(&wifiAttackMenu, text_table1[51], TFTORANGE, BEACON_SPAM, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_BEACON_SPAM, TFT_ORANGE); + }); + this->addNodes(&wifiAttackMenu, text1_67, TFTCYAN, FUNNY_BEACON, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_FUNNY_BEACON, TFT_CYAN); + }); + this->addNodes(&wifiAttackMenu, text_table1[52], TFTYELLOW, RICK_ROLL, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_RICK_ROLL, TFT_YELLOW); + }); + this->addNodes(&wifiAttackMenu, text_table1[53], TFTRED, PROBE_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_AUTH, TFT_RED); + }); + this->addNodes(&wifiAttackMenu, "Evil Portal", TFTORANGE, BEACON_SNIFF, [this]() { + + wifiAPMenu.list->clear(); + ssidsMenu.list->clear(); + + wifiAPMenu.parentMenu = &evilPortalMenu; + ssidsMenu.parentMenu = &evilPortalMenu; + + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + this->addNodes(&ssidsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(ssidsMenu.parentMenu, true); + }); + + // Get AP list ready + for (int i = 0; i < access_points->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + if (evil_portal_obj.setAP(access_points->get(i).essid)) { + AccessPoint new_ap = access_points->get(i); + new_ap.selected = true; + access_points->set(i, new_ap); + + evil_portal_obj.ap_index = i; + + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE); + wifi_scan_obj.setMac(); + } + else + this->changeMenu(&evilPortalMenu, true); + }); + } + + for (int i = 0; i < ssids->size(); i++) { + // This is the menu node + this->addNodes(&ssidsMenu, ssids->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + if (evil_portal_obj.setAP(ssids->get(i).essid)) { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE); + wifi_scan_obj.setMac(); + } + else + this->changeMenu(&evilPortalMenu, true); + }); + } + this->changeMenu(&evilPortalMenu, true); + }); + this->addNodes(&wifiAttackMenu, text_table1[54], TFTRED, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH, TFT_RED); + }); + this->addNodes(&wifiAttackMenu, text_table1[57], TFTMAGENTA, BEACON_LIST, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_AP_SPAM, TFT_MAGENTA); + }); + this->addNodes(&wifiAttackMenu, text_table1[62], TFTRED, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_DEAUTH_TARGETED, TFT_ORANGE); + }); + + this->addNodes(&wifiAttackMenu, "Karma", TFTORANGE, KEYBOARD_ICO, [this](){ + // Add the back button + selectProbeSSIDsMenu.list->clear(); + this->addNodes(&selectProbeSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(&wifiAttackMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < probe_req_ssids->size(); i++) { + // This is the menu node + this->addNodes(&selectProbeSSIDsMenu, probe_req_ssids->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + if (evil_portal_obj.setAP(probe_req_ssids->get(i).essid)) { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_EVIL_PORTAL, TFT_ORANGE); + wifi_scan_obj.setMac(); + } + else + this->changeMenu(&wifiAttackMenu, true); + }); + } + this->changeMenu(&selectProbeSSIDsMenu, true); + }); + + this->addNodes(&wifiAttackMenu, "Bad Msg", TFTRED, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_BAD_MSG, TFT_RED); + }); + this->addNodes(&wifiAttackMenu, "Bad Msg Targeted", TFTYELLOW, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_BAD_MSG_TARGETED, TFT_YELLOW); + }); + this->addNodes(&wifiAttackMenu, "Assoc Sleep", TFTRED, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_SLEEP, TFT_RED); + }); + this->addNodes(&wifiAttackMenu, "Assoc Sleep Targ", TFTMAGENTA, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_SLEEP_TARGETED, TFT_MAGENTA); + }); + this->addNodes(&wifiAttackMenu, "SAE Commit Flood", TFTLIME, EAPOL, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_SAE_COMMIT, TFT_GREEN); + }); + this->addNodes(&wifiAttackMenu, "Channel Switch", TFTORANGE, BEACON_LIST, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_CSA, TFT_GREEN); + }); + this->addNodes(&wifiAttackMenu, "Quiet Time", TFTRED, BEACON_LIST, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_ATTACK_QUIET, TFT_GREEN); + }); + + evilPortalMenu.parentMenu = &wifiAttackMenu; + this->addNodes(&evilPortalMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(evilPortalMenu.parentMenu, true); + }); + this->addNodes(&evilPortalMenu, "Access Points", TFTGREEN, BEACON_SNIFF, [this]() { + this->changeMenu(&wifiAPMenu, true); + }); + this->addNodes(&evilPortalMenu, "User SSIDs", TFTCYAN, PROBE_SNIFF, [this]() { + this->changeMenu(&ssidsMenu, true); + }); + + // Build WiFi General menu + wifiGeneralMenu.parentMenu = &wifiMenu; + this->addNodes(&wifiGeneralMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiGeneralMenu.parentMenu, true); + }); + this->addNodes(&wifiGeneralMenu, text_table1[27], TFTSKYBLUE, GENERATE, [this]() { + this->changeMenu(&generateSSIDsMenu, true); + wifi_scan_obj.RunGenerateSSIDs(); + }); + + //Add Select probe ssid + this->addNodes(&wifiGeneralMenu, text_table1[65], TFTCYAN, KEYBOARD_ICO, [this]() { + selectProbeSSIDsMenu.list->clear(); + + // Add the back button + this->addNodes(&selectProbeSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(&wifiGeneralMenu, true); + + // TODO: TBD - Should probe_req_ssids have it´s own life and override ap.config and/or ssids -list for EP? + // If so, then we should not add selected ssids to ssids list + + // Add selected ssid names to ssids list when clicking back button + if (probe_req_ssids->size() > 0) { + + //TODO: TBD - Clear ssids list before adding new ones?? + + for (int i = 0; i < probe_req_ssids->size(); i++) { + ProbeReqSsid cur_probe_ssid = probe_req_ssids->get(i); + if (cur_probe_ssid.selected) { + bool ssidExists = false; + for (int i = 0; i < ssids->size(); i++) { + if (ssids->get(i).essid == cur_probe_ssid.essid) { + ssidExists = true; + break; + } + } + if (!ssidExists) { + wifi_scan_obj.addSSID(cur_probe_ssid.essid); + } + } + } + } + }); + + // Populate the menu with buttons + for (int i = 0; i < probe_req_ssids->size(); i++) { + ProbeReqSsid cur_ssid = probe_req_ssids->get(i); + // This is the menu node + String button_name = "[" + String(cur_ssid.requests) + "]" + cur_ssid.essid; + this->addNodes( + &selectProbeSSIDsMenu, + button_name.c_str(), + TFTCYAN, + 255, + [this, i]() { + ProbeReqSsid new_ssid = probe_req_ssids->get(i); + new_ssid.selected = !probe_req_ssids->get(i).selected; + + // Change selection status of menu node + MenuNode new_node = current_menu->list->get(i + 1); + new_node.selected = !current_menu->list->get(i + 1).selected; + current_menu->list->set(i + 1, new_node); + + probe_req_ssids->set(i, new_ssid); + }, + probe_req_ssids->get(i).selected); + } + this->changeMenu(&selectProbeSSIDsMenu, true); + }); + + clearSSIDsMenu.parentMenu = &wifiGeneralMenu; + + #ifdef HAS_ILI9341 + this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, KEYBOARD_ICO, [this](){ + char ssidBuf[64] = {0}; + bool keep_going = true; + while (keep_going) { + display_obj.clearScreen(); + if (keyboardInput(ssidBuf, sizeof(ssidBuf), "Enter SSID")) { + if (ssidBuf[0] != 0) + wifi_scan_obj.addSSID(String(ssidBuf)); + for (int i = 0; i < 64; i++) + ssidBuf[i] = NULL; + } + else + keep_going = false; + } + + this->changeMenu(current_menu); + }); + #endif + #if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) + this->addNodes(&wifiGeneralMenu, text_table1[1], TFTNAVY, KEYBOARD_ICO, [this](){ + this->changeMenu(&miniKbMenu, true); + #ifdef HAS_MINI_KB + this->miniKeyboard(&miniKbMenu); + #endif + }); + #endif + this->addNodes(&wifiGeneralMenu, text_table1[28], TFTSILVER, CLEAR_ICO, [this]() { + this->changeMenu(&clearSSIDsMenu, true); + wifi_scan_obj.RunClearSSIDs(); + }); + this->addNodes(&wifiGeneralMenu, text_table1[29], TFTDARKGREY, CLEAR_ICO, [this]() { + this->changeMenu(&clearAPsMenu, true); + wifi_scan_obj.RunClearAPs(); + }); + this->addNodes(&wifiGeneralMenu, text_table1[60], TFTBLUE, CLEAR_ICO, [this]() { + this->changeMenu(&clearAPsMenu, true); + wifi_scan_obj.RunClearStations(); + }); + //#else // Mini EP HTML select + this->addNodes(&wifiGeneralMenu, "Select EP HTML File", TFTCYAN, KEYBOARD_ICO, [this](){ + // Add the back button + htmlMenu.list->clear(); + this->addNodes(&htmlMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(htmlMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < evil_portal_obj.html_files->size(); i++) { + // This is the menu node + this->addNodes(&htmlMenu, evil_portal_obj.html_files->get(i).c_str(), TFTCYAN, 255, [this, i](){ + evil_portal_obj.selected_html_index = i; + evil_portal_obj.target_html_name = evil_portal_obj.html_files->get(evil_portal_obj.selected_html_index); + Serial.println("Set Evil Portal HTML as " + evil_portal_obj.target_html_name); + evil_portal_obj.using_serial_html = false; + this->changeMenu(htmlMenu.parentMenu, true); + return; + }); + } + this->changeMenu(&htmlMenu, true); + }); + + //#if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) + miniKbMenu.parentMenu = &wifiGeneralMenu; + #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + this->addNodes(&miniKbMenu, "a", TFTCYAN, 0, [this]() { + this->changeMenu(miniKbMenu.parentMenu, true); + }); + #endif + //#endif + + htmlMenu.parentMenu = &wifiGeneralMenu; + this->addNodes(&htmlMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(htmlMenu.parentMenu, true); + }); + + // Select APs on Mini + this->addNodes(&wifiGeneralMenu, "Select APs", TFTNAVY, KEYBOARD_ICO, [this](){ + wifiAPMenu.parentMenu = &wifiGeneralMenu; + // Add the back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + this->addNodes(&wifiAPMenu, "Select ALL", TFTGREEN, 255, [this](){ + + for (int x = 0; x < access_points->size(); x++) { + AccessPoint new_ap = access_points->get(x); + new_ap.selected = !access_points->get(x).selected; + access_points->set(x, new_ap); + + MenuNode new_node = current_menu->list->get(x + 2); + new_node.selected = !current_menu->list->get(x + 2).selected; + current_menu->list->set(x + 2, new_node); + } + + this->changeMenu(current_menu, true); + + }); + + // Populate the menu with buttons + for (int i = 0; i < access_points->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + AccessPoint new_ap = access_points->get(i); + new_ap.selected = !access_points->get(i).selected; + + // Change selection status of menu node + MenuNode new_node = current_menu->list->get(i + 2); + new_node.selected = !current_menu->list->get(i + 2).selected; + current_menu->list->set(i + 2, new_node); + + access_points->set(i, new_ap); + }, access_points->get(i).selected); + } + this->changeMenu(&wifiAPMenu, true); + }); + + this->addNodes(&wifiGeneralMenu, "View AP Info", TFTCYAN, KEYBOARD_ICO, [this](){ + wifiAPMenu.parentMenu = &wifiGeneralMenu; + + // Add the back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < access_points->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + this->changeMenu(&apInfoMenu, true); + wifi_scan_obj.RunAPInfo(i); + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + + apInfoMenu.parentMenu = &wifiAPMenu; + this->addNodes(&apInfoMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(apInfoMenu.parentMenu, true); + }); + + wifiAPMenu.parentMenu = &wifiGeneralMenu; + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + wifiIPMenu.parentMenu = &wifiScannerMenu; + this->addNodes(&wifiIPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiIPMenu.parentMenu, true); + }); + + + // Select Stations on Mini v2 + this->addNodes(&wifiGeneralMenu, "Select Stations", TFTCYAN, KEYBOARD_ICO, [this](){ + wifiAPMenu.parentMenu = &wifiGeneralMenu; + + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + int menu_limit = access_points->size(); + + + for (int i = 0; i < menu_limit; i++) { + wifiStationMenu.list->clear(); + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + + wifiStationMenu.list->clear(); + + wifiStationMenu.parentMenu = &wifiAPMenu; + + // Add back button to the APs + this->addNodes(&wifiStationMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiStationMenu.parentMenu, true); + }); + + this->addNodes(&wifiStationMenu, "Select ALL", TFTGREEN, 255, [this, i](){ + + for (int y = 0; y < access_points->get(i).stations->size(); y++) { + int cur_ap_sta_inx = access_points->get(i).stations->get(y); + Station new_sta = stations->get(cur_ap_sta_inx); + new_sta.selected = !stations->get(cur_ap_sta_inx).selected; + + // Change selection status of menu node + MenuNode new_node = current_menu->list->get(y + 2); + new_node.selected = !current_menu->list->get(y + 2).selected; + current_menu->list->set(y + 2, new_node); + + stations->set(cur_ap_sta_inx, new_sta); + } + + this->changeMenu(current_menu, true); + + }); + + // Add the AP's stations to the specific AP menu + for (int x = 0; x < access_points->get(i).stations->size(); x++) { + int cur_ap_sta = access_points->get(i).stations->get(x); + + this->addNodes(&wifiStationMenu, macToString(stations->get(cur_ap_sta)).c_str(), TFTCYAN, 255, [this, i, cur_ap_sta, x](){ + Station new_sta = stations->get(cur_ap_sta); + new_sta.selected = !stations->get(cur_ap_sta).selected; + + // Change selection status of menu node + MenuNode new_node = current_menu->list->get(x + 2); + new_node.selected = !current_menu->list->get(x + 2).selected; + current_menu->list->set(x + 2, new_node); + + stations->set(cur_ap_sta, new_sta); + }, stations->get(cur_ap_sta).selected); + } + + // Final change menu to the menu of Stations + this->changeMenu(&wifiStationMenu, true); + + }, false); + } + this->changeMenu(&wifiAPMenu, true); + }); + + this->addNodes(&wifiGeneralMenu, "Join WiFi", TFTWHITE, KEYBOARD_ICO, [this](){ + + wifiAPMenu.parentMenu = &wifiGeneralMenu; + + // Add the back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < access_points->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + // Join WiFi using mini keyboard + #ifdef HAS_MINI_KB + this->changeMenu(&miniKbMenu, true); + String password = this->miniKeyboard(&miniKbMenu, true); + if (password != "") { + Serial.println("Using SSID: " + (String)access_points->get(i).essid + " Password: " + (String)password); + wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + wifi_scan_obj.joinWiFi(access_points->get(i).essid, password); + this->changeMenu(current_menu, true); + } + #endif + + // Join WiFi using touch screen keyboard + #ifdef HAS_TOUCH + char passwordBuf[64] = {0}; // or prefill with existing SSID + if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { + wifi_scan_obj.joinWiFi(access_points->get(i).essid, String(passwordBuf), true); + } + + this->changeMenu(&wifiGeneralMenu, true); + #endif + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + + this->addNodes(&wifiGeneralMenu, "Join Saved WiFi", TFTWHITE, KEYBOARD_ICO, [this](){ + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + if ((ssid != "") && (pw != "")) { + wifi_scan_obj.joinWiFi(ssid, pw, false); + this->changeMenu(&wifiGeneralMenu, true); + } + else { + wifiAPMenu.parentMenu = &wifiGeneralMenu; + + // Add the back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < access_points->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + // Join WiFi using mini keyboard + #ifdef HAS_MINI_KB + this->changeMenu(&miniKbMenu, true); + String password = this->miniKeyboard(&miniKbMenu, true); + if (password != "") { + Serial.println("Using SSID: " + (String)access_points->get(i).essid + " Password: " + (String)password); + wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + wifi_scan_obj.joinWiFi(access_points->get(i).essid, password); + this->changeMenu(current_menu, true); + } + #endif + + // Join WiFi using touch screen keyboard + #ifdef HAS_TOUCH + char passwordBuf[64] = {0}; // or prefill with existing SSID + if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { + wifi_scan_obj.joinWiFi(access_points->get(i).essid, String(passwordBuf), true); + } + + this->changeMenu(&wifiGeneralMenu, true); + #endif + }); + } + this->changeMenu(&wifiAPMenu, true); + } + }); + + this->addNodes(&wifiGeneralMenu, "Start AP", TFTGREEN, KEYBOARD_ICO, [this](){ + ssidsMenu.parentMenu = &wifiGeneralMenu; + + // Add the back button + ssidsMenu.list->clear(); + this->addNodes(&ssidsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(ssidsMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < ssids->size(); i++) { + // This is the menu node + this->addNodes(&ssidsMenu, ssids->get(i).essid.c_str(), TFTCYAN, 255, [this, i](){ + // Join WiFi using mini keyboard + #ifdef HAS_MINI_KB + this->changeMenu(&miniKbMenu, true); + String password = this->miniKeyboard(&miniKbMenu, true); + if (password != "") { + Serial.println("Using SSID: " + (String)ssids->get(i).essid + " Password: " + (String)password); + wifi_scan_obj.currentScanMode = LV_JOIN_WIFI; + wifi_scan_obj.StartScan(LV_JOIN_WIFI, TFT_YELLOW); + wifi_scan_obj.startWiFi(ssids->get(i).essid, password); + this->changeMenu(current_menu, true); + } + #endif + + // Join WiFi using touch screen keyboard + #ifdef HAS_TOUCH + char passwordBuf[64] = {0}; // or prefill with existing SSID + if (keyboardInput(passwordBuf, sizeof(passwordBuf), "Enter Password")) { + Serial.println("Using SSID: " + (String)ssids->get(i).essid + " Password: " + String(passwordBuf)); + wifi_scan_obj.startWiFi(ssids->get(i).essid, String(passwordBuf)); + } + + this->changeMenu(&wifiGeneralMenu, false); + #endif + }); + } + this->changeMenu(&ssidsMenu, true); + }); + + this->addNodes(&wifiGeneralMenu, "Host AP Info", TFTGREEN, BEACON_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(WIFI_SCAN_DISPLAY_AP_INFO, TFT_GREEN); + }); + + wifiStationMenu.parentMenu = &ssidsMenu; + this->addNodes(&wifiStationMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiStationMenu.parentMenu, true); + }); + + this->addNodes(&wifiGeneralMenu, "Set MACs", TFTLIGHTGREY, 0, [this]() { + this->changeMenu(&setMacMenu, true); + }); + + this->addNodes(&wifiGeneralMenu, "Shutdown WiFi", TFTRED, 0, [this]() { + WiFi.softAPdisconnect(true); // Also shut down the SoftAP if it is running + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + this->changeMenu(current_menu, true); + }); + + #ifdef HAS_DIRECT_UPLOAD + this->addNodes(&wifiGeneralMenu, "Upload Wardrive Logs", TFTGREEN, 0, [this]() { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(false); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.println("Loading..."); + + this->buildUploadFileMenu(); + + this->changeMenu(&uploadLogsMenu, true); + }); + + uploadAllMenu.parentMenu = &uploadLogsMenu; + this->addNodes(&uploadAllMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(uploadAllMenu.parentMenu, true); + }); + this->addNodes(&uploadAllMenu, "WiGLE", TFTLIGHTGREY, 0, [this]() { + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + if ((ssid == "") && (pw == "")) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("WiFi Credentials Empty."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + display_obj.clearScreen(); + display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); + if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("Could not connect to WiFi."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + delay(1000); + for (int i = 0; i < sd_obj.sd_files->size(); i++) { + if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { + if (!sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { + Serial.println("Uploading " + sd_obj.sd_files->get(i) + "..."); + if (wifi_scan_obj.uploadFile("/" + sd_obj.sd_files->get(i), true, WIGLE_UPLOAD)) { + display_obj.clearScreen(); + display_obj.showCenterText("WiGLE OK", TFT_HEIGHT / 2); + } else { + display_obj.clearScreen(); + display_obj.showCenterText("WiGLE failed", TFT_HEIGHT / 2); + } + } + } + } + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + } + } + + delay(2000); + + this->changeMenu(uploadAllMenu.parentMenu, true); + }); + this->addNodes(&uploadAllMenu, "WDGWars", TFTLIGHTGREY, 0, [this]() { + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + + if ((ssid == "") && (pw == "")) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("WiFi Credentials Empty."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + display_obj.clearScreen(); + display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); + if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("Could not connect to WiFi."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + delay(1000); + for (int i = 0; i < sd_obj.sd_files->size(); i++) { + if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { + if (!sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { + Serial.println("Uploading " + sd_obj.sd_files->get(i) + "..."); + if (wifi_scan_obj.uploadFile("/" + sd_obj.sd_files->get(i), true, WDG_UPLOAD)) { + display_obj.clearScreen(); + display_obj.showCenterText("WDG OK", TFT_HEIGHT / 2); + } else { + display_obj.clearScreen(); + display_obj.showCenterText("WDG failed", TFT_HEIGHT / 2); + } + } + } + } + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + } + } + + delay(2000); + + this->changeMenu(uploadAllMenu.parentMenu, true); + }); + this->addNodes(&uploadAllMenu, "Both", TFTLIGHTGREY, 0, [this]() { + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + + if ((ssid == "") && (pw == "")) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("WiFi Credentials Empty."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + display_obj.clearScreen(); + display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); + if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("Could not connect to WiFi."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + delay(1000); + for (int i = 0; i < sd_obj.sd_files->size(); i++) { + if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { + if (!sd_obj.sd_files->get(i).endsWith(".wigle") && !sd_obj.sd_files->get(i).endsWith(".wdg") && !sd_obj.sd_files->get(i).endsWith(".gpx")) { + Serial.println("Uploading " + sd_obj.sd_files->get(i) + "..."); + if (wifi_scan_obj.uploadFile("/" + sd_obj.sd_files->get(i), true, BOTH_UPLOAD)) { + display_obj.clearScreen(); + display_obj.showCenterText("Upload OK", TFT_HEIGHT / 2); + } else { + display_obj.clearScreen(); + display_obj.showCenterText("Upload failed", TFT_HEIGHT / 2); + } + } + } + } + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + } + } + + delay(2000); + + this->changeMenu(uploadAllMenu.parentMenu, true); + }); + + deleteAllMenu.parentMenu = &uploadLogsMenu; + this->addNodes(&deleteAllMenu, "No", TFTLIGHTGREY, 0, [this]() { + this->changeMenu(deleteAllMenu.parentMenu, true); + }); + this->addNodes(&deleteAllMenu, "Yes", TFTRED, 0, [this]() { + display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK); + + display_obj.clearScreen(); + + display_obj.showCenterText("Deleting logs...", TFT_HEIGHT / 2, true); + + for (int i = 0; i < sd_obj.sd_files->size(); i++) { + if (sd_obj.sd_files->get(i).startsWith("wardrive_") || sd_obj.sd_files->get(i).startsWith("wigle-")) { + if (sd_obj.removeFile("/" + sd_obj.sd_files->get(i))) { + Serial.println("Removed file: " + sd_obj.sd_files->get(i)); + sd_obj.removeFile("/" + sd_obj.sd_files->get(i) + ".wdg"); + sd_obj.removeFile("/" + sd_obj.sd_files->get(i) + ".wigle"); + } + else { + Serial.println("Could not remove file: " + sd_obj.sd_files->get(i)); + } + } + } + display_obj.clearScreen(); + + display_obj.showCenterText("Logs removed", TFT_HEIGHT / 2, true); + + delay(2000); + + this->buildUploadFileMenu(); + + this->changeMenu(&uploadLogsMenu, true); + }); + + actionMenu.parentMenu = &uploadLogsMenu; + this->addNodes(&actionMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(actionMenu.parentMenu, true); + }); + this->addNodes(&actionMenu, "WiGLE", TFTLIGHTGREY, 0, [this]() { + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + + if ((ssid == "") && (pw == "")) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("WiFi Credentials Empty."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + display_obj.clearScreen(); + display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); + if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.println("Could not connect to WiFi."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + delay(1000); + Serial.println("Uploading " + sd_obj.selected_file_name + "..."); + if (wifi_scan_obj.uploadFile("/" + sd_obj.selected_file_name, true, WIGLE_UPLOAD)) { + display_obj.clearScreen(); + display_obj.showCenterText("WiGLE OK", TFT_HEIGHT / 2, true); + } else { + display_obj.clearScreen(); + display_obj.showCenterText("WiGLE failed", TFT_HEIGHT / 2, true); + } + + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + } + } + + delay(2000); + + this->changeMenu(&actionMenu, true); + }); + this->addNodes(&actionMenu, "WDGWars", TFTLIGHTGREY, 0, [this]() { + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + + if ((ssid == "") && (pw == "")) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("WiFi Credentials Empty."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + display_obj.clearScreen(); + display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); + if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("Could not connect to WiFi."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + delay(1000); + Serial.println("Uploading " + sd_obj.selected_file_name + "..."); + if (wifi_scan_obj.uploadFile("/" + sd_obj.selected_file_name, true, WDG_UPLOAD)) { + display_obj.clearScreen(); + display_obj.showCenterText("WDG OK", TFT_HEIGHT / 2, true); + } else { + display_obj.clearScreen(); + display_obj.showCenterText("WDG failed", TFT_HEIGHT / 2, true); + } + + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + } + } + + delay(2000); + + this->changeMenu(&actionMenu, true); + }); + this->addNodes(&actionMenu, "Both", TFTLIGHTGREY, 0, [this]() { + String ssid = settings_obj.loadSetting("ClientSSID"); + String pw = settings_obj.loadSetting("ClientPW"); + + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + + if ((ssid == "") && (pw == "")) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("WiFi Credentials Empty."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + display_obj.clearScreen(); + display_obj.showCenterText(String("Connecting to " + ssid).c_str(), TFT_HEIGHT / 2, true); + if (!wifi_scan_obj.joinWiFi(ssid, pw, false)) { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(true); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.println("Could not connect to WiFi."); + display_obj.tft.println("Returning..."); + display_obj.tft.setTextWrap(false); + } + else { + delay(1000); + Serial.println("Uploading " + sd_obj.selected_file_name + "..."); + if (wifi_scan_obj.uploadFile("/" + sd_obj.selected_file_name, true, BOTH_UPLOAD)) { + display_obj.clearScreen(); + display_obj.showCenterText("Upload OK", TFT_HEIGHT / 2, true); + } else { + display_obj.clearScreen(); + display_obj.showCenterText("Upload failed", TFT_HEIGHT / 2, true); + } + + WiFi.disconnect(true); + delay(100); + wifi_scan_obj.StartScan(WIFI_SCAN_OFF, TFT_RED); + } + } + + delay(2000); + + this->changeMenu(&actionMenu, true); + }); + #endif + + + // Menu for generating and setting MAC addrs for AP and STA + setMacMenu.parentMenu = &wifiGeneralMenu; + this->addNodes(&setMacMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(setMacMenu.parentMenu, true); + }); + + // Generate random MAC for AP + this->addNodes(&setMacMenu, "Generate AP MAC", TFTLIME, 0, [this]() { + this->changeMenu(&genAPMacMenu, true); + wifi_scan_obj.RunGenerateRandomMac(true); + }); + + // Generate random MAC for AP + this->addNodes(&setMacMenu, "Generate STA MAC", TFTCYAN, 0, [this]() { + this->changeMenu(&genAPMacMenu, true); + wifi_scan_obj.RunGenerateRandomMac(false); + }); + + // Clone AP MAC to ESP32 for button folks + //#ifndef HAS_ILI9341 + this->addNodes(&setMacMenu, "Clone AP MAC", TFTRED, CLEAR_ICO, [this](){ + wifiAPMenu.parentMenu = &wifiGeneralMenu; + + // Add the back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < access_points->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, access_points->get(i).essid.c_str(), TFTLIME, 255, [this, i](){ + this->changeMenu(&genAPMacMenu, true); + wifi_scan_obj.RunSetMac(access_points->get(i).bssid, true); + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + + this->addNodes(&setMacMenu, "Clone STA MAC", TFTMAGENTA, CLEAR_ICO, [this](){ + wifiAPMenu.parentMenu = &wifiGeneralMenu; + + // Add the back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Populate the menu with buttons + for (int i = 0; i < stations->size(); i++) { + // This is the menu node + this->addNodes(&wifiAPMenu, macToString(stations->get(i).mac).c_str(), TFTMAGENTA, 255, [this, i](){ + this->changeMenu(&genAPMacMenu, true); + wifi_scan_obj.RunSetMac(stations->get(i).mac, false); + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + //#endif + + // Menu for generating and setting access point MAC (just goes bacK) + genAPMacMenu.parentMenu = &wifiGeneralMenu; + this->addNodes(&genAPMacMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(genAPMacMenu.parentMenu, true); + }); + + // Build generate ssids menu + generateSSIDsMenu.parentMenu = &wifiGeneralMenu; + this->addNodes(&generateSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(generateSSIDsMenu.parentMenu, true); + }); + + // Build clear ssids menu + + this->addNodes(&clearSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(clearSSIDsMenu.parentMenu, true); + }); + clearAPsMenu.parentMenu = &wifiGeneralMenu; + this->addNodes(&clearAPsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(clearAPsMenu.parentMenu, true); + }); + +#ifdef HAS_BT + // Build Bluetooth Menu + bluetoothMenu.parentMenu = &mainMenu; // Second Menu is third menu parent + this->addNodes(&bluetoothMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(bluetoothMenu.parentMenu, true); + }); + this->addNodes(&bluetoothMenu, text_table1[31], TFTYELLOW, SNIFFERS, [this]() { + this->changeMenu(&bluetoothSnifferMenu, true); + }); + this->addNodes(&bluetoothMenu, "Bluetooth Attacks", TFTRED, ATTACKS, [this]() { + this->changeMenu(&bluetoothAttackMenu, true); + }); + + // Build bluetooth sniffer Menu + bluetoothSnifferMenu.parentMenu = &bluetoothMenu; // Second Menu is third menu parent + this->addNodes(&bluetoothSnifferMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(bluetoothSnifferMenu.parentMenu, true); + }); + this->addNodes(&bluetoothSnifferMenu, text_table1[34], TFTGREEN, BLUETOOTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_ALL, TFT_GREEN); + }); + this->addNodes(&bluetoothSnifferMenu, "Flipper Sniff", TFTORANGE, FLIPPER, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_FLIPPER, TFT_ORANGE); + }); + this->addNodes(&bluetoothSnifferMenu, "FindMy Sniff", TFTWHITE, BLUETOOTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_AIRTAG, TFT_WHITE); + }); + this->addNodes(&bluetoothSnifferMenu, "FindMy Monitor", TFTWHITE, BLUETOOTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_AIRTAG_MON, TFT_WHITE); + }); + this->addNodes(&bluetoothSnifferMenu, text_table1[35], TFTMAGENTA, CC_SKIMMERS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_SKIMMERS, TFT_MAGENTA); + }); + this->addNodes(&bluetoothSnifferMenu, "Bluetooth Analyzer", TFTCYAN, PACKET_MONITOR, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + this->renderGraphUI(BT_SCAN_ANALYZER); + wifi_scan_obj.StartScan(BT_SCAN_ANALYZER, TFT_CYAN); + }); + this->addNodes(&bluetoothSnifferMenu, "Flock Sniff", TFTORANGE, FLOCK, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_FLOCK, TFT_ORANGE); + }); + this->addNodes(&bluetoothSnifferMenu, "Meta Detect", TFTWHITE, BLUETOOTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SCAN_RAYBAN, TFT_CYAN); + }); + this->addNodes(&bluetoothSnifferMenu, "Fox Hunt", TFTCYAN, SCANNERS, [this]() { + this->buildBluetoothFoxHuntMenu(); + }); + + // Bluetooth Attack menu + bluetoothAttackMenu.parentMenu = &bluetoothMenu; // Second Menu is third menu parent + this->addNodes(&bluetoothAttackMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(bluetoothAttackMenu.parentMenu, true); + }); + this->addNodes(&bluetoothAttackMenu, "Sour Apple", TFTGREEN, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_SOUR_APPLE, TFT_GREEN); + }); + this->addNodes(&bluetoothAttackMenu, "Apple Juice", TFTYELLOW, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_APPLE_JUICE, TFT_YELLOW); + }); + this->addNodes(&bluetoothAttackMenu, "Swiftpair Spam", TFTCYAN, KEYBOARD_ICO, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_SWIFTPAIR_SPAM, TFT_CYAN); + }); + this->addNodes(&bluetoothAttackMenu, "Samsung BLE Spam", TFTRED, GENERAL_APPS, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_SAMSUNG_SPAM, TFT_RED); + }); + this->addNodes(&bluetoothAttackMenu, "Google BLE Spam", TFTPURPLE, LANGUAGE, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_GOOGLE_SPAM, TFT_PURPLE); + }); + this->addNodes(&bluetoothAttackMenu, "Flipper BLE Spam", TFTORANGE, FLIPPER, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_FLIPPER_SPAM, TFT_ORANGE); + }); + this->addNodes(&bluetoothAttackMenu, "BLE Spam All", TFTMAGENTA, DEAUTH_SNIFF, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_SPAM_ALL, TFT_MAGENTA); + }); + +#endif + + //#ifndef HAS_ILI9341 + #ifdef HAS_BT + this->addNodes(&bluetoothAttackMenu, "Spoof Airtag", TFTWHITE, ATTACKS, [this](){ + wifiAPMenu.parentMenu = &bluetoothAttackMenu; + + // Clear nodes and add back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Add buttons for all airtags + // Find out how big our menu is going to be + int menu_limit; + if (airtags->size() <= BUTTON_ARRAY_LEN) + menu_limit = airtags->size(); + else + menu_limit = BUTTON_ARRAY_LEN; + + // Create the menu nodes for all of the list items + for (int i = 0; i < menu_limit; i++) { + this->addNodes(&wifiAPMenu, airtags->get(i).mac.c_str(), TFTWHITE, BLUETOOTH, [this, i](){ + AirTag new_at = airtags->get(i); + new_at.selected = true; + + airtags->set(i, new_at); + + // Set all other airtags to "Not Selected" + for (int x = 0; x < airtags->size(); x++) { + if (x != i) { + AirTag new_atx = airtags->get(x); + new_atx.selected = false; + airtags->set(x, new_atx); + } + } + + // Start the spoof + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_SPOOF_AIRTAG, TFT_WHITE); + + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + + #ifdef HAS_NIMBLE_2 + this->addNodes(&bluetoothAttackMenu, "FindMy Sound", TFTCYAN, ATTACKS, [this](){ + wifiAPMenu.parentMenu = &bluetoothAttackMenu; + + // Clear nodes and add back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + /*this->addNodes(&wifiAPMenu, "Live", TFTMAGENTA, 0, [this]() { + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.StartScan(BT_ATTACK_FINDMY_LIVE, TFT_RED); + });*/ + + int menu_limit = airtags->size(); + + // Create the menu nodes for all of the list items + for (int i = 0; i < menu_limit; i++) { + uint8_t node_color = rssiToMenuColor(airtags->get(i).rssi); + String node_name = String(airtags->get(i).rssi) + " " + airtags->get(i).mac; + this->addNodes(&wifiAPMenu, node_name.c_str(), node_color, BLUETOOTH, [this, i](){ + AirTag new_at = airtags->get(i); + new_at.selected = true; + new_at.connectable = true; + + airtags->set(i, new_at); + + // Set all other airtags to "Not Selected" + for (int x = 0; x < airtags->size(); x++) { + if (x != i) { + AirTag new_atx = airtags->get(x); + new_atx.selected = false; + airtags->set(x, new_atx); + } + } + + // Start the spoof + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.executeFindMySound(true); + delay(2000); + this->changeMenu(&wifiAPMenu, true); + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + #endif + + wifiAPMenu.parentMenu = &bluetoothAttackMenu; + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + wifiAPMenu.parentMenu = &bluetoothAttackMenu; + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + #endif + + //#endif + + // Device menu + deviceMenu.parentMenu = &mainMenu; + this->addNodes(&deviceMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(deviceMenu.parentMenu, true); + }); + + #ifdef HAS_SD + if (sd_obj.supported) { + + sdDeleteMenu.parentMenu = &deviceMenu; + + this->addNodes(&deviceMenu, "Update Firmware", TFTORANGE, SD_UPDATE, [this]() { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(false); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.println("Loading..."); + + // Clear menu and lists + this->buildSDFileMenu(true); + + this->changeMenu(&sdDeleteMenu, true); + }); + } + #endif + + this->addNodes(&deviceMenu, "Save/Load Files", TFTCYAN, SD_UPDATE, [this]() { + this->changeMenu(&saveFileMenu, true); + }); + + #ifndef HAS_MINI_SCREEN + this->addNodes(&deviceMenu, "Brightness", TFTYELLOW, BRIGHTNESS, [this]() { + this->brightnessMode(); + }); + #endif + + this->addNodes(&deviceMenu, text_table1[17], TFTWHITE, DEVICE_INFO, [this]() { + wifi_scan_obj.currentScanMode = SHOW_INFO; + this->changeMenu(&infoMenu, true); + wifi_scan_obj.RunInfo(); + }); + this->addNodes(&deviceMenu, text08, TFTBLUE, SETTINGS, [this]() { + this->changeMenu(&settingsMenu, true); + }); + + #ifdef HAS_SD + if (sd_obj.supported) { + + sdDeleteMenu.parentMenu = &deviceMenu; + + this->addNodes(&deviceMenu, "Delete SD Files", TFTCYAN, SD_UPDATE, [this]() { + display_obj.clearScreen(); + display_obj.tft.setTextWrap(false); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.println("Loading..."); + + // Clear menu and lists + this->buildSDFileMenu(); + + this->changeMenu(&sdDeleteMenu, true); + }); + } + #endif + + // Save Files Menu + saveFileMenu.parentMenu = &deviceMenu; + this->addNodes(&saveFileMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(saveFileMenu.parentMenu, true); + }); + this->addNodes(&saveFileMenu, "Save SSIDs", TFTCYAN, SD_UPDATE, [this]() { + this->changeMenu(&saveSSIDsMenu, true); + wifi_scan_obj.RunSaveSSIDList(true); + }); + this->addNodes(&saveFileMenu, "Load SSIDs", TFTSKYBLUE, SD_UPDATE, [this]() { + this->changeMenu(&loadSSIDsMenu, true); + wifi_scan_obj.RunLoadSSIDList(); + }); + this->addNodes(&saveFileMenu, "Save APs", TFTNAVY, SD_UPDATE, [this]() { + this->changeMenu(&saveAPsMenu, true); + wifi_scan_obj.RunSaveAPList(); + }); + this->addNodes(&saveFileMenu, "Load APs", TFTBLUE, SD_UPDATE, [this]() { + this->changeMenu(&loadAPsMenu, true); + wifi_scan_obj.RunLoadAPList(); + }); + this->addNodes(&saveFileMenu, "Save Airtags", TFTWHITE, SD_UPDATE, [this]() { + this->changeMenu(&saveAPsMenu, true); + wifi_scan_obj.RunSaveATList(); + }); + this->addNodes(&saveFileMenu, "Load Airtags", TFTWHITE, SD_UPDATE, [this]() { + this->changeMenu(&loadAPsMenu, true); + wifi_scan_obj.RunLoadATList(); + }); + + saveSSIDsMenu.parentMenu = &saveFileMenu; + this->addNodes(&saveSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(saveSSIDsMenu.parentMenu, true); + }); + + loadSSIDsMenu.parentMenu = &saveFileMenu; + this->addNodes(&loadSSIDsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(loadSSIDsMenu.parentMenu, true); + }); + + saveAPsMenu.parentMenu = &saveFileMenu; + this->addNodes(&saveAPsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(saveAPsMenu.parentMenu, true); + }); + + loadAPsMenu.parentMenu = &saveFileMenu; + this->addNodes(&loadAPsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(loadAPsMenu.parentMenu, true); + }); + + saveATsMenu.parentMenu = &saveFileMenu; + this->addNodes(&saveATsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(saveATsMenu.parentMenu, true); + }); + + loadATsMenu.parentMenu = &saveFileMenu; + this->addNodes(&loadATsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(loadATsMenu.parentMenu, true); + }); + + // GPS Menu + #ifdef HAS_GPS + if (gps_obj.getGpsModuleStatus()) { + gpsMenu.parentMenu = &mainMenu; // Main Menu is second menu parent + + this->addNodes(&gpsMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(gpsMenu.parentMenu, true); + }); + + this->addNodes(&gpsMenu, "GPS Data", TFTRED, GPS_MENU, [this]() { + wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_DATA; + this->changeMenu(&gpsInfoMenu, true); + wifi_scan_obj.StartScan(WIFI_SCAN_GPS_DATA, TFT_CYAN); + }); + + this->addNodes(&gpsMenu, "NMEA Stream", TFTORANGE, GPS_MENU, [this]() { + wifi_scan_obj.currentScanMode = WIFI_SCAN_GPS_NMEA; + this->changeMenu(&gpsInfoMenu, true); + wifi_scan_obj.StartScan(WIFI_SCAN_GPS_NMEA, TFT_ORANGE); + }); + + this->addNodes(&gpsMenu, "GPS Tracker", TFTGREEN, GPS_MENU, [this]() { + wifi_scan_obj.currentScanMode = GPS_TRACKER; + this->changeMenu(&gpsInfoMenu, true); + wifi_scan_obj.StartScan(GPS_TRACKER, TFT_CYAN); + }); + + this->addNodes(&gpsMenu, "GPS POI", TFTCYAN, GPS_MENU, [this]() { + wifi_scan_obj.StartScan(GPS_POI, TFT_CYAN); + wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; + this->changeMenu(&gpsPOIMenu, true); + }); + + // GPS POI Menu + gpsPOIMenu.parentMenu = &gpsMenu; + this->addNodes(&gpsPOIMenu, text09, TFTLIGHTGREY, 0, [this]() { + wifi_scan_obj.currentScanMode = GPS_POI; + wifi_scan_obj.StartScan(WIFI_SCAN_OFF); + this->changeMenu(gpsPOIMenu.parentMenu, true); + }); + this->addNodes(&gpsPOIMenu, "Mark POI", TFTCYAN, GPS_MENU, [this]() { + wifi_scan_obj.currentScanMode = GPS_POI; + display_obj.tft.setCursor(0, TFT_HEIGHT / 2); + display_obj.clearScreen(); + if (wifi_scan_obj.RunGPSInfo(true, false, true)) + display_obj.showCenterText("POI Logged", TFT_HEIGHT / 2); + else + display_obj.showCenterText("POI Log Failed", TFT_HEIGHT / 2); + wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; + delay(2000); + this->changeMenu(&gpsPOIMenu, true); + }); + + // GPS Info Menu + gpsInfoMenu.parentMenu = &gpsMenu; + this->addNodes(&gpsInfoMenu, text09, TFTLIGHTGREY, 0, [this]() { + if(wifi_scan_obj.currentScanMode != GPS_TRACKER) + wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; + wifi_scan_obj.StartScan(WIFI_SCAN_OFF); + this->changeMenu(gpsInfoMenu.parentMenu, true); + }); + } + #endif + + // Settings menu + // Device menu + settingsMenu.parentMenu = &deviceMenu; + this->addNodes(&settingsMenu, text09, TFTLIGHTGREY, 0, [this]() { + changeMenu(settingsMenu.parentMenu, true); + }); + for (int i = 0; i < settings_obj.getNumberSettings(); i++) { + String settingName = settings_obj.setting_index_to_name(i); + const char* type = this->callSetting(settingName.c_str()); + if (type && strcmp(type, "bool") == 0) { + this->addNodes(&settingsMenu, settingName.c_str(), TFTLIGHTGREY, SETTINGS, [this, i, settingName]() { + settings_obj.toggleSetting(settingName.c_str()); + this->callSetting(settingName.c_str()); + this->changeMenu(&specSettingMenu, true); + this->displaySetting(settingName.c_str(), &settingsMenu, i + 1); + wifi_scan_obj.force_pmkid = settings_obj.loadSetting(text_table4[5]); + wifi_scan_obj.force_probe = settings_obj.loadSetting(text_table4[6]); + wifi_scan_obj.save_pcap = settings_obj.loadSetting(text_table4[7]); + wifi_scan_obj.ep_deauth = settings_obj.loadSetting("EPDeauth"); + wifi_scan_obj.channel_hop = settings_obj.loadSetting("ChanHop"); + }, settings_obj.loadSetting(settingName.c_str())); + } + } + + Serial.println("Finished settings nodes"); + + // Specific setting menu + specSettingMenu.parentMenu = &settingsMenu; + addNodes(&specSettingMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(specSettingMenu.parentMenu, true); + }); + + // Web Update + updateMenu.parentMenu = &deviceMenu; + + // Failed update menu + failedUpdateMenu.parentMenu = &deviceMenu; + this->addNodes(&failedUpdateMenu, text09, TFTLIGHTGREY, 0, [this]() { + wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; + this->changeMenu(failedUpdateMenu.parentMenu, true); + }); + + // Device info menu + infoMenu.parentMenu = &deviceMenu; + this->addNodes(&infoMenu, text09, TFTLIGHTGREY, 0, [this]() { + wifi_scan_obj.currentScanMode = WIFI_SCAN_OFF; + this->changeMenu(infoMenu.parentMenu, true); + }); + + Serial.println("Changing to main menu..."); + + // Set the current menu to the mainMenu + this->changeMenu(&mainMenu, true); + + this->initTime = millis(); +} + +//#if (!defined(HAS_ILI9341) && defined(HAS_BUTTONS)) +#ifdef HAS_MINI_KB + String MenuFunctions::miniKeyboard(Menu * targetMenu, bool do_pass) { + // Prepare a char array and reset temp SSID string + extern LinkedList* ssids; + + String ret_val = ""; + + bool pressed = true; + + wifi_scan_obj.current_mini_kb_ssid = ""; + + #ifdef HAS_MINI_KB + if (c_btn.isHeld()) { + while (!c_btn.justReleased()) + delay(1); + } + #endif + + int str_len = wifi_scan_obj.alfa.length() + 1; + + char char_array[str_len]; + + wifi_scan_obj.alfa.toCharArray(char_array, str_len); + + #ifdef HAS_TOUCH + uint16_t t_x = 0, t_y = 0; + + #endif + + // Button loop until hold center button + #ifdef HAS_BUTTONS + //#if !(defined(MARAUDER_V6) || defined(MARAUDER_V6_1) || defined(MARAUDER_CYD_MICRO)) + while(true) { + // Keyboard functions for switch hardware + #ifdef HAS_MINI_KB + // Cycle char previous + #ifdef HAS_L + if ((l_btn.justPressed()) || (l_btn.isHeld())) { + pressed = true; + if (this->mini_kb_index > 0) + this->mini_kb_index--; + else + this->mini_kb_index = str_len - 2; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu); + + while (!l_btn.justReleased()) { + l_btn.justPressed(); + if (!l_btn.isHeld()) + delay(1); + else + break; + } + } + #endif + + // Cycle char next + #ifdef HAS_R + if ((r_btn.justPressed()) || (r_btn.isHeld())) { + pressed = true; + if (this->mini_kb_index < str_len - 2) + this->mini_kb_index++; + else + this->mini_kb_index = 0; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); + + while (!r_btn.justReleased()) { + r_btn.justPressed(); + if (!r_btn.isHeld()) + delay(1); + else + break; + } + } + #endif + + //// 5-WAY SWITCH STUFF + // Add character + #if (defined(HAS_D) && defined(HAS_R)) + if (d_btn.justPressed()) { + pressed = true; + wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); + while (!d_btn.justReleased()) + delay(1); + } + #endif + + // Remove character + #if (defined(HAS_U) && defined(HAS_L)) + if (u_btn.justPressed()) { + pressed = true; + wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); + while (!u_btn.justReleased()) + delay(1); + } + #endif + + //// PARTIAL SWITCH STUFF + // Advance char or add char + #if (defined(HAS_D) && !defined(HAS_R)) + if (d_btn.justPressed()) { + bool was_held = false; + pressed = true; + while(!d_btn.justReleased()) { + d_btn.justPressed(); + + // Add letter to string + if (d_btn.isHeld()) { + wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); + was_held = true; + break; + } + } + if (!was_held) { + if (this->mini_kb_index < str_len - 2) + this->mini_kb_index++; + else + this->mini_kb_index = 0; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); + } + } + #endif + + // Prev char or remove char + #if (defined(HAS_U) && !defined(HAS_L)) + if (u_btn.justPressed()) { + bool was_held = false; + pressed = true; + while(!u_btn.justReleased()) { + u_btn.justPressed(); + + // Remove letter from string + if (u_btn.isHeld()) { + wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); + was_held = true; + break; + } + } + if (!was_held) { + if (this->mini_kb_index > 0) + this->mini_kb_index--; + else + this->mini_kb_index = str_len - 2; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu); + } + } + #endif + + // Add SSID + #if defined(HAS_C) && !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + if (c_btn.justPressed()) { + while (!c_btn.justReleased()) { + c_btn.justPressed(); // Need to continue updating button hold status. My shitty library. + + // Exit + if (c_btn.isHeld()) { + this->changeMenu(targetMenu->parentMenu); + return wifi_scan_obj.current_mini_kb_ssid; + } + delay(1); + } + + if (!do_pass) { + // If we have a string, add it to list of SSIDs + if (wifi_scan_obj.current_mini_kb_ssid != "") { + pressed = true; + ssid s = {wifi_scan_obj.current_mini_kb_ssid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false}; + ssids->unshift(s); + wifi_scan_obj.current_mini_kb_ssid = ""; + } + } + } + #endif + #endif + + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + for (int i = 0; i < 95; i++) { + if ((M5CardputerKeyboard._ascii_list[i] != '(') && + (M5CardputerKeyboard._ascii_list[i] != '`')) { + if (this->isKeyPressed(M5CardputerKeyboard._ascii_list[i])) { + pressed = true; + wifi_scan_obj.current_mini_kb_ssid.concat(M5CardputerKeyboard._ascii_list[i]); + } + if (this->isKeyPressed(KEY_BACKSPACE)) { + pressed = true; + wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); + } + } + } + + if (!do_pass) { + if (this->isKeyPressed('`')) { + this->changeMenu(targetMenu->parentMenu, true); + return wifi_scan_obj.current_mini_kb_ssid; + } + + if (this->isKeyPressed('(')) { + if (!do_pass) { + if (wifi_scan_obj.current_mini_kb_ssid != "") { + pressed = true; + ssid s = {wifi_scan_obj.current_mini_kb_ssid, random(1, 12), {random(256), random(256), random(256), random(256), random(256), random(256)}, false}; + ssids->unshift(s); + wifi_scan_obj.current_mini_kb_ssid = ""; + } + } + } + } + else { + if (this->isKeyPressed('(')) { + this->changeMenu(targetMenu->parentMenu, true); + return wifi_scan_obj.current_mini_kb_ssid; + } + + if (this->isKeyPressed('`')) { + this->changeMenu(targetMenu->parentMenu, true); + return ""; + } + } + + #endif + + // Keyboard functions for touch hardware + #ifdef HAS_TOUCH + bool touched = display_obj.updateTouch(&t_x, &t_y); + + uint8_t menu_button = display_obj.menuButton(&t_x, &t_y, touched); + + // Cycle char previous + if (menu_button == UP_BUTTON) { + pressed = true; + if (this->mini_kb_index > 0) + this->mini_kb_index--; + else + this->mini_kb_index = str_len - 2; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu); + while (display_obj.updateTouch(&t_x, &t_y) > 0) + delay(1); + display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); + } + + // Cycle char next + if (menu_button == DOWN_BUTTON) { + pressed = true; + if (this->mini_kb_index < str_len - 2) + this->mini_kb_index++; + else + this->mini_kb_index = 0; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); + while (display_obj.updateTouch(&t_x, &t_y) > 0) + delay(1); + display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); + } + + //// 5-WAY SWITCH STUFF + // Add character when select button is pressed + if (menu_button == SELECT_BUTTON) { + pressed = true; + wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); + while (display_obj.updateTouch(&t_x, &t_y) > 0) + delay(1); + display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); + } + + // Remove character when select button is held + if ((display_obj.isTouchHeld()) && (display_obj.menuButton(&t_x, &t_y, touched, true) == SELECT_BUTTON)) { + pressed = true; + wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); + while (display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)) < 0) + delay(1); + } + + //// PARTIAL SWITCH STUFF + // Advance char or add char + #if (defined(HAS_D) && !defined(HAS_R)) + if (d_btn.justPressed()) { + bool was_held = false; + pressed = true; + while(!d_btn.justReleased()) { + d_btn.justPressed(); + + // Add letter to string + if (d_btn.isHeld()) { + wifi_scan_obj.current_mini_kb_ssid.concat(String(char_array[this->mini_kb_index]).c_str()); + was_held = true; + break; + } + } + if (!was_held) { + if (this->mini_kb_index < str_len - 2) + this->mini_kb_index++; + else + this->mini_kb_index = 0; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu, 0, &char_array[this->mini_kb_index]); + } + } + #endif + + // Prev char or remove char + #if (defined(HAS_U) && !defined(HAS_L)) + if (u_btn.justPressed()) { + bool was_held = false; + pressed = true; + while(!u_btn.justReleased()) { + u_btn.justPressed(); + + // Remove letter from string + if (u_btn.isHeld()) { + wifi_scan_obj.current_mini_kb_ssid.remove(wifi_scan_obj.current_mini_kb_ssid.length() - 1); + was_held = true; + break; + } + } + if (!was_held) { + if (this->mini_kb_index > 0) + this->mini_kb_index--; + else + this->mini_kb_index = str_len - 2; + + targetMenu->list->set(0, MenuNode{String(char_array[this->mini_kb_index]).c_str(), false, TFTCYAN, 0, true, NULL}); + this->buildButtons(targetMenu); + } + } + #endif + + // Exit if UP button is held + if ((display_obj.isTouchHeld()) && (display_obj.menuButton(&t_x, &t_y, touched, true) == UP_BUTTON)) { + display_obj.clearScreen(); + while (display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)) < 0) + delay(1); + + // Reset the touch keys so we don't activate the keys when we go back + display_obj.menuButton(&t_x, &t_y, display_obj.updateTouch(&t_x, &t_y)); + this->changeMenu(targetMenu->parentMenu, true); + return wifi_scan_obj.current_mini_kb_ssid; + } + + // If the screen is touched but none of the keys are used, don't refresh display + if (menu_button < 0) + pressed = false; + + #endif + + // Display info on screen + if (pressed) { + this->displayCurrentMenu(); + display_obj.tft.setTextWrap(false); + display_obj.tft.fillRect(0, SCREEN_HEIGHT / 3, SCREEN_WIDTH, STATUS_BAR_WIDTH, TFT_BLACK); + display_obj.tft.fillRect(0, SCREEN_HEIGHT / 3 + TEXT_HEIGHT * 2, SCREEN_WIDTH, STATUS_BAR_WIDTH, TFT_BLACK); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.println(wifi_scan_obj.current_mini_kb_ssid + "\n"); + display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); + + display_obj.tft.println(ssids->get(0).essid); + + display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK); + #ifdef HAS_MINI_KB + #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.println("U/D - Rem/Add Char"); + display_obj.tft.println("L/R - Prev/Nxt Char"); + #endif + if (!do_pass) { + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.println("Enter - Save"); + display_obj.tft.println("Esc - Exit"); + #else + display_obj.tft.println("C - Save"); + display_obj.tft.println("C(Hold) - Exit"); + #endif + } + else { + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.println("Enter - Enter"); + #else + display_obj.tft.println("C(Hold) - Enter"); + #endif + } + #endif + + #ifdef HAS_TOUCH + display_obj.tft.println("U/D - Prev/Nxt Char"); + display_obj.tft.println("C - Add Char"); + display_obj.tft.println("C(Hold) - Rem Char"); + display_obj.tft.println("U(Hold) - Enter"); + #endif + pressed = false; + } + } + //#endif + #endif + } +#endif + +void MenuFunctions::setupSDFileList(bool update) { + sd_obj.sd_files->clear(); + + delete sd_obj.sd_files; + + sd_obj.sd_files = new LinkedList(); + + if (!update) + sd_obj.listDirToLinkedList(sd_obj.sd_files); + else + sd_obj.listDirToLinkedList(sd_obj.sd_files, "/", ".bin"); +} + +void MenuFunctions::buildSDFileMenu(bool update) { + this->setupSDFileList(update); + + sdDeleteMenu.list->clear(); + delete sdDeleteMenu.list; + sdDeleteMenu.list = new LinkedList(); + + if (!update) + sdDeleteMenu.name = "SD Files"; + else + sdDeleteMenu.name = "Bin Files"; + + this->addNodes(&sdDeleteMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(sdDeleteMenu.parentMenu, true); + }); + + if (!update) { + this->addNodes(&sdDeleteMenu, "Delete Selected", TFTORANGE, 0, [this]() { + for (int x = 0; x < sd_obj.sd_files->size(); x++) { + if (current_menu->list->get(x + 2).selected) { + if (sd_obj.removeFile("/" + sd_obj.sd_files->get(x))) { + Serial.println("Deleted /" + sd_obj.sd_files->get(x)); + display_obj.clearScreen(); + display_obj.tft.setTextWrap(false); + display_obj.tft.setCursor(0, SCREEN_HEIGHT / 3); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.println("Deleting /" + sd_obj.sd_files->get(x) + "..."); + } + } + } + this->buildSDFileMenu(); + this->changeMenu(&sdDeleteMenu, true); + }); + } + + if (!update) { + for (int x = 0; x < sd_obj.sd_files->size(); x++) { + this->addNodes(&sdDeleteMenu, sd_obj.sd_files->get(x).c_str(), TFTCYAN, SD_UPDATE, [this, x]() { + // Change selection status of menu node + MenuNode new_node = current_menu->list->get(x + 2); + new_node.selected = !current_menu->list->get(x + 2).selected; + current_menu->list->set(x + 2, new_node); + }); + } + } + else { + for (int x = 0; x < sd_obj.sd_files->size(); x++) { + this->addNodes(&sdDeleteMenu, sd_obj.sd_files->get(x).c_str(), TFTCYAN, SD_UPDATE, [this, x]() { + wifi_scan_obj.currentScanMode = OTA_UPDATE; + this->changeMenu(&failedUpdateMenu, true); + sd_obj.runUpdate("/" + sd_obj.sd_files->get(x)); + }); + } + } +} + + +// Function to add MenuNodes to a menu +void MenuFunctions::addNodes(Menu * menu, const char* name, uint8_t color, int place, std::function callable, bool selected) +{ + //Serial.println("Building node: " + name); + menu->list->add(MenuNode{String(name), false, color, place, selected, callable}); +} + +void MenuFunctions::setGraphScale(float scale) { + this->_graph_scale = scale; +} + +float MenuFunctions::calculateGraphScale(uint8_t value) { + if ((value * this->_graph_scale < GRAPH_VERT_LIM) && (value * this->_graph_scale > GRAPH_VERT_LIM * 0.75)) { + return this->_graph_scale; // No scaling needed if the value is within the limit + } + + if (value < GRAPH_VERT_LIM) + return 1.0; + + // Calculate the multiplier proportionally + return (0.75 * GRAPH_VERT_LIM) / value; +} + +float MenuFunctions::calculateGraphScale(int16_t value) { + if ((value * this->_graph_scale < GRAPH_VERT_LIM) && (value * this->_graph_scale > GRAPH_VERT_LIM * 0.75)) { + return this->_graph_scale; // No scaling needed if the value is within the limit + } + + if (value < GRAPH_VERT_LIM) + return 1.0; + + // Calculate the multiplier proportionally + return (0.75 * GRAPH_VERT_LIM) / value; +} + +float MenuFunctions::graphScaleCheck(const int16_t array[SCREEN_WIDTH]) { + int16_t maxValue = 0; + + // Iterate through the array to find the highest value + for (int16_t i = 0; i < SCREEN_WIDTH; i++) { + if (array[i] > maxValue) { + maxValue = array[i]; + } + } + + // If the highest value exceeds GRAPH_VERT_LIM, call calculateMultiplier + if (maxValue > GRAPH_VERT_LIM) { + return this->calculateGraphScale(maxValue); + } + + // If the highest value does not exceed GRAPH_VERT_LIM, return 1.0 + return 1.0; +} + +float MenuFunctions::graphScaleCheckSmall(const uint8_t array[CHAN_PER_PAGE]) { + uint8_t maxValue = 0; + + // Iterate through the array to find the highest value + for (uint8_t i = 0; i < CHAN_PER_PAGE; i++) { + if (array[i] > maxValue) { + maxValue = array[i]; + } + } + + // If the highest value exceeds GRAPH_VERT_LIM, call calculateMultiplier + if (maxValue > GRAPH_VERT_LIM) { + return this->calculateGraphScale(maxValue); + } + + // If the highest value does not exceed GRAPH_VERT_LIM, return 1.0 + return 1.0; +} + +void MenuFunctions::drawMaxLine(int16_t value, uint16_t color) { + display_obj.tft.drawLine(0, TFT_HEIGHT - (value * this->_graph_scale), TFT_WIDTH, TFT_HEIGHT - (value * this->_graph_scale), color); + display_obj.tft.setCursor(0, TFT_HEIGHT - (value * this->_graph_scale)); + display_obj.tft.setTextColor(color, TFT_BLACK); + display_obj.tft.setTextSize(1); + display_obj.tft.println((String)(value / BASE_MULTIPLIER)); +} + +void MenuFunctions::drawMaxLine(uint8_t value, uint16_t color) { + //display_obj.tft.drawLine(0, TFT_HEIGHT - (value * this->_graph_scale), TFT_WIDTH, TFT_HEIGHT - (value * this->_graph_scale), color); + display_obj.tft.setCursor(0, TFT_HEIGHT - (value * this->_graph_scale)); + display_obj.tft.setTextColor(color, TFT_BLACK); + display_obj.tft.setTextSize(1); + display_obj.tft.println((String)value); +} + +void MenuFunctions::drawGraphSmall(uint8_t *values) { + uint8_t maxValue = 0; + //(i + (CHAN_PER_PAGE * (this->activity_page - 1))) + + int bar_width = SCREEN_WIDTH / (CHAN_PER_PAGE * 2); + //display_obj.tft.fillRect(0, TFT_HEIGHT / 2 + 1, SCREEN_WIDTH, (TFT_HEIGHT / 2) + 1, TFT_BLACK); + + #ifndef HAS_DUAL_BAND + for (int i = 1; i < CHAN_PER_PAGE + 1; i++) { + int targ_val = i + (CHAN_PER_PAGE * (wifi_scan_obj.activity_page - 1)) - 1; + int x_mult = (i * 2) - 1; + int x_coord = (SCREEN_WIDTH / (CHAN_PER_PAGE * 2)) * (x_mult - 1); + + if (values[targ_val] > maxValue) { + maxValue = values[targ_val]; + } + + if (values[targ_val] * this->_graph_scale <= GRAPH_VERT_LIM) { + display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT / 2 + 1, bar_width, SCREEN_HEIGHT / 2 + 1, TFT_BLACK); + display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT - (values[targ_val] * this->_graph_scale), bar_width, values[targ_val] * this->_graph_scale, TFT_CYAN); + } + + display_obj.tft.drawLine(x_coord - 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), x_coord - 2, SCREEN_HEIGHT, TFT_WHITE); + } + #else + for (int i = 1; i < CHAN_PER_PAGE + 1; i++) { + int targ_val = i + (CHAN_PER_PAGE * (wifi_scan_obj.activity_page - 1)) - 1; + int x_mult = (i * 2) - 1; + int x_coord = (SCREEN_WIDTH / (CHAN_PER_PAGE * 2)) * (x_mult - 1); + + if (values[targ_val] > maxValue) { + maxValue = values[targ_val]; + } + + if (values[targ_val] * this->_graph_scale <= GRAPH_VERT_LIM) { + display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT / 2 + 1, bar_width + 3, SCREEN_HEIGHT / 2 + 1, TFT_BLACK); + display_obj.tft.fillRect(x_coord, SCREEN_HEIGHT - (values[targ_val] * this->_graph_scale), bar_width, values[targ_val] * this->_graph_scale, TFT_CYAN); + } + + display_obj.tft.drawLine(x_coord - 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), x_coord - 2, SCREEN_HEIGHT, TFT_WHITE); + } + #endif + + this->drawMaxLine(maxValue, TFT_GREEN); // Draw max +} + +void MenuFunctions::drawGraph(int16_t *values) { + #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + int width = TFT_WIDTH; + #else + int width = SCREEN_WIDTH; + #endif + + int16_t maxValue = 0; + int total = 0; + for (int i = width - 1; i >= 0; i--) { + if (values[i] >= 0) { + total = total + values[i]; + if (values[i] > maxValue) { + maxValue = values[i]; + } + #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - GRAPH_VERT_LIM, TFT_BLACK); + display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - (values[i] * this->_graph_scale), TFT_CYAN); + #else + display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - GRAPH_VERT_LIM, TFT_BLACK); + display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - (values[i] * this->_graph_scale), TFT_CYAN); + display_obj.tft.setCursor(0, 0); + display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); + #endif + } + else { + int16_t ch_val = values[i] * -1; + #if !defined(MARAUDER_CARDPUTER) && !defined(MARAUDER_CARDPUTER_ADV) + display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - GRAPH_VERT_LIM, TFT_BLACK); + display_obj.tft.drawLine(i, TFT_HEIGHT, i, TFT_HEIGHT - GRAPH_VERT_LIM, TFT_RED); + display_obj.tft.setCursor(i, TFT_HEIGHT - GRAPH_VERT_LIM); + #else + display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - GRAPH_VERT_LIM, TFT_BLACK); + display_obj.tft.drawLine(i, TFT_WIDTH, i, TFT_WIDTH - GRAPH_VERT_LIM, TFT_RED); + display_obj.tft.setCursor(i, TFT_WIDTH - GRAPH_VERT_LIM); + #endif + display_obj.tft.setTextColor(TFT_BLACK, TFT_RED); + display_obj.tft.setTextSize(1); + display_obj.tft.println((String)ch_val); + } + } + + this->drawMaxLine(maxValue, TFT_GREEN); // Draw max + this->drawMaxLine((int16_t)(total / TFT_WIDTH), TFT_ORANGE); // Draw average +} + +void MenuFunctions::renderGraphUI(uint8_t scan_mode) { + display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); + if (scan_mode == WIFI_SCAN_CHAN_ANALYZER) + display_obj.tft.drawCentreString("Frames/" + (String)BANNER_TIME + "ms", SCREEN_WIDTH / 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), 1); + else if (scan_mode == BT_SCAN_ANALYZER) + display_obj.tft.drawCentreString("BLE Beacons/" + (String)BANNER_TIME + "ms", SCREEN_WIDTH / 2, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 2), 1); + display_obj.tft.drawLine(0, SCREEN_HEIGHT - GRAPH_VERT_LIM - 1, SCREEN_WIDTH, SCREEN_HEIGHT - GRAPH_VERT_LIM - 1, TFT_WHITE); + display_obj.tft.setCursor(0, SCREEN_HEIGHT - GRAPH_VERT_LIM - (CHAR_WIDTH * 8)); + display_obj.tft.setTextSize(1); + display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK); + display_obj.tft.println("Max"); + display_obj.tft.setTextColor(TFT_ORANGE, TFT_BLACK); + display_obj.tft.println("Average"); + display_obj.tft.setTextColor(TFT_RED, TFT_BLACK); + if (scan_mode != BT_SCAN_ANALYZER) + display_obj.tft.println("Channel Marker"); +} + +uint16_t MenuFunctions::getColor(uint16_t color) { + if (color == TFTWHITE) return TFT_WHITE; + else if (color == TFTCYAN) return TFT_CYAN; + else if (color == TFTBLUE) return TFT_BLUE; + else if (color == TFTRED) return TFT_RED; + else if (color == TFTGREEN) return TFT_GREEN; + else if (color == TFTGREY) return TFT_LIGHTGREY; + else if (color == TFTGRAY) return TFT_LIGHTGREY; + else if (color == TFTMAGENTA) return TFT_MAGENTA; + else if (color == TFTVIOLET) return TFT_VIOLET; + else if (color == TFTORANGE) return TFT_ORANGE; + else if (color == TFTYELLOW) return TFT_YELLOW; + else if (color == TFTLIGHTGREY) return TFT_LIGHTGREY; + else if (color == TFTPURPLE) return TFT_PURPLE; + else if (color == TFTNAVY) return TFT_NAVY; + else if (color == TFTSILVER) return TFT_SILVER; + else if (color == TFTDARKGREY) return TFT_DARKGREY; + else if (color == TFTSKYBLUE) return TFT_SKYBLUE; + else if (color == TFTLIME) return 0x97e0; + else return color; +} + +// Function to change menu +void MenuFunctions::changeMenu(Menu* menu, bool simple_change) { + if (!simple_change) { + //display_obj.initScrollValues(); + //display_obj.setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA); + display_obj.init(); + + #ifdef HAS_ILI9341 + extern void backlightOn(); + backlightOn(); + #endif + } + current_menu = menu; + + current_menu->selected = 0; + + buildButtons(menu); + + displayCurrentMenu(); + + //#ifdef MARAUDER_V8 + // digitalWrite(TFT_BL, HIGH); + //#endif +} + +void MenuFunctions::buildButtons(Menu *menu, int starting_index, const char* button_name) { + if (menu->list == NULL || menu->list->size() == 0) + return; + + if (starting_index >= menu->list->size()) + starting_index = menu->list->size() - BUTTON_SCREEN_LIMIT; + if (starting_index < 0) + starting_index = 0; + + this->menu_start_index = starting_index; + + uint8_t visible_buttons = min(BUTTON_SCREEN_LIMIT, menu->list->size() - starting_index); + + for (uint8_t i = 0; i < visible_buttons; i++) { + MenuNode node = menu->list->get(starting_index + i); + uint16_t color = (node.icon == SETTINGS && node.color == TFTLIGHTGREY) ? (node.selected ? TFT_GREEN : TFT_RED) : this->getColor(node.color); + + char buf[64]; + + if (button_name != nullptr && button_name[0] != '\0') { + strncpy(buf, button_name, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } else { + node.name.toCharArray(buf, sizeof(buf)); + } + + display_obj.key[i].initButton(&display_obj.tft, + KEY_X, + KEY_Y + i * (KEY_H + KEY_SPACING_Y), + KEY_W, + KEY_H, + TFT_BLACK, + TFT_BLACK, + color, + buf, + KEY_TEXTSIZE); + + #if defined(MARAUDER_CARDPUTER) || defined(MARAUDER_CARDPUTER_ADV) + display_obj.key[i].setLabelDatum(BUTTON_PADDING - (KEY_W / 2), 4, ML_DATUM); + #else + display_obj.key[i].setLabelDatum(BUTTON_PADDING - (KEY_W / 2), 2, ML_DATUM); + #endif + } + + for (int i = BUTTON_ARRAY_LEN; i < BUTTON_ARRAY_LEN + 3; i++) { + uint16_t x = TFT_WIDTH / 2; + uint16_t y = TFT_HEIGHT / 3 * (i - BUTTON_ARRAY_LEN) + ((TFT_HEIGHT / 3) / 2); + uint16_t w = TFT_WIDTH; + uint16_t h = TFT_HEIGHT / 3 - 1; + + display_obj.key[i].initButton(&display_obj.tft, + x, + y, + w, + h, + TFT_LIGHTGREY, + TFT_BLACK, + TFT_BLACK, + "Chicken", + 1); + } +} + +void MenuFunctions::displayCurrentMenu(int start_index) +{ + //Serial.println(F("Displaying current menu...")); + display_obj.clearScreen(); + display_obj.updateBanner(current_menu->name); + display_obj.tft.setTextColor(TFT_LIGHTGREY, TFT_DARKGREY); + this->drawStatusBar(); + + if (current_menu->list != NULL) + { + #ifdef HAS_FULL_SCREEN + display_obj.tft.setFreeFont(MENU_FONT); + #endif + + #ifdef HAS_MINI_SCREEN + display_obj.tft.setFreeFont(NULL); + display_obj.tft.setTextSize(1); + #endif + + for (uint16_t i = start_index; i < min(start_index + BUTTON_SCREEN_LIMIT, current_menu->list->size()); i++) + { + if (!current_menu || !current_menu->list || i >= current_menu->list->size()) + continue; + uint16_t color = this->getColor(current_menu->list->get(i).color); + #ifdef HAS_FULL_SCREEN + bool is_setting_node = (current_menu->list->get(i).icon == SETTINGS && current_menu->list->get(i).color == TFTLIGHTGREY); + if (is_setting_node && current_menu->selected == i) { + uint16_t setting_color = current_menu->list->get(i).selected ? TFT_GREEN : TFT_RED; + display_obj.key[i - start_index].initButton(&display_obj.tft, KEY_X, KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y), KEY_W, KEY_H, TFT_BLACK, TFT_LIGHTGREY, setting_color, (char*)"", KEY_TEXTSIZE); + display_obj.key[i - start_index].drawButton(false, current_menu->list->get(i).name); + display_obj.tft.drawXBitmap(0, + KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2), + menu_icons[current_menu->list->get(i).icon], + ICON_W, + ICON_H, + TFT_BLACK, + TFT_LIGHTGREY); + } else if ((!is_setting_node && current_menu->list->get(i).selected) || (current_menu->selected == i)) { + display_obj.key[i - start_index].drawButton(true, current_menu->list->get(i).name); + if ((current_menu->list->get(i).name != text09) && (current_menu->list->get(i).icon != 255)) + display_obj.tft.drawXBitmap(0, + KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2), + menu_icons[current_menu->list->get(i).icon], + ICON_W, + ICON_H, + TFT_BLACK, + color); + } else { + display_obj.key[i - start_index].drawButton(false, current_menu->list->get(i).name); + if ((current_menu->list->get(i).name != text09) && (current_menu->list->get(i).icon != 255)) + display_obj.tft.drawXBitmap(0, + KEY_Y + (i - start_index) * (KEY_H + KEY_SPACING_Y) - (ICON_H / 2), + menu_icons[current_menu->list->get(i).icon], + ICON_W, + ICON_H, + TFT_BLACK, + is_setting_node ? TFT_LIGHTGREY : color); + } + + #endif + + #ifdef HAS_MINI_SCREEN + if ((current_menu->selected == i) || ((current_menu->list->get(i).icon != SETTINGS || current_menu->list->get(i).color != TFTLIGHTGREY) && current_menu->list->get(i).selected)) + this->drawMiniMenuButton(i - start_index, i, true); + else + this->drawMiniMenuButton(i - start_index, i, false); + #endif + } + display_obj.tft.setFreeFont(NULL); + } + + this->displayMenuButtons(); +} + +// ============================================================ +// BRIGHTNESS ADJUSTMENT MODE +// Hold top/bottom zone 1.5s to enter. TAP TOP = brighter, TAP BOTTOM = dimmer. +// TAP MIDDLE or wait 3s = save & exit. +// ============================================================ +#ifndef HAS_MINI_SCREEN + void MenuFunctions::brightnessMode() { + extern void brightnessSave(uint8_t level); + extern uint8_t getBrightnessLevel(); + + const uint8_t levels[] = {26, 51, 77, 102, 128, 153, 179, 204, 230, 255}; + const uint8_t numLevels = 10; + uint8_t level = getBrightnessLevel(); + + // LEDC write compatibility (2.x vs 3.x board package) + #if ESP_ARDUINO_VERSION_MAJOR >= 3 + #define BL_PREVIEW(duty) ledcWrite(TFT_BL, (duty)) + #else + #define BL_PREVIEW(duty) ledcWrite(0, (duty)) + #endif + + display_obj.tft.fillScreen(TFT_BLACK); + display_obj.tft.setTextColor(TFT_CYAN, TFT_BLACK); + display_obj.tft.drawCentreString("BRIGHTNESS", TFT_WIDTH/2, 30, 2); + + display_obj.tft.setTextColor(TFT_DARKGREY, TFT_BLACK); + display_obj.tft.drawCentreString("TAP TOP = BRIGHTER", TFT_WIDTH/2, 10, 1); + display_obj.tft.drawCentreString("TAP BOTTOM = DIMMER", TFT_WIDTH/2, TFT_HEIGHT - 20, 1); + display_obj.tft.setTextColor(TFT_RED, TFT_BLACK); + display_obj.tft.drawCentreString("TAP MIDDLE or WAIT 3s = SAVE", TFT_WIDTH/2, TFT_HEIGHT/2 + 50, 1); + + auto drawBar = [&]() { + uint16_t barX = 30, barY = TFT_HEIGHT/2 - 25, barW = TFT_WIDTH - 60, barH = 30; + display_obj.tft.drawRect(barX, barY, barW, barH, TFT_WHITE); + uint16_t fillW = (barW - 4) * (level + 1) / numLevels; + display_obj.tft.fillRect(barX + 2, barY + 2, barW - 4, barH - 4, TFT_BLACK); + display_obj.tft.fillRect(barX + 2, barY + 2, fillW, barH - 4, TFT_CYAN); + display_obj.tft.fillRect(0, barY + barH + 5, TFT_WIDTH, 20, TFT_BLACK); + display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK); + String pct = String(levels[level] * 100 / 255) + "%"; + display_obj.tft.drawCentreString(pct, TFT_WIDTH/2, barY + barH + 8, 2); + }; + drawBar(); + + uint16_t zoneUp = TFT_HEIGHT * 25 / 100; + uint16_t zoneDown = TFT_HEIGHT * 75 / 100; + uint32_t lastTouch = millis(); + + while (true) { + // Auto-save after 3s of no touch + if (millis() - lastTouch >= 3000) { + brightnessSave(level); + break; + } + + uint16_t tx, ty; + if (display_obj.updateTouch(&tx, &ty)) { + lastTouch = millis(); + // Wait for release + while (display_obj.updateTouch(&tx, &ty)) delay(10); + + if (ty < zoneUp) { + if (level < numLevels - 1) { + level++; + BL_PREVIEW(levels[level]); + drawBar(); + } + } else if (ty >= zoneDown) { + if (level > 0) { + level--; + BL_PREVIEW(levels[level]); + drawBar(); + } + } else { + // Middle = save now + brightnessSave(level); + break; + } + delay(150); + } + delay(30); + } + + #undef BL_PREVIEW + this->changeMenu(current_menu, true); + } +#endif + +#endif + + + From 29a93d76439efb3fa3f732d0fe4eb30232a01bae Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:29:59 -0400 Subject: [PATCH 47/57] test: exclude hardware ARP entry points from host coverage --- esp32_marauder/CommandLine.cpp | 2 ++ esp32_marauder/MenuFunctions.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/esp32_marauder/CommandLine.cpp b/esp32_marauder/CommandLine.cpp index 09c61a850..30a242829 100644 --- a/esp32_marauder/CommandLine.cpp +++ b/esp32_marauder/CommandLine.cpp @@ -1289,9 +1289,11 @@ void CommandLine::runCommand(String input) { this->startScanFromCLI(WIFI_PING_SCAN, TFT_GREEN, "Ping Scan"); } + // GCOVR_EXCL_START -- command dispatch requires the firmware CLI runtime. if (cmd_args.get(0) == ARP_SCAN_CMD) { this->startScanFromCLI(WIFI_ARP_SCAN, TFT_CYAN, "ARP Scan"); } + // GCOVR_EXCL_STOP // GPS POI if (cmd_args.get(0) == GPS_POI_CMD) { diff --git a/esp32_marauder/MenuFunctions.cpp b/esp32_marauder/MenuFunctions.cpp index 8e74594f8..4a9087f64 100644 --- a/esp32_marauder/MenuFunctions.cpp +++ b/esp32_marauder/MenuFunctions.cpp @@ -2002,11 +2002,13 @@ void MenuFunctions::RunSetup() this->drawStatusBar(); wifi_scan_obj.StartScan(WIFI_PING_SCAN, TFT_CYAN); }); + // GCOVR_EXCL_START -- scanner menu wiring requires the hardware UI. this->addNodes(&wifiScannerMenu, "ARP Scan", TFTCYAN, SCANNERS, [this]() { display_obj.clearScreen(); this->drawStatusBar(); wifi_scan_obj.StartScan(WIFI_ARP_SCAN, TFT_CYAN); }); + // GCOVR_EXCL_STOP this->addNodes(&wifiScannerMenu, "Port Scan All", TFTMAGENTA, BEACON_LIST, [this](){ // Add the back button wifiIPMenu.list->clear(); From 4c6b3a7dbc399136b56844a83568ab3b4c4f61e0 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:47:08 -0400 Subject: [PATCH 48/57] fix: lock lwIP core during C5 ARP operations --- esp32_marauder/WiFiScan.cpp | 40 +++++++++++++++++++++++++++---------- esp32_marauder/WiFiScan.h | 1 + 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 0720af6e0..b714e6702 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10572,6 +10572,33 @@ static struct netif* getStationLwipNetif() { #endif } +static bool findStationARP(struct netif* station, const ip4_addr_t* ip) { + const ip4_addr_t* resolved_ip = nullptr; + struct eth_addr* resolved_mac = nullptr; + + #ifdef HAS_IDF_3 + LOCK_TCPIP_CORE(); + #endif + const bool found = etharp_find_addr(station, ip, &resolved_mac, &resolved_ip) >= 0; + #ifdef HAS_IDF_3 + UNLOCK_TCPIP_CORE(); + #endif + + return found; +} + +static err_t requestStationARP(struct netif* station, const ip4_addr_t* ip) { + #ifdef HAS_IDF_3 + LOCK_TCPIP_CORE(); + #endif + const err_t result = etharp_request(station, ip); + #ifdef HAS_IDF_3 + UNLOCK_TCPIP_CORE(); + #endif + + return result; +} + bool WiFiScan::readARP(IPAddress targ_ip) { // Convert IPAddress to ip4_addr_t using IP4_ADDR ip4_addr_t test_ip; @@ -10581,14 +10608,7 @@ static struct netif* getStationLwipNetif() { if (netif_interface == nullptr) return false; - const ip4_addr_t* ipaddr_ret = NULL; - struct eth_addr* eth_ret = NULL; - - if (etharp_find_addr(netif_interface, &test_ip, ð_ret, &ipaddr_ret) >= 0) { - return true; - } - - return false; + return findStationARP(netif_interface, &test_ip); } bool WiFiScan::singleARP(IPAddress ip_addr) { @@ -10603,7 +10623,7 @@ static struct netif* getStationLwipNetif() { ip_addr[2], ip_addr[3]); - etharp_request(netif_interface, &lwip_ip); + requestStationARP(netif_interface, &lwip_ip); delay(250); @@ -10632,7 +10652,7 @@ static struct netif* getStationLwipNetif() { this->current_scan_ip[2], this->current_scan_ip[3]); - etharp_request(netif_interface, &lwip_ip); + requestStationARP(netif_interface, &lwip_ip); delay(100); diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index a46b5b4aa..aac2198d6 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef HAS_IDF_3 #include "esp_netif.h" #include "esp_netif_net_stack.h" From 5be4913bc73bbc77f719140243e9952b6747a546 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:27:33 -0400 Subject: [PATCH 49/57] fix: use ARP discovery for service scans on C5 --- esp32_marauder/WiFiScan.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index b714e6702..57b7c8b61 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10767,11 +10767,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { if (this->current_scan_ip == IPAddress(0, 0, 0, 0)) { return; } - #ifndef HAS_IDF_3 - if (this->singleARP(this->current_scan_ip)) { - #else - if (this->isHostAlive(this->current_scan_ip)) { - #endif + if (this->singleARP(this->current_scan_ip)) { Serial.println(this->current_scan_ip); this->portScan(scan_mode, targ_port); } From a90f8b71f6eb8d59cda5360ef8fc9d13af923e05 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:36:03 -0400 Subject: [PATCH 50/57] refactor: reuse station ARP lookup state --- esp32_marauder/WiFiScan.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 57b7c8b61..04740d503 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10626,11 +10626,7 @@ static err_t requestStationARP(struct netif* station, const ip4_addr_t* ip) { requestStationARP(netif_interface, &lwip_ip); delay(250); - - if (this->readARP(ip_addr)) - return true; - - return false; + return findStationARP(netif_interface, &lwip_ip); } void WiFiScan::fullARP() { From 49bb27df9321ae13c6a43edfa19035704d3c9161 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:44:03 -0400 Subject: [PATCH 51/57] refactor: inline single-host ARP probe --- esp32_marauder/WiFiScan.cpp | 8 +++----- esp32_marauder/WiFiScan.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 04740d503..9442b1222 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10587,16 +10587,14 @@ static bool findStationARP(struct netif* station, const ip4_addr_t* ip) { return found; } -static err_t requestStationARP(struct netif* station, const ip4_addr_t* ip) { +static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { #ifdef HAS_IDF_3 LOCK_TCPIP_CORE(); #endif - const err_t result = etharp_request(station, ip); + etharp_request(station, ip); #ifdef HAS_IDF_3 UNLOCK_TCPIP_CORE(); #endif - - return result; } bool WiFiScan::readARP(IPAddress targ_ip) { @@ -10611,7 +10609,7 @@ static err_t requestStationARP(struct netif* station, const ip4_addr_t* ip) { return findStationARP(netif_interface, &test_ip); } - bool WiFiScan::singleARP(IPAddress ip_addr) { + inline __attribute__((always_inline)) bool WiFiScan::singleARP(IPAddress ip_addr) { struct netif* netif_interface = getStationLwipNetif(); if (netif_interface == nullptr) return false; diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index aac2198d6..0b931c18c 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -718,7 +718,7 @@ class WiFiScan void setNetworkInfo(); void fullARP(); bool readARP(IPAddress targ_ip); - bool singleARP(IPAddress ip_addr); + inline __attribute__((always_inline)) bool singleARP(IPAddress ip_addr); void pingScan(uint8_t scan_mode = WIFI_PING_SCAN); void portScan(uint8_t scan_mode = WIFI_PORT_SCAN_ALL, uint16_t targ_port = 22); IPAddress advanceScanIP(); From 278e3c2e5166fde2cb1f4ac3e1fe3c022a9a7310 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:51:04 -0400 Subject: [PATCH 52/57] refactor: reuse active station for ARP cache reads --- esp32_marauder/WiFiScan.cpp | 22 ++++++++-------------- esp32_marauder/WiFiScan.h | 1 - 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 9442b1222..36df32be4 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10587,6 +10587,12 @@ static bool findStationARP(struct netif* station, const ip4_addr_t* ip) { return found; } +static bool findStationARP(struct netif* station, IPAddress ip) { + ip4_addr_t lwip_ip; + IP4_ADDR(&lwip_ip, ip[0], ip[1], ip[2], ip[3]); + return findStationARP(station, &lwip_ip); +} + static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { #ifdef HAS_IDF_3 LOCK_TCPIP_CORE(); @@ -10597,18 +10603,6 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { #endif } - bool WiFiScan::readARP(IPAddress targ_ip) { - // Convert IPAddress to ip4_addr_t using IP4_ADDR - ip4_addr_t test_ip; - IP4_ADDR(&test_ip, targ_ip[0], targ_ip[1], targ_ip[2], targ_ip[3]); - - struct netif* netif_interface = getStationLwipNetif(); - if (netif_interface == nullptr) - return false; - - return findStationARP(netif_interface, &test_ip); - } - inline __attribute__((always_inline)) bool WiFiScan::singleARP(IPAddress ip_addr) { struct netif* netif_interface = getStationLwipNetif(); if (netif_interface == nullptr) @@ -10661,7 +10655,7 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { IPAddress check_ip = getPrevIP(this->current_scan_ip, this->subnet, i); display_string = ""; output_line = ""; - if (this->readARP(check_ip)) { + if (findStationARP(netif_interface, check_ip)) { ipList->add(check_ip); output_line = check_ip.toString(); display_string.concat(output_line); @@ -10688,7 +10682,7 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { IPAddress check_ip = getPrevIP(this->last_scan_ip, this->subnet, i - 1); display_string = ""; output_line = ""; - if (this->readARP(check_ip)) { + if (findStationARP(netif_interface, check_ip)) { ipList->add(check_ip); output_line = check_ip.toString(); display_string.concat(output_line); diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index 0b931c18c..dc211c984 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -717,7 +717,6 @@ class WiFiScan void finishNetworkScanDisplay(const String& result_label); void setNetworkInfo(); void fullARP(); - bool readARP(IPAddress targ_ip); inline __attribute__((always_inline)) bool singleARP(IPAddress ip_addr); void pingScan(uint8_t scan_mode = WIFI_PING_SCAN); void portScan(uint8_t scan_mode = WIFI_PORT_SCAN_ALL, uint16_t targ_port = 22); From 894ba3cbcccdecb792b6d541a27189bf094923a2 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:59:31 -0400 Subject: [PATCH 53/57] refactor: trim redundant C5 scan work --- esp32_marauder/WiFiScan.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 36df32be4..bf1882882 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10558,11 +10558,8 @@ IPAddress WiFiScan::advanceScanIP() { // GCOVR_EXCL_START -- ARP discovery requires a live lwIP station interface. static struct netif* getStationLwipNetif() { #ifdef HAS_IDF_3 - esp_netif_t* station = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); - if (station == nullptr) - return nullptr; - - return static_cast(esp_netif_get_netif_impl(station)); + return static_cast( + esp_netif_get_netif_impl(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"))); #else void* station = nullptr; if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &station) != ESP_OK) @@ -10756,7 +10753,6 @@ void WiFiScan::pingScan(uint8_t scan_mode) { return; } if (this->singleARP(this->current_scan_ip)) { - Serial.println(this->current_scan_ip); this->portScan(scan_mode, targ_port); } } From 48f42fb3610d1a7ab5fa04bfc46f0098b16c9763 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:07:09 -0400 Subject: [PATCH 54/57] refactor: compact service scan iteration --- esp32_marauder/WiFiScan.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index bf1882882..aba9c43f7 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10748,11 +10748,8 @@ void WiFiScan::pingScan(uint8_t scan_mode) { targ_port = 3389; if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { - this->advanceScanIP(); - if (this->current_scan_ip == IPAddress(0, 0, 0, 0)) { - return; - } - if (this->singleARP(this->current_scan_ip)) { + if ((this->advanceScanIP() != IPAddress(0, 0, 0, 0)) && + this->singleARP(this->current_scan_ip)) { this->portScan(scan_mode, targ_port); } } From 1e45ef4d8e5423de10f629f370d1254d9f63718e Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:15:03 -0400 Subject: [PATCH 55/57] refactor: consolidate ARP result reporting --- esp32_marauder/WiFiScan.cpp | 43 +++++++++---------------------------- esp32_marauder/WiFiScan.h | 1 + 2 files changed, 11 insertions(+), 33 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index aba9c43f7..5ffa03b0a 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10618,10 +10618,15 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { return findStationARP(netif_interface, &lwip_ip); } - void WiFiScan::fullARP() { - String display_string = ""; - String output_line = ""; + void WiFiScan::recordARPResult(IPAddress ip_addr) { + ipList->add(ip_addr); + String output_line = ip_addr.toString(); + this->addNetworkScanDisplayResult(String("UP ") + output_line); + buffer_obj.append(output_line + "\n"); + Serial.println(output_line); + } + void WiFiScan::fullARP() { struct netif* netif_interface = getStationLwipNetif(); if (netif_interface == nullptr) return; @@ -10650,22 +10655,8 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { for (int i = 9; i >= 0; i--) { IPAddress check_ip = getPrevIP(this->current_scan_ip, this->subnet, i); - display_string = ""; - output_line = ""; if (findStationARP(netif_interface, check_ip)) { - ipList->add(check_ip); - output_line = check_ip.toString(); - display_string.concat(output_line); - uint8_t temp_len = display_string.length(); - for (uint8_t i = 0; i < 40 - temp_len; i++) - { - display_string.concat(" "); - } - #ifdef HAS_SCREEN - display_obj.display_buffer->add(display_string); - #endif - buffer_obj.append(output_line + "\n"); - Serial.println(output_line); + this->recordARPResult(check_ip); } } } @@ -10677,22 +10668,8 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { delay(250); IPAddress check_ip = getPrevIP(this->last_scan_ip, this->subnet, i - 1); - display_string = ""; - output_line = ""; if (findStationARP(netif_interface, check_ip)) { - ipList->add(check_ip); - output_line = check_ip.toString(); - display_string.concat(output_line); - uint8_t temp_len = display_string.length(); - for (uint8_t i = 0; i < 40 - temp_len; i++) - { - display_string.concat(" "); - } - #ifdef HAS_SCREEN - display_obj.display_buffer->add(display_string); - #endif - buffer_obj.append(output_line + "\n"); - Serial.println(output_line); + this->recordARPResult(check_ip); } } this->arp_count = 0; diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index dc211c984..b762a9881 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -717,6 +717,7 @@ class WiFiScan void finishNetworkScanDisplay(const String& result_label); void setNetworkInfo(); void fullARP(); + void recordARPResult(IPAddress ip_addr); inline __attribute__((always_inline)) bool singleARP(IPAddress ip_addr); void pingScan(uint8_t scan_mode = WIFI_PING_SCAN); void portScan(uint8_t scan_mode = WIFI_PORT_SCAN_ALL, uint16_t targ_port = 22); From ed6e8ee37208347245f12bc7e062d1fcc89274a3 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:22:52 -0400 Subject: [PATCH 56/57] test: exclude live ARP service discovery from host coverage --- esp32_marauder/WiFiScan.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 5ffa03b0a..61554cf5f 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10724,6 +10724,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { else if (scan_mode == WIFI_SCAN_RDP) targ_port = 3389; + // GCOVR_EXCL_START -- service discovery requires a live lwIP station interface. if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { if ((this->advanceScanIP() != IPAddress(0, 0, 0, 0)) && this->singleARP(this->current_scan_ip)) { @@ -10736,6 +10737,7 @@ void WiFiScan::pingScan(uint8_t scan_mode) { this->finishNetworkScanDisplay("hosts open"); // GCOVR_EXCL_LINE } } + // GCOVR_EXCL_STOP } } From c1d575b97f56383b1934a632d9bf1b0fb8bdc9f2 Mon Sep 17 00:00:00 2001 From: Just Call Me Koko <25190487+justcallmekoko@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:36:41 -0400 Subject: [PATCH 57/57] refactor: restore clear ARP scan implementation --- esp32_marauder/WiFiScan.cpp | 91 +++++++++++++++++++++++++++---------- esp32_marauder/WiFiScan.h | 4 +- 2 files changed, 68 insertions(+), 27 deletions(-) diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 61554cf5f..dcf4e22f5 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -10558,8 +10558,11 @@ IPAddress WiFiScan::advanceScanIP() { // GCOVR_EXCL_START -- ARP discovery requires a live lwIP station interface. static struct netif* getStationLwipNetif() { #ifdef HAS_IDF_3 - return static_cast( - esp_netif_get_netif_impl(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"))); + esp_netif_t* station = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (station == nullptr) + return nullptr; + + return static_cast(esp_netif_get_netif_impl(station)); #else void* station = nullptr; if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &station) != ESP_OK) @@ -10584,23 +10587,30 @@ static bool findStationARP(struct netif* station, const ip4_addr_t* ip) { return found; } -static bool findStationARP(struct netif* station, IPAddress ip) { - ip4_addr_t lwip_ip; - IP4_ADDR(&lwip_ip, ip[0], ip[1], ip[2], ip[3]); - return findStationARP(station, &lwip_ip); -} - -static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { +static err_t requestStationARP(struct netif* station, const ip4_addr_t* ip) { #ifdef HAS_IDF_3 LOCK_TCPIP_CORE(); #endif - etharp_request(station, ip); + const err_t result = etharp_request(station, ip); #ifdef HAS_IDF_3 UNLOCK_TCPIP_CORE(); #endif + + return result; } - inline __attribute__((always_inline)) bool WiFiScan::singleARP(IPAddress ip_addr) { + bool WiFiScan::readARP(IPAddress targ_ip) { + ip4_addr_t test_ip; + IP4_ADDR(&test_ip, targ_ip[0], targ_ip[1], targ_ip[2], targ_ip[3]); + + struct netif* netif_interface = getStationLwipNetif(); + if (netif_interface == nullptr) + return false; + + return findStationARP(netif_interface, &test_ip); + } + + bool WiFiScan::singleARP(IPAddress ip_addr) { struct netif* netif_interface = getStationLwipNetif(); if (netif_interface == nullptr) return false; @@ -10615,18 +10625,17 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { requestStationARP(netif_interface, &lwip_ip); delay(250); - return findStationARP(netif_interface, &lwip_ip); - } - void WiFiScan::recordARPResult(IPAddress ip_addr) { - ipList->add(ip_addr); - String output_line = ip_addr.toString(); - this->addNetworkScanDisplayResult(String("UP ") + output_line); - buffer_obj.append(output_line + "\n"); - Serial.println(output_line); + if (this->readARP(ip_addr)) + return true; + + return false; } void WiFiScan::fullARP() { + String display_string = ""; + String output_line = ""; + struct netif* netif_interface = getStationLwipNetif(); if (netif_interface == nullptr) return; @@ -10655,8 +10664,22 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { for (int i = 9; i >= 0; i--) { IPAddress check_ip = getPrevIP(this->current_scan_ip, this->subnet, i); - if (findStationARP(netif_interface, check_ip)) { - this->recordARPResult(check_ip); + display_string = ""; + output_line = ""; + if (this->readARP(check_ip)) { + ipList->add(check_ip); + output_line = check_ip.toString(); + display_string.concat(output_line); + uint8_t temp_len = display_string.length(); + for (uint8_t i = 0; i < 40 - temp_len; i++) + { + display_string.concat(" "); + } + #ifdef HAS_SCREEN + display_obj.display_buffer->add(display_string); + #endif + buffer_obj.append(output_line + "\n"); + Serial.println(output_line); } } } @@ -10668,8 +10691,22 @@ static void requestStationARP(struct netif* station, const ip4_addr_t* ip) { delay(250); IPAddress check_ip = getPrevIP(this->last_scan_ip, this->subnet, i - 1); - if (findStationARP(netif_interface, check_ip)) { - this->recordARPResult(check_ip); + display_string = ""; + output_line = ""; + if (this->readARP(check_ip)) { + ipList->add(check_ip); + output_line = check_ip.toString(); + display_string.concat(output_line); + uint8_t temp_len = display_string.length(); + for (uint8_t i = 0; i < 40 - temp_len; i++) + { + display_string.concat(" "); + } + #ifdef HAS_SCREEN + display_obj.display_buffer->add(display_string); + #endif + buffer_obj.append(output_line + "\n"); + Serial.println(output_line); } } this->arp_count = 0; @@ -10726,8 +10763,12 @@ void WiFiScan::pingScan(uint8_t scan_mode) { // GCOVR_EXCL_START -- service discovery requires a live lwIP station interface. if (this->current_scan_ip != IPAddress(0, 0, 0, 0)) { - if ((this->advanceScanIP() != IPAddress(0, 0, 0, 0)) && - this->singleARP(this->current_scan_ip)) { + this->advanceScanIP(); + if (this->current_scan_ip == IPAddress(0, 0, 0, 0)) { + return; + } + if (this->singleARP(this->current_scan_ip)) { + Serial.println(this->current_scan_ip); this->portScan(scan_mode, targ_port); } } diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index b762a9881..aac2198d6 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -717,8 +717,8 @@ class WiFiScan void finishNetworkScanDisplay(const String& result_label); void setNetworkInfo(); void fullARP(); - void recordARPResult(IPAddress ip_addr); - inline __attribute__((always_inline)) bool singleARP(IPAddress ip_addr); + bool readARP(IPAddress targ_ip); + bool singleARP(IPAddress ip_addr); void pingScan(uint8_t scan_mode = WIFI_PING_SCAN); void portScan(uint8_t scan_mode = WIFI_PORT_SCAN_ALL, uint16_t targ_port = 22); IPAddress advanceScanIP();