diff --git a/.github/workflows/buil_parallel.yml b/.github/workflows/buil_parallel.yml index 08fb9432b..f3fb60ea7 100644 --- a/.github/workflows/buil_parallel.yml +++ b/.github/workflows/buil_parallel.yml @@ -17,60 +17,9 @@ jobs: fail-fast: false matrix: board: - - { env: "m5stack-cardputer", family: "ESP32-S3",} - - { env: "m5stack-sticks3", family: "ESP32-S3",} - - { env: "m5stack-cplus2", family: "ESP32",} - - { env: "m5stack-cplus1_1", family: "ESP32",} - - { env: "LAUNCHER_m5stack-cplus1_1", family: "ESP32",} - - { env: "m5stack-core2", family: "ESP32",} - - { env: "m5stack-core16mb", family: "ESP32",} - - { env: "m5stack-core4mb", family: "ESP32",} - - { env: "m5stack-cores3", family: "ESP32-S3",} - - { env: "esp32-s3-devkitc-1", family: "ESP32-S3",} - - { env: "esp32-c5", family: "ESP32-C5",} - - { env: "esp32-c5-tft", family: "ESP32-C5",} - - { env: "CYD-2432S028", family: "ESP32",} - - { env: "CYD-2USB", family: "ESP32",} - - { env: "CYD-2432W328C", family: "ESP32",} - - { env: "CYD-2432W328C_2", family: "ESP32",} - - { env: "CYD-2432W328R-or-S024R", family: "ESP32",} - - { env: "CYD-3248S035R", family: "ESP32",} - - { env: "CYD-3248S035C", family: "ESP32",} - - { env: "LAUNCHER_CYD-2432W328R-or-S024R", family: "ESP32",} - - { env: "LAUNCHER_CYD-2432S028", family: "ESP32",} - - { env: "LAUNCHER_CYD-2USB", family: "ESP32",} - - { env: "LAUNCHER_CYD-2432W328C", family: "ESP32",} - - { env: "LAUNCHER_CYD-3248S035R", family: "ESP32",} - # - { env: "LAUNCHER_CYD-3248S035C", family: "ESP32",} - - { env: "lilygo-t-embed-cc1101", family: "ESP32-S3",} - - { env: "lilygo-t-embed", family: "ESP32-S3",} - - { env: "lilygo-t-deck", family: "ESP32-S3",} - - { env: "lilygo-t-watch-s3", family: "ESP32-S3",} - - { env: "lilygo-t-deck-pro", family: "ESP32-S3",} - - { env: "lilygo-t-display-s3", family: "ESP32-S3",} - - { env: "lilygo-t-display-s3-touch", family: "ESP32-S3",} - - { env: "lilygo-t-display-s3-mmc", family: "ESP32-S3",} - - { env: "lilygo-t-display-s3-touch-mmc", family: "ESP32-S3",} - - { env: "lilygo-t-display-S3-pro", family: "ESP32-S3",} - - { env: "lilygo-t-display-ttgo", family: "ESP32",} - - { env: "lilygo-t-hmi", family: "ESP32-S3",} - - { env: "lilygo-t-lora-pager", family: "ESP32-S3",} - - { env: "smoochiee-board", family: "ESP32-S3",} - - { env: "reaper", family: "ESP32-S3",} - - { env: "Phantom_S024R", family: "ESP32",} - - { env: "LAUNCHER_Phantom_S024R", family: "ESP32",} - { env: "Marauder-Mini", family: "ESP32",} - - { env: "LAUNCHER_Marauder-Mini", family: "ESP32",} - - { env: "Awok-Mini", family: "ESP32",} - - { env: "Marauder-v7", family: "ESP32",} - - { env: "LAUNCHER_Marauder-v7", family: "ESP32",} - - { env: "Marauder-V4-V6", family: "ESP32",} - - { env: "Marauder-v61", family: "ESP32",} - - { env: "LAUNCHER_Marauder-V4-V6", family: "ESP32",} - - { env: "LAUNCHER_Marauder-v61", family: "ESP32",} - - { env: "Awok-Touch", family: "ESP32",} - - { env: "WaveSentry-R1", family: "ESP32",} - - { env: "LAUNCHER_WaveSentry-R1", family: "ESP32",} + - { env: "lilygo-t-display-ttgo", family: "ESP32",} + steps: - uses: actions/checkout@v4 diff --git a/boards/_boards_json/lilygo-t-display-ttgo.json b/boards/_boards_json/lilygo-t-display-ttgo.json index 467b52b6f..146748323 100644 --- a/boards/_boards_json/lilygo-t-display-ttgo.json +++ b/boards/_boards_json/lilygo-t-display-ttgo.json @@ -29,11 +29,11 @@ "arduino", "espidf" ], - "name": "Espressif ESP32 Dev Module", + "name": "Espressif ESP32 Dev Module (16MB)", "upload": { - "flash_size": "4MB", + "flash_size": "16MB", "maximum_ram_size": 327680, - "maximum_size": 4194304, + "maximum_size": 16777216, "require_upload_port": true, "speed": 460800 }, diff --git a/boards/lilygo-t-display-ttgo/interface.cpp b/boards/lilygo-t-display-ttgo/interface.cpp index fc60e8389..dba970d66 100644 --- a/boards/lilygo-t-display-ttgo/interface.cpp +++ b/boards/lilygo-t-display-ttgo/interface.cpp @@ -4,6 +4,8 @@ #include #include +#include "core/display.h" + volatile bool nxtPress = false; volatile bool prvPress = false; volatile bool ecPress = false; @@ -110,6 +112,43 @@ void InputHandler(void) { slPress = false; } } + + // New logic for Shutdown + static unsigned long upBtnHoldStart = 0; + static bool upBtnHeldState = false; + static int lastShutdownCountdown = 0; + + // Check UP_BTN (GPIO 35) + if (digitalRead(UP_BTN) == LOW) { // Pressed + if (menuOptionType == MENU_TYPE_MAIN) { + if (!upBtnHeldState) { + upBtnHoldStart = millis(); + upBtnHeldState = true; + } else { + unsigned long elapsed = millis() - upBtnHoldStart; + int remaining = 5 - (elapsed / 1000); + + if (remaining <= 0) { + powerOff(); + } else if (remaining != lastShutdownCountdown && elapsed > 500) { + // Draw countdown + tft.setTextColor(TFT_RED, bruceConfig.bgColor); + String msg = "OFF: " + String(remaining); + tft.drawCentreString(msg.c_str(), tftWidth / 2, tftHeight / 2, 4); + lastShutdownCountdown = remaining; + } + } + } + } else { + if (upBtnHeldState) { + upBtnHeldState = false; + // Clear countdown + if (lastShutdownCountdown > 0) { + tft.fillRect(0, tftHeight / 2, tftWidth, 40, bruceConfig.bgColor); + lastShutdownCountdown = 0; + } + } + } } void powerOff() { diff --git a/boards/lilygo-t-display-ttgo/lilygo-t-display-s3.ini b/boards/lilygo-t-display-ttgo/lilygo-t-display-s3.ini index c71da510a..c7c716dd6 100644 --- a/boards/lilygo-t-display-ttgo/lilygo-t-display-s3.ini +++ b/boards/lilygo-t-display-ttgo/lilygo-t-display-s3.ini @@ -1,6 +1,6 @@ [env:lilygo-t-display-ttgo] board = lilygo-t-display-ttgo -board_build.partitions = custom_4Mb_full.csv +board_build.partitions = custom_16Mb.csv build_src_filter =${env.build_src_filter} +<../boards/lilygo-t-display-ttgo> build_flags = ${env.build_flags} diff --git a/boards/lilygo-t-display-ttgo/pins_arduino.h b/boards/lilygo-t-display-ttgo/pins_arduino.h index 09f0c73d6..19d285501 100644 --- a/boards/lilygo-t-display-ttgo/pins_arduino.h +++ b/boards/lilygo-t-display-ttgo/pins_arduino.h @@ -71,7 +71,7 @@ static const uint8_t SCL = GROVE_SCL; // Display Setup# #define HAS_SCREEN -#define ROTATION 3 +#define ROTATION 1 #define MINBRIGHT (uint8_t)1 // Font Sizes# @@ -92,8 +92,8 @@ static const uint8_t SCL = GROVE_SCL; // Buttons & Navigation #define BTN_ALIAS "\"OK\"" #define HAS_3_BUTTONS -#define UP_BTN 0 -#define DW_BTN 35 +#define UP_BTN 35 +#define DW_BTN 0 #define BTN_ACT LOW // IR pins diff --git a/boards/marauder-mini/pins_arduino.h b/boards/marauder-mini/pins_arduino.h index e96e28f68..320135252 100644 --- a/boards/marauder-mini/pins_arduino.h +++ b/boards/marauder-mini/pins_arduino.h @@ -79,8 +79,8 @@ static const uint8_t ADC2 = 8; #define CC1101_SCK_PIN SPI_SCK_PIN #define CC1101_MISO_PIN SPI_MISO_PIN -#define NRF24_CE_PIN -1 -#define NRF24_SS_PIN -1 +#define NRF24_CE_PIN 12 +#define NRF24_SS_PIN 27 #define NRF24_MOSI_PIN SPI_MOSI_PIN #define NRF24_SCK_PIN SPI_SCK_PIN #define NRF24_MISO_PIN SPI_MISO_PIN diff --git a/boards/smoochiee-board/pins_arduino.h b/boards/smoochiee-board/pins_arduino.h index e195481c4..9cdd76d2d 100644 --- a/boards/smoochiee-board/pins_arduino.h +++ b/boards/smoochiee-board/pins_arduino.h @@ -64,7 +64,7 @@ static const uint8_t SCK = 18; #define USER_SETUP_LOADED 1 #define ST7789_DRIVER 1 #define TFT_RGB_ORDER 0 -#define TFT_WIDTH 170 +#define TFT_WIDTH 172 #define TFT_HEIGHT 320 #define TFT_BACKLIGHT_ON 1 #define TFT_BL 6 @@ -123,3 +123,4 @@ static const uint8_t SCK = 18; #define IO_EXP_CC_RX 7 #define IO_EXP_CC_TX 12 #endif /* Pins_Arduino_h */ + diff --git a/platformio.ini b/platformio.ini index 160a118ee..5770020b5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,7 @@ default_envs = ;m5stack-cardputer ;m5stack-sticks3 - m5stack-cplus2 + ;m5stack-cplus2 ;m5stack-cplus1_1 ;LAUNCHER_m5stack-cplus1_1 ;m5stack-core2 @@ -43,7 +43,7 @@ default_envs = ;lilygo-t-display-s3-mmc ;lilygo-t-display-s3-touch-mmc ;lilygo-t-display-S3-pro - ;lilygo-t-display-ttgo + lilygo-t-display-ttgo ;lilygo-t-hmi ;lilygo-t-lora-pager ;smoochiee-board diff --git a/src/core/main_menu.cpp b/src/core/main_menu.cpp index 1fb02b376..e6e3d409a 100644 --- a/src/core/main_menu.cpp +++ b/src/core/main_menu.cpp @@ -6,6 +6,7 @@ MainMenu::MainMenu() { _menuItems = { &wifiMenu, + &bw16Menu, &bleMenu, #if !defined(LITE_VERSION) ðernetMenu, diff --git a/src/core/main_menu.h b/src/core/main_menu.h index 705e967c5..d27dd2f2e 100644 --- a/src/core/main_menu.h +++ b/src/core/main_menu.h @@ -19,6 +19,8 @@ #include "menu_items/RFMenu.h" #include "menu_items/ScriptsMenu.h" #include "menu_items/WifiMenu.h" +#include "menu_items/BW16Menu.h" + class MainMenu { public: FileMenu fileMenu; @@ -35,6 +37,7 @@ class MainMenu { RFMenu rfMenu; ScriptsMenu scriptsMenu; WifiMenu wifiMenu; + BW16Menu bw16Menu; #if !defined(LITE_VERSION) LoRaMenu loraMenu; EthernetMenu ethernetMenu; diff --git a/src/core/menu_items/BW16Menu.cpp b/src/core/menu_items/BW16Menu.cpp new file mode 100644 index 000000000..43a1cf16f --- /dev/null +++ b/src/core/menu_items/BW16Menu.cpp @@ -0,0 +1,195 @@ +#include "BW16Menu.h" +#include +#include +#include + +void BW16Menu::drawIcon(float scale) { + clearIconArea(); + int x = iconCenterX; + int y = iconCenterY; + + tft.setTextSize(scale * 7.0); + tft.setTextColor(bruceConfig.priColor); + + // Draw "5G" larger and slightly higher + tft.drawCentreString("5G", x, y - (15 * scale), 1); + + // Draw "Hz" larger below it + tft.setTextSize(max(2.5f, scale)); + tft.drawCentreString("Hz", x, y + (10 * scale), 1); +} + +// Global static tick helper +static bool bw16_tick(void* ptr, bool) { + if (ptr) { + BW16Menu* menu = (BW16Menu*)ptr; + menu->runLoop(); + } + return false; +} + +void BW16Menu::optionsMenu() { + bw16.begin(); + + // Initial status check + bw16.getStatus(); + + while(1) { + options = { + {"Scan Networks", [this]() { scanNetworks(); }, false, bw16_tick, this}, + {"Show AP List", [this]() { showAPList(); }, false, bw16_tick, this}, + {"Deauth All", [this]() { + bw16.deauthAll(); + long start = millis(); + while(millis() - start < 1000) { + bw16.loop(); + delay(10); + } + displaySuccess("Deauth All Sent"); + }, false, bw16_tick, this}, + {"Stop All Deauths", [this]() { + bw16.deauthStopAll(); + displaySuccess("Stopped All!"); + delay(1000); + }, false, bw16_tick, this}, + }; + + String status = "Status: "; + if (bw16.isConnected()) status += "Ready"; + else status += "Checking..."; + + status += " | APs: " + String(bw16.getResults().size()); + + if (bw16.getLastMessage().length() > 0) { + status += "\n" + bw16.getLastMessage(); + } + + int ret = loopOptions(options, MENU_TYPE_REGULAR, status.c_str()); + + if (returnToMenu) break; + if (ret == -1) break; + } + + bw16.end(); +} + +void BW16Menu::scanNetworks() { + drawMainBorderWithTitle("Scanning..."); // Clear screen and show title + tft.drawCentreString("Scanning...", tftWidth/2, tftHeight/2 - 20, 1); + + bw16.scan(5000); + + long start = millis(); + bool completed = false; + + while(millis() - start < 6000) { // 6s timeout for 5s scan + bw16.loop(); + + // Progress bar + float progress = (millis() - start) / 5000.0; + if (progress > 1.0) progress = 1.0; + + int barWidth = tftWidth - 40; + int barX = 20; + int barY = tftHeight/2 + 20; + + tft.drawRect(barX, barY, barWidth, 10, bruceConfig.priColor); + tft.fillRect(barX + 2, barY + 2, (barWidth-4) * progress, 6, bruceConfig.secColor); + + if (!bw16.isScanning() && (millis() - start > 500)) { + completed = true; + break; + } + + if (check(EscPress)) { + completed = false; + break; + } + + delay(10); + } + + if (completed) { + long extraWait = millis(); + while(millis() - extraWait < 500) { + bw16.loop(); + delay(10); + } + showAPList(); + } else { + displayError("Scan Timeout"); + delay(1000); + } +} + +void BW16Menu::showAPList() { + auto results = bw16.getResults(); + if (results.empty()) { + displayError("No APs Found"); + delay(1000); + return; + } + + while(1) { + options.clear(); + for(const auto& res : results) { + String label = res.ssid; + if (label.length() == 0) label = ""; + label += " (" + String(res.rssi) + ")"; + + options.push_back({label, [this, res]() { showActionMenu(res.index); }, false, bw16_tick, this}); + } + + int ret = loopOptions(options, MENU_TYPE_REGULAR, "Select AP"); + if (ret == -1) break; + } +} + +void BW16Menu::showActionMenu(int index) { + auto results = bw16.getResults(); + BW16ScanResult target; + bool found = false; + for(const auto& res : results) { + if (res.index == index) { + target = res; + found = true; + break; + } + } + + if (!found) return; + + while(1) { + options = { + {"Deauth Start", [this, index]() { + bw16.deauthStart(index); + displaySuccess("Deauth Started"); + delay(500); + }, false, bw16_tick, this}, + + {"Deauth Stop", [this, index]() { + bw16.deauthStop(index); + displaySuccess("Deauth Stopped"); + delay(500); + }, false, bw16_tick, this}, + + {"Select SSID", [this, index]() { + bw16.selectSSID(index); + displaySuccess("SSID Selected"); + delay(500); + }, false, bw16_tick, this} + }; + + String info = "Ch:" + String(target.channel) + " " + target.bssid + "\nSec:" + String(target.security) + " RSSI:" + String(target.rssi); + + // drawMainBorderWithTitle(target.ssid); // loopOptions handles title if passed via subText? No, title is separate. + // loopOptions clears screen. + + // We can pass target.ssid as title to loopOptions if we modify utils... + // But loopOptions uses generic title logic. + // Let's rely on info string. + + int ret = loopOptions(options, MENU_TYPE_REGULAR, info.c_str()); + if (ret == -1) break; + } +} diff --git a/src/core/menu_items/BW16Menu.h b/src/core/menu_items/BW16Menu.h new file mode 100644 index 000000000..92025d601 --- /dev/null +++ b/src/core/menu_items/BW16Menu.h @@ -0,0 +1,25 @@ +#ifndef __BW16_MENU_H__ +#define __BW16_MENU_H__ + +#include +#include + +class BW16Menu : public MenuItemInterface { +public: + BW16Menu() : MenuItemInterface("BW16 5G") {} + + void optionsMenu(void); + void drawIcon(float scale); + bool hasTheme() { return false; } + String themePath() { return ""; } + + void runLoop() { bw16.loop(); } + +private: + BW16 bw16; + void showAPList(); + void scanNetworks(); + void showActionMenu(int index); +}; + +#endif diff --git a/src/modules/bw16/BW16.cpp b/src/modules/bw16/BW16.cpp new file mode 100644 index 000000000..4c7c7dd59 --- /dev/null +++ b/src/modules/bw16/BW16.cpp @@ -0,0 +1,191 @@ +#include "BW16.h" +#include + +BW16::BW16() { + // Constructor +} + +BW16::~BW16() { + end(); +} + +void BW16::begin() { + releasePins(); + // Use HardwareSerial(2) as defined in header + _serial.begin(115200, SERIAL_8N1, bruceConfigPins.uart_bus.rx, bruceConfigPins.uart_bus.tx); + + // Check if pins are valid + if (bruceConfigPins.uart_bus.rx == GPIO_NUM_NC || bruceConfigPins.uart_bus.tx == GPIO_NUM_NC) { + log_e("BW16 UART pins not configured!"); + _connected = false; + return; + } + + _connected = true; + _scanning = false; + _scanResults.clear(); + _lastMessage = ""; + getStatus(); // Check connection +} + +void BW16::end() { + if (_connected) { + _serial.end(); + restorePins(); + _connected = false; + } +} + +void BW16::loop() { + if (!_connected) return; + + while (_serial.available()) { + char c = _serial.read(); + if (c == '\n') { + parseLine(_buffer); + _buffer = ""; + } else { + if (c != '\r') _buffer += c; + } + } +} + +void BW16::sendCommand(String cmd) { + if (!_connected) return; + String fullCmd = "BRUCE:" + cmd; + _serial.println(fullCmd); + log_d("Sent: %s", fullCmd.c_str()); +} + +void BW16::scan(int timeMs) { + _scanning = true; + _scanResults.clear(); + sendCommand("SCAN," + String(timeMs)); +} + +void BW16::deauthStart(int index) { + sendCommand("DEAUTH_START," + String(index)); +} + +void BW16::deauthStop(int index) { + sendCommand("DEAUTH_STOP," + String(index)); +} + +void BW16::deauthStopAll() { + sendCommand("DEAUTH_STOP_ALL"); +} + +void BW16::deauthAll() { + sendCommand("DEAUTH_ALL"); +} + +void BW16::selectSSID(int index) { + sendCommand("SELECT_SSID," + String(index)); +} + +void BW16::getAPList() { + _scanResults.clear(); + sendCommand("GET_AP_LIST"); +} + +void BW16::getStatus() { + sendCommand("GET_STATUS"); +} + +void BW16::parseLine(String line) { + line.trim(); + if (line.length() == 0) return; + + // Log for debug + // Serial.println("[BW16] " + line); + + if (!line.startsWith("BRUCE_RESP:")) return; + + String resp = line.substring(11); // Remove prefix + + if (resp.startsWith("SCAN_SUCCESS")) { + _scanning = false; + } else if (resp.startsWith("SCAN_FAILED")) { + _scanning = false; + } else if (resp.startsWith("DEAUTH_ALL_STARTED:COUNT=")) { + _lastMessage = "Deauth All Started: " + resp.substring(25); + } else if (resp.startsWith("ERROR:")) { + _lastMessage = resp.substring(6); + } else if (resp.startsWith("AP:")) { + // Format: AP:index|SSID|BSSID|Channel|Security|RSSI + // Example: AP:0|MyWifi|00:11:22:33:44:55|6|3|-60 + + int idx = resp.indexOf(':') + 1; + String data = resp.substring(idx); + + int pipe1 = data.indexOf('|'); + int pipe2 = data.indexOf('|', pipe1 + 1); + int pipe3 = data.indexOf('|', pipe2 + 1); + int pipe4 = data.indexOf('|', pipe3 + 1); + int pipe5 = data.indexOf('|', pipe4 + 1); + + if (pipe1 > 0 && pipe2 > pipe1 && pipe3 > pipe2 && pipe4 > pipe3 && pipe5 > pipe4) { + BW16ScanResult res; + res.index = data.substring(0, pipe1).toInt(); + res.ssid = data.substring(pipe1 + 1, pipe2); + res.bssid = data.substring(pipe2 + 1, pipe3); + res.channel = data.substring(pipe3 + 1, pipe4).toInt(); + res.security = data.substring(pipe4 + 1, pipe5).toInt(); + res.rssi = data.substring(pipe5 + 1).toInt(); + + _scanResults.push_back(res); + } + } else if (resp.startsWith("SCAN_COMPLETE")) { + _scanning = false; + } else if (resp.startsWith("SCAN_RESULT:COUNT=")) { + int count = resp.substring(18).toInt(); + if (count == 0) _scanning = false; + // Pre-allocate vector? Not strictly necessary. + } +} + +// Logic copied/adapted from GPSTracker to avoid conflicts +void BW16::releasePins() { + _pinsReleased = false; + if (bruceConfigPins.CC1101_bus.checkConflict(bruceConfigPins.uart_bus.rx) || + bruceConfigPins.NRF24_bus.checkConflict(bruceConfigPins.uart_bus.rx) || +#if !defined(LITE_VERSION) + bruceConfigPins.W5500_bus.checkConflict(bruceConfigPins.uart_bus.rx) || + bruceConfigPins.LoRa_bus.checkConflict(bruceConfigPins.uart_bus.rx) || +#endif + bruceConfigPins.SDCARD_bus.checkConflict(bruceConfigPins.uart_bus.rx)) { + + pinMode(bruceConfigPins.uart_bus.rx, INPUT); + _pinsReleased = true; + } +} + +void BW16::restorePins() { + if (_pinsReleased) { + if (bruceConfigPins.CC1101_bus.checkConflict(bruceConfigPins.uart_bus.rx) || + bruceConfigPins.NRF24_bus.checkConflict(bruceConfigPins.uart_bus.rx) || +#if !defined(LITE_VERSION) + bruceConfigPins.W5500_bus.checkConflict(bruceConfigPins.uart_bus.rx) || + bruceConfigPins.LoRa_bus.checkConflict(bruceConfigPins.uart_bus.rx) || +#endif + bruceConfigPins.SDCARD_bus.checkConflict(bruceConfigPins.uart_bus.rx)) { + + pinMode(bruceConfigPins.uart_bus.rx, OUTPUT); + + // Check specific conflicts to set HIGH/LOW + if (bruceConfigPins.uart_bus.rx == bruceConfigPins.CC1101_bus.cs || + bruceConfigPins.uart_bus.rx == bruceConfigPins.NRF24_bus.cs || +#if !defined(LITE_VERSION) + bruceConfigPins.uart_bus.rx == bruceConfigPins.W5500_bus.cs || +#endif + bruceConfigPins.uart_bus.rx == bruceConfigPins.SDCARD_bus.cs) { + // If it is conflicting to an SPI CS pin, keep it HIGH + digitalWrite(bruceConfigPins.uart_bus.rx, HIGH); + } else { + // Keep it LOW otherwise + digitalWrite(bruceConfigPins.uart_bus.rx, LOW); + } + } + _pinsReleased = false; + } +} diff --git a/src/modules/bw16/BW16.h b/src/modules/bw16/BW16.h new file mode 100644 index 000000000..32be08f85 --- /dev/null +++ b/src/modules/bw16/BW16.h @@ -0,0 +1,54 @@ +#ifndef __BW16_H__ +#define __BW16_H__ + +#include +#include + +struct BW16ScanResult { + int index; + String ssid; + String bssid; + int channel; + int security; + int rssi; +}; + +class BW16 { +public: + BW16(); + ~BW16(); + + void begin(); + void end(); + void loop(); + + void scan(int timeMs = 5000); + void deauthStart(int index); + void deauthStop(int index); + void deauthStopAll(); + void deauthAll(); + void selectSSID(int index); + void getAPList(); + void getStatus(); + + std::vector getResults() { return _scanResults; } + String getLastMessage() { return _lastMessage; } + bool isScanning() { return _scanning; } + bool isConnected() { return _connected; } + +private: + HardwareSerial _serial = HardwareSerial(2); + std::vector _scanResults; + bool _scanning = false; + bool _connected = false; + String _buffer; + String _lastMessage; + bool _pinsReleased = false; + + void parseLine(String line); + void releasePins(); + void restorePins(); + void sendCommand(String cmd); +}; + +#endif