Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/modules/NRF24/nrf_common.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
#include "nrf_common.h"
#include "../../core/bus_HAL.h"
#include "../../core/display.h"
#include "../../core/mykeyboard.h"

RF24 NRFradio(bruceConfigPins.NRF24_bus.io0, bruceConfigPins.NRF24_bus.cs);
HardwareSerial NRFSerial = HardwareSerial(2); // Uses UART2 for External NRF's
SPIClass *NRFSPI;

NRF_BACK_ACTION nrf_checkBackButton() {
#ifdef HAS_3_BUTTONS
if (PrevPress) {
const uint32_t pressStarted = millis();
LongPress = true;
while (PrevPress) {
const uint32_t elapsed = millis() - pressStarted;
if (elapsed > 200) {
int sweep = 360 * (elapsed - 200) / 500;
if (sweep > 360) sweep = 360;
tft.drawArc(
tftWidth / 2,
tftHeight / 2,
25,
15,
0,
sweep,
getColorVariation(bruceConfig.priColor),
bruceConfig.bgColor
);
}
vTaskDelay(pdMS_TO_TICKS(10));
}
tft.drawArc(tftWidth / 2, tftHeight / 2, 25, 15, 0, 360, bruceConfig.bgColor, bruceConfig.bgColor);
LongPress = false;
return millis() - pressStarted > 700 ? NRF_BACK_EXIT : NRF_BACK_SHORT;
}
#endif
return check(EscPress) ? NRF_BACK_EXIT : NRF_BACK_NONE;
}

