11#include " Controllers/Rf24Controller.h"
2+ #include " Vendors/wifi_atks.h"
23
34/*
45Entry 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 (" \n RF24: 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 (" \n RF24: Sniff stopped by user.\n " );
124+ terminalView.println (" \n RF24 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 (" \n RF24 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 (" \n RF24: 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 }
0 commit comments