Skip to content

Commit 9a6ebea

Browse files
committed
rework rf24 controller, create receive/send cmd
1 parent c882856 commit 9a6ebea

3 files changed

Lines changed: 263 additions & 41 deletions

File tree

src/Controllers/Rf24Controller.cpp

Lines changed: 259 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "Controllers/Rf24Controller.h"
2+
#include "Vendors/wifi_atks.h"
23

34
/*
45
Entry point for rf24 commands
@@ -8,7 +9,8 @@ void Rf24Controller::handleCommand(const TerminalCommand& cmd) {
89

910
if (root == "help") handleHelp();
1011
else if (root == "config") handleConfig();
11-
else if (root == "sniff") handleSniff();
12+
else if (root == "send") handleSend();
13+
else if (root == "receive") handleReceive();
1214
else if (root == "scan") handleScan();
1315
else if (root == "sweep") handleSweep();
1416
else if (root == "waterfall") handleWaterfall();
@@ -36,44 +38,231 @@ void Rf24Controller::ensureConfigured() {
3638
}
3739

3840
/*
39-
Sniff
41+
Receive
4042
*/
41-
void Rf24Controller::handleSniff() {
42-
terminalView.println("RF24: Sniffing Channel " + std::to_string(rf24Service.getChannel()) + "... Press [ENTER] to stop.\n");
43+
void Rf24Controller::handleReceive() {
44+
int channel = userInputManager.readValidatedInt("Channel (0..125)", rf24Service.getChannel(), 0, 125);
45+
46+
uint8_t addrLen = userInputManager.readValidatedInt("Address length (3..5)", 5, 3, 5);
47+
std::string addrStr = userInputManager.readValidatedHexString(
48+
"RX " + std::to_string(addrLen) + " bytes address (AA 00 ...)", addrLen, true, 2
49+
);
50+
51+
uint8_t addr[5];
52+
if (!argTransformer.parseHexBytes(addrStr, addr, addrLen)) {
53+
terminalView.println("Invalid address. Example: AA BB CC 10 20\n");
54+
return;
55+
}
56+
57+
// Params
58+
int pipe = userInputManager.readValidatedInt("Pipe (0..5)", 1, 0, 5);
59+
int crcBits = userInputManager.readValidatedInt("CRC (0=off, 8, 16)", 16, 0, 16);
60+
int rateSel = userInputManager.readValidatedInt("Rate (0=250kbps, 1=1Mbps, 2=2Mbps)", 1, 0, 2);
61+
bool dynPayload = userInputManager.readYesNo("Dynamic payloads?", true);
62+
bool showAscii = true;
63+
64+
int fixedLen = 32;
65+
if (!dynPayload) {
66+
fixedLen = userInputManager.readValidatedInt("Payload size (1..32)", 32, 1, 32);
67+
}
68+
69+
// Configure RX
70+
Rf24Service::Rf24Config cfg{};
71+
cfg.channel = static_cast<uint8_t>(channel);
72+
cfg.pipe = static_cast<uint8_t>(pipe);
73+
memcpy(cfg.addr, addr, addrLen);
74+
cfg.addrStr = addrStr;
75+
cfg.addrLen = addrLen; // 3/4/5
76+
cfg.crcBits = crcBits; // 0/8/16
77+
cfg.dataRate = rateSel; // 0/1/2
78+
cfg.dynamicPayloads = dynPayload;
79+
cfg.fixedPayloadSize = static_cast<uint8_t>(fixedLen);
80+
81+
if (!rf24Service.initRx(cfg)) {
82+
terminalView.println("RF24 Receive: init failed (bad addr or not ready).\n");
83+
return;
84+
}
85+
86+
terminalView.println("\n[RF24 Receive]");
87+
terminalView.println(" Channel : " + std::to_string(channel));
88+
terminalView.println(" Pipe : " + std::to_string(pipe));
89+
terminalView.println(" Addr : " + addrStr);
90+
terminalView.println(" CRC : " + std::to_string(crcBits));
91+
terminalView.println(" Rate : " + std::string(rateSel == 0 ? "250k" : (rateSel == 1 ? "1M" : "2M")));
92+
terminalView.println(" Dyn : " + std::string(dynPayload ? "on" : "off"));
93+
terminalView.println("\nRF24: Receiving... Press [ENTER] to stop.");
4394

44-
rf24Service.initRx();
4595
rf24Service.startListening();
96+
4697
while (true) {
47-
auto c = terminalInput.readChar();
98+
// Cancel
99+
char c = terminalInput.readChar();
48100
if (c == '\n' || c == '\r') break;
49101

50-
if (rf24Service.available()) {
51-
uint8_t tmp[32] = {0};
52-
if (rf24Service.receive(tmp, sizeof(tmp))) {
53-
54-
// Display hex and ASCII
55-
for (int row = 0; row < 32; row += 16) {
56-
// Hex
57-
for (int i = 0; i < 16; i++) {
58-
terminalView.print(argTransformer.toHex(tmp[row + i], 2) + " ");
59-
}
60-
61-
terminalView.print(" | ");
102+
// Read frames
103+
uint8_t pipeNum = 7;
104+
if (rf24Service.availablePipe(&pipeNum)) {
105+
uint8_t buf[32] = {0};
106+
uint8_t len = 0;
62107

63-
// ASCII
64-
for (int i = 0; i < 16; i++) {
65-
char c = (tmp[row + i] >= 32 && tmp[row + i] <= 126) ? tmp[row + i] : '.';
66-
terminalView.print(std::string(1, c));
67-
}
108+
if (rf24Service.receive(buf, sizeof(buf), len)) {
109+
terminalView.println(
110+
"[RX pipe=" + std::to_string(pipeNum) +
111+
" len=" + std::to_string(len) + "]"
112+
);
68113

69-
terminalView.println("");
70-
}
114+
terminalView.println(argTransformer.formatHexAscii(buf, len, showAscii));
115+
terminalView.println("");
116+
} else {
117+
// Payload invalid
71118
}
72119
}
73120
}
121+
74122
rf24Service.stopListening();
75123
rf24Service.flushRx();
76-
terminalView.println("\nRF24: Sniff stopped by user.\n");
124+
terminalView.println("\nRF24 Receive: Stopped by user.\n");
125+
}
126+
127+
/*
128+
Send
129+
*/
130+
void Rf24Controller::handleSend() {
131+
int channel = userInputManager.readValidatedInt("Channel (0..125)", rf24Service.getChannel(), 0, 125);
132+
133+
uint8_t addrLen = userInputManager.readValidatedInt("Address length (3..5)", 5, 3, 5);
134+
std::string addrStr = userInputManager.readValidatedHexString(
135+
"TX " + std::to_string(addrLen) + " bytes address (AA 00 ...)", addrLen, true, 2
136+
);
137+
138+
uint8_t addr[5];
139+
if (!argTransformer.parseHexBytes(addrStr, addr, addrLen)) {
140+
terminalView.println("Invalid address. Example: AA BB CC 10 20\n");
141+
return;
142+
}
143+
144+
// Params
145+
int crcBits = userInputManager.readValidatedInt("CRC (0=off, 8, 16)", 16, 0, 16);
146+
int rateSel = userInputManager.readValidatedInt("Rate (0=250kbps, 1=1Mbps, 2=2Mbps)", 1, 0, 2);
147+
bool dynPayload = userInputManager.readYesNo("Dynamic payloads?", true);
148+
149+
int fixedLen = 32;
150+
if (!dynPayload) {
151+
fixedLen = userInputManager.readValidatedInt("Payload size (1..32)", 32, 1, 32);
152+
}
153+
154+
// Send behavior
155+
bool repeat = userInputManager.readYesNo("Repeat send?", false);
156+
int repeatDelayMs = 1000;
157+
if (repeat) {
158+
repeatDelayMs = userInputManager.readValidatedInt("Repeat delay (ms)", repeatDelayMs, 1, 60000);
159+
}
160+
161+
// Payload prompt
162+
terminalView.println("\n[Payload format]");
163+
terminalView.println(" Text: hello world");
164+
terminalView.println(" Hex : hex{ AA BB CC 10 }");
165+
terminalView.println(" Max : 32 bytes or defined length\n");
166+
167+
std::string patternRaw = userInputManager.readString("Payload", "hello world");
168+
169+
// Build payload
170+
std::string textPattern;
171+
std::vector<uint8_t> hexPattern;
172+
std::vector<uint8_t> hexMask;
173+
bool isHex = false;
174+
175+
if (!argTransformer.parsePattern(patternRaw, textPattern, hexPattern, hexMask, isHex)) {
176+
terminalView.println("RF24 Send: invalid payload. Aborted.\n");
177+
return;
178+
}
179+
180+
std::vector<uint8_t> payload;
181+
182+
if (isHex) {
183+
payload = hexPattern;
184+
} else {
185+
// decodeEscapes already done
186+
payload.assign(textPattern.begin(), textPattern.end());
187+
}
188+
189+
if (payload.empty()) {
190+
terminalView.println("RF24 Send: empty payload. Aborted.\n");
191+
return;
192+
}
193+
194+
// Enforce max
195+
if (payload.size() > 32) {
196+
terminalView.println("RF24 Send: payload too long (" + std::to_string(payload.size()) + " > 32). Truncating.\n");
197+
payload.resize(32);
198+
}
199+
200+
// If fixed payload mode, pad to fixedLen
201+
if (!dynPayload) {
202+
if ((int)payload.size() < fixedLen) {
203+
payload.resize((size_t)fixedLen, 0x00);
204+
} else if ((int)payload.size() > fixedLen) {
205+
payload.resize((size_t)fixedLen);
206+
}
207+
}
208+
209+
// Configure TX
210+
Rf24Service::Rf24Config cfg{};
211+
cfg.channel = static_cast<uint8_t>(channel);
212+
memcpy(cfg.addr, addr, addrLen);
213+
cfg.addrStr = addrStr;
214+
cfg.addrLen = addrLen; // 3/4/5
215+
cfg.crcBits = crcBits; // 0/8/16
216+
cfg.dataRate = rateSel; // 0/1/2
217+
cfg.dynamicPayloads = dynPayload;
218+
cfg.fixedPayloadSize = static_cast<uint8_t>(fixedLen);
219+
220+
if (!rf24Service.initTx(cfg)) {
221+
terminalView.println("RF24 Send: init failed (bad addr or not ready).\n");
222+
return;
223+
}
224+
225+
// Summary
226+
terminalView.println("\n[RF24 Send]");
227+
terminalView.println(" Channel : " + std::to_string(channel));
228+
terminalView.println(" Addr : " + addrStr);
229+
terminalView.println(" CRC : " + std::to_string(crcBits));
230+
terminalView.println(" Rate : " + std::string(rateSel == 0 ? "250k" : (rateSel == 1 ? "1M" : "2M")));
231+
terminalView.println(" Dyn : " + std::string(dynPayload ? "on" : "off"));
232+
if (!dynPayload) terminalView.println(" Len : " + std::to_string(fixedLen));
233+
terminalView.println(" Payload : " + std::to_string((int)payload.size()) + " bytes");
234+
terminalView.println("");
235+
236+
terminalView.println(argTransformer.formatHexAscii(payload.data(), (uint8_t)payload.size(), true));
237+
terminalView.println("");
238+
239+
// Send loop
240+
if (!repeat) {
241+
bool ok = rf24Service.send(payload.data(), (uint8_t)payload.size());
242+
terminalView.println(std::string(ok ? "TX SENT ACK OK\n" : "TX SENT NO ACK\n"));
243+
rf24Service.flushTx();
244+
return;
245+
}
246+
247+
terminalView.println("RF24: Sending... Press [ENTER] to stop.\n");
248+
249+
uint32_t count = 0;
250+
while (true) {
251+
char c = terminalInput.readChar();
252+
if (c == '\n' || c == '\r') break;
253+
254+
bool ok = rf24Service.send(payload.data(), (uint8_t)payload.size());
255+
count++;
256+
257+
terminalView.println(
258+
"[TX #" + std::to_string(count) + " " + (ok ? "SENT ACK OK" : "SENT NO ACK") + " len=" + std::to_string((int)payload.size()) + "]"
259+
);
260+
261+
delay(repeatDelayMs);
262+
}
263+
264+
rf24Service.flushTx();
265+
terminalView.println("\nRF24 Send: Stopped by user.\n");
77266
}
78267

79268
/*
@@ -164,26 +353,42 @@ void Rf24Controller::handleJam() {
164353
std::vector<std::string> groupNames;
165354
groupNames.reserve(RF24_GROUP_COUNT);
166355
for (size_t i = 0; i < RF24_GROUP_COUNT; ++i) groupNames.emplace_back(RF24_GROUPS[i].name);
167-
groupNames.emplace_back("Full range (0..125)");
356+
groupNames.emplace_back(" All channels");
357+
groupNames.emplace_back(" One Channel");
358+
groupNames.emplace_back(" Exit");
168359

169360
// Select group
170361
int choice = userInputManager.readValidatedChoiceIndex("Select band to jam:", groupNames, 0);
171362

363+
// Exit selected
364+
if (choice == (int)groupNames.size() - 1) {
365+
terminalView.println("RF24 Jam: Exiting...\n");
366+
return;
367+
}
368+
369+
// Prepare channel list based on choice
370+
uint8_t fullRangeChannels[126];
371+
for (uint8_t i = 0; i <= 125; ++i) fullRangeChannels[i] = i;
372+
uint8_t oneRange[1];
373+
Rf24ChannelGroup localGroup = {" Local", nullptr, 0};
374+
172375
// Get group
173376
const Rf24ChannelGroup* group = nullptr;
174-
if (choice >= (int)RF24_GROUP_COUNT) {
377+
if (groupNames[choice].find("All channels") != std::string::npos) {
175378
// Full range
176-
uint8_t fullRangeChannels[126];
177-
for (uint8_t i = 0; i <= 125; ++i) fullRangeChannels[i] = i;
178-
static const Rf24ChannelGroup fullRangeGroup = {
179-
" Full range",
180-
fullRangeChannels,
181-
126
182-
};
183-
group = &fullRangeGroup;
379+
localGroup = { " All channels", fullRangeChannels, 126 };
380+
group = &localGroup;;
381+
} else if (groupNames[choice].find("One Channel") != std::string::npos) {
382+
// One channel
383+
uint8_t ch = userInputManager.readValidatedUint8("Channel to jam (0..125)", 0, 0, 125);
384+
oneRange[0] = ch;
385+
localGroup = { " One channel", oneRange, 1 };
386+
group = &localGroup;
184387
} else {
388+
// WiFi, Bluetooth, etc
185389
group = &RF24_GROUPS[choice];
186390
}
391+
bool isWiFi = groupNames[choice].find("WiFi") != std::string::npos;
187392

188393
terminalView.println("\nRF24: Sweeping noise on channels... Press [ENTER] to stop.");
189394

@@ -192,6 +397,11 @@ void Rf24Controller::handleJam() {
192397
rf24Service.powerUp();
193398
rf24Service.setPowerMax();
194399

400+
// WiFi beacon setup for wifi group
401+
const uint8_t wifiCh[3] = { 1, 6, 11 };
402+
constexpr size_t wifiChCount = sizeof(wifiCh) / sizeof(wifiCh[0]);
403+
uint8_t chIdx = 0;
404+
195405
// Jam loop
196406
bool run = true;
197407
while (run) {
@@ -202,6 +412,12 @@ void Rf24Controller::handleJam() {
202412

203413
// Sweep
204414
rf24Service.setChannel(group->channels[i]);
415+
416+
// also spam with WiFi beacons
417+
if (isWiFi) {
418+
beaconCreate("", wifiCh[chIdx], true); // from wifi_atks
419+
chIdx = (chIdx + 1) % wifiChCount;
420+
}
205421
}
206422
}
207423

@@ -282,7 +498,7 @@ void Rf24Controller::handleWaterfall()
282498
uint8_t ch = 0;
283499
int bestChannel = -1;
284500
int bestLevel = 0;
285-
std::string title;
501+
std::string title = "Peak: --";
286502

287503
rf24Service.initRx();
288504

@@ -318,8 +534,6 @@ void Rf24Controller::handleWaterfall()
318534
if (bestChannel >= 0 && bestLevel > 1) {
319535
title = "Peak: CH" + std::to_string(bestChannel) +
320536
" (" + std::to_string(2400 + bestChannel) + "MHz)";
321-
} else {
322-
title = "Peak: --";
323537
}
324538

325539
// Draw the line for this channel
@@ -333,6 +547,12 @@ void Rf24Controller::handleWaterfall()
333547
level
334548
);
335549

550+
// Update channel, reset at 0
551+
if (ch == 0) {
552+
title = "Peak: --";
553+
bestChannel = -1;
554+
bestLevel = 0;
555+
}
336556
ch++;
337557
if (ch > 125) ch = 0;
338558
}

src/Controllers/Rf24Controller.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class Rf24Controller {
4343
private:
4444
// Command handlers
4545
void handleConfig();
46-
void handleSniff();
46+
void handleReceive();
47+
void handleSend();
4748
void handleScan();
4849
void handleJam();
4950
void handleSweep();

0 commit comments

Comments
 (0)