void nrf_info() {
tft.fillScreen(bruceConfig.bgColor);
tft.setTextSize(FM);
Expand Down
11 changes: 11 additions & 0 deletions src/modules/NRF24/nrf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ enum NRF24_MODE {
NRF_MODE_UART, // 0b10
NRF_MODE_BOTH // 0b11
};

enum NRF_BACK_ACTION : uint8_t {
NRF_BACK_NONE,
NRF_BACK_SHORT,
NRF_BACK_EXIT,
};
#define CHECK_NRF_SPI(mode) (mode & NRF_MODE_SPI)
#define CHECK_NRF_UART(mode) (mode & NRF_MODE_UART)
#define CHECK_NRF_BOTH(mode) (mode == NRF_MODE_BOTH)
Expand All @@ -28,5 +34,10 @@ NRF24_MODE nrf_setMode();

bool nrf_start(NRF24_MODE mode);

// Handles the standard Bruce Back gesture used inside active NRF24 screens.
// On three-button devices, a short Back press is reported separately and a
// 700 ms hold draws the normal progress ring before requesting an exit.
NRF_BACK_ACTION nrf_checkBackButton();

void nrf_info();
#endif
20 changes: 18 additions & 2 deletions src/modules/NRF24/nrf_jammer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ void nrf_jammer() {
padprintln("");
padprintln("> Switch Mode: Next/Prev");
padprintln("> Hop Mode: Sel");
#ifdef HAS_3_BUTTONS
padprintln("> Exit: Hold Back");
#else
padprintln("> Exit: Esc");
#endif

tft.drawRoundRect(5, 5, tftWidth - 10, tftHeight - 10, 5, bruceConfig.priColor);
if ((CHECK_NRF_UART(mode)) || (CHECK_NRF_BOTH(mode))) {
Expand Down Expand Up @@ -181,7 +185,15 @@ void nrf_jammer() {
need_reshuffle = true;
redraw = true;
}
if (check(PrevPress)) {
bool previousMode = false;
#ifdef HAS_3_BUTTONS
NRF_BACK_ACTION backAction = nrf_checkBackButton();
if (backAction == NRF_BACK_EXIT) break;
previousMode = backAction == NRF_BACK_SHORT;
#else
previousMode = check(PrevPress);
#endif
if (previousMode) {
modeIndex--;
if (modeIndex < 0) modeIndex = (sizeof(modes) / sizeof(modes[0])) - 1;
hopIndex = 0;
Expand All @@ -198,7 +210,11 @@ void nrf_jammer() {
}
}

if (CHECK_NRF_SPI(mode)) NRFradio.stopConstCarrier();
if (CHECK_NRF_SPI(mode)) {
NRFradio.stopConstCarrier();
digitalWrite(bruceConfigPins.NRF24_bus.io0, LOW);
NRFradio.powerDown();
}
if ((CHECK_NRF_UART(mode)) || (CHECK_NRF_BOTH(mode))) { NRFSerial.println("OFF"); }

} else {
Expand Down
71 changes: 55 additions & 16 deletions src/modules/NRF24/nrf_mousejack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static MjTarget mj_targets[MJ_MAX_TARGETS];
static uint8_t mj_targetCount = 0;
static uint16_t mj_msSequence = 0;
static NRF24_MODE mj_nrfMode = NRF_MODE_SPI;
static bool mj_scanCancelled = false;

// ── ASCII to HID scancode lookup table ──────────────────────────
// Maps ASCII 0x20-0x7E to {modifier, keycode}
Expand Down Expand Up @@ -465,9 +466,9 @@ static void mj_sendKeystroke(const MjTarget &target, uint8_t modifier, uint8_t k
}

// ── Type a string as keystrokes ─────────────────────────────────
static void mj_typeString(const MjTarget &target, const char *text) {
static bool mj_typeString(const MjTarget &target, const char *text) {
for (size_t i = 0; text[i] != '\0'; i++) {
if (check(EscPress)) return;
if (nrf_checkBackButton() == NRF_BACK_EXIT) return false;

MjHidKey entry;
char c = text[i];
Expand All @@ -483,6 +484,7 @@ static void mj_typeString(const MjTarget &target, const char *text) {
mj_sendKeystroke(target, entry.modifier, entry.keycode);
delay(ATTACK_INTER_KEY_MS);
}
return true;
}

// ── DuckyScript line parser ─────────────────────────────────────
Expand All @@ -491,7 +493,13 @@ static bool mj_parseDuckyLine(const String &line, const MjTarget &target) {

if (line.startsWith("DELAY ") || line.startsWith("DELAY\t")) {
int delayMs = line.substring(6).toInt();
if (delayMs > 0 && delayMs <= 60000) delay(delayMs);
if (delayMs > 0 && delayMs <= 60000) {
const uint32_t delayStarted = millis();
while (millis() - delayStarted < (uint32_t)delayMs) {
if (nrf_checkBackButton() == NRF_BACK_EXIT) return false;
vTaskDelay(pdMS_TO_TICKS(10));
}
}
return true;
}

Expand All @@ -500,12 +508,11 @@ static bool mj_parseDuckyLine(const String &line, const MjTarget &target) {
}

if (line.startsWith("STRING ")) {
mj_typeString(target, line.substring(7).c_str());
return true;
return mj_typeString(target, line.substring(7).c_str());
}

if (line.startsWith("STRINGLN ")) {
mj_typeString(target, line.substring(9).c_str());
if (!mj_typeString(target, line.substring(9).c_str())) return false;
mj_sendKeystroke(target, MJ_MOD_NONE, MJ_KEY_ENTER);
return true;
}
Expand Down Expand Up @@ -633,11 +640,16 @@ static void mj_drawScanScreen(uint8_t currentCh, bool initial) {
int footerY = tftHeight - BORDER_PAD_X - FP * LH - 2;
tft.fillRect(7, footerY, tftWidth - 14, FP * LH, bruceConfig.bgColor);
tft.setTextColor(TFT_DARKGREY, bruceConfig.bgColor);
#ifdef HAS_3_BUTTONS
tft.drawCentreString("Hold Back: Stop", tftWidth / 2, footerY, 1);
#else
tft.drawCentreString("[ESC] Stop", tftWidth / 2, footerY, 1);
#endif
}

// ── Scanning function ───────────────────────────────────────────
static bool mj_scan() {
mj_scanCancelled = false;
mj_targetCount = 0;
memset(mj_targets, 0, sizeof(mj_targets));

Expand Down Expand Up @@ -677,7 +689,8 @@ static bool mj_scan() {
while (scanning) {
// Sweep channels 2-84 (ESB range)
for (uint8_t ch = 2; ch <= 84 && scanning; ch++) {
if (check(EscPress)) {
if (nrf_checkBackButton() == NRF_BACK_EXIT) {
mj_scanCancelled = true;
scanning = false;
break;
}
Expand Down Expand Up @@ -784,10 +797,11 @@ static void mj_attackString(int targetIndex) {
}
}

mj_typeString(target, text.c_str());
bool completed = mj_typeString(target, text.c_str());

NRFradio.powerDown();
displaySuccess("Injection complete", true);
displaySuccess(completed ? "Injection complete" : "Injection stopped", completed);
if (!completed) delay(500);
}

// ── Attack: DuckyScript from SD Card ────────────────────────────
Expand Down Expand Up @@ -850,9 +864,13 @@ static void mj_attackDucky(int targetIndex) {

uint16_t defaultDelayMs = 0;
String lastLine;
bool completed = true;

while (file.available()) {
if (check(EscPress)) break;
if (nrf_checkBackButton() == NRF_BACK_EXIT) {
completed = false;
break;
}

String line = file.readStringUntil('\n');
line.trim();
Expand All @@ -871,21 +889,42 @@ static void mj_attackDucky(int targetIndex) {
if (reps < 1) reps = 1;
if (reps > 500) reps = 500;
for (int r = 0; r < reps; r++) {
if (check(EscPress)) break;
if (lastLine.length() > 0) { mj_parseDuckyLine(lastLine, target); }
if (nrf_checkBackButton() == NRF_BACK_EXIT) {
completed = false;
break;
}
if (lastLine.length() > 0 && !mj_parseDuckyLine(lastLine, target)) {
completed = false;
break;
}
}
if (!completed) break;
continue;
}

mj_parseDuckyLine(line, target);
if (!mj_parseDuckyLine(line, target)) {
completed = false;
break;
}
lastLine = line;

if (defaultDelayMs > 0) delay(defaultDelayMs);
if (defaultDelayMs > 0) {
const uint32_t delayStarted = millis();
while (millis() - delayStarted < defaultDelayMs) {
if (nrf_checkBackButton() == NRF_BACK_EXIT) {
completed = false;
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
if (!completed) break;
}
}

file.close();
NRFradio.powerDown();
displaySuccess("Script complete", true);
displaySuccess(completed ? "Script complete" : "Script stopped", completed);
if (!completed) delay(500);
}

// ══════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -943,7 +982,7 @@ void nrf_mousejack() {
[=]() {
if (mj_scan()) {
mj_targetListMenu();
} else {
} else if (!mj_scanCancelled) {
displayInfo("No devices found", true);
}
} },
Expand Down
3 changes: 2 additions & 1 deletion src/modules/NRF24/nrf_spectrum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ void nrf_spectrum() {
for (uint8_t i = 0; i < 6; ++i) { NRFradio.openReadingPipe(i, noiseAddress[i]); }
NRFradio.setDataRate(RF24_1MBPS);

while (!check(EscPress)) {
while (true) {
if (nrf_checkBackButton() == NRF_BACK_EXIT) break;
scanChannels();
vTaskDelay(pdMS_TO_TICKS(1));
}
Expand Down