Skip to content

Commit

Permalink
Promiscuous scanners (#955)
Browse files Browse the repository at this point in the history
* adjust scanner examples as discussed in #852
* add new curses python scanner
* replace scanner.py w/ curses implementation
* update pico scanner example
* update arduino scanner

* introducing an Arduino scannerGraphic example
   - supports 2 types of displays (& optional Serial debugginng)

   1. SPI display (uses same bus as radio) is tested with an ST7789 (https://www.adafruit.com/product/4383)
   2. I2C display is tested with SSd1306 (https://www.adafruit.com/product/326)

   Use defines to toggle debugging and EITHER (not both) of the displays.
* [Arduino scanner] ensure radio is not stuck with CONT_WAVE flag asserted after MCU reset

---------

Co-authored-by: TMRh20 <tmrh20@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 11, 2024
1 parent 7e97360 commit ef08a40
Show file tree
Hide file tree
Showing 10 changed files with 1,325 additions and 264 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ on:
- "utility/MRAAA/*"
- "utility/SPIDEV/*"
- "utility/pigpio"
- "examples_linux/*"
- "examples_linux/**"
- "!examples_linux/*.py"
- "!examples_linux/*.md"
- "pyRF24/setup.py"
Expand All @@ -39,7 +39,7 @@ on:
- "utility/MRAAA/*"
- "utility/SPIDEV/*"
- "utility/pigpio"
- "examples_linux/*"
- "examples_linux/**"
- "!examples_linux/*.py"
- "!examples_linux/*.md"
- "pyRF24/setup.py"
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ Session.vim
.DS_Store
Makefile.inc
utility/includes.h
!examples_linux/
examples_linux/*
examples_linux/**/*
!examples_linux/**/
!examples_linux/*.cpp
!examples_linux/*.py
!examples_linux/**/*.cpp
Expand Down
201 changes: 143 additions & 58 deletions examples/scanner/scanner.ino
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,36 @@
* This is a good diagnostic tool to check whether you're picking a
* good channel for your application.
*
* Run this sketch on two devices. On one device, start CCW output by sending a 'g'
* character over Serial. The other device scanning should detect the output of the sending
* device on the given channel. Adjust channel and output power of CCW below.
* Run this sketch on two devices. On one device, start emitting a constant carrier wave
* by sending a channel number in the Serial Monitor. The other device scanning should
* detect the constant carrier wave from the sending device on the given channel.
* Send a negative number in the Serial Monitor to stop emitting a constant carrier wave
* and resume scanning.
*
* Inspired by cpixip.
* See http://arduino.cc/forum/index.php/topic,54795.0.html
* See https://forum.arduino.cc/t/poor-mans-2-4-ghz-scanner/54846
*
* See documentation at https://nRF24.github.io/RF24
*/

/*
* How to read the output:
* - The header is a list of supported channels in decimal written vertically.
* - Each column corresponding to the vertical header is a hexadecimal count of
* detected signals (max is 15 or 'f').
*
* The following example
* 000
* 111
* 789
* ~~~ <- just a divider between the channel's vertical labels and signal counts
* 1-2
* can be interpreted as
* - 1 signal detected on channel 17
* - 0 signals (denoted as '-') detected on channel 18
* - 2 signals detected on channel 19
*
* Each line of signal counts represent 100 passes of the supported spectrum.
*/

#include "RF24.h"
Expand All @@ -38,76 +62,112 @@ RF24 radio(CE_PIN, CSN_PIN);
// Channel info
//

const uint8_t num_channels = 126;
uint8_t values[num_channels];
const uint8_t num_channels = 126; // 0-125 are supported
uint8_t values[num_channels]; // the array to store summary of signal counts per channel

// To detect noise, we'll use the worst addresses possible (a reverse engineering tactic).
// These addresses are designed to confuse the radio into thinking
// that the RF signal's preamble is part of the packet/payload.
const uint8_t noiseAddress[][2] = { { 0x55, 0x55 }, { 0xAA, 0xAA }, { 0xA0, 0xAA }, { 0xAB, 0xAA }, { 0xAC, 0xAA }, { 0xAD, 0xAA } };

const int num_reps = 100; // number of passes for each scan of the entire spectrum
bool constCarrierMode = 0; // this flag controls example behavior (scan mode is default)

void printHeader(); // prototype function for printing the channels' header

//
// Setup
//

void setup(void) {
//
// Print preamble
//

// Print preamble
Serial.begin(115200);
printf_begin();
Serial.println(F("\n\rRF24/examples/scanner/"));
while (!Serial) {
// some boards need this to wait for Serial connection
}
Serial.println(F("RF24/examples/scanner/"));

//
// Setup and configure rf radio
//
if (!radio.begin()) {
Serial.println(F("radio hardware not responding!"));
while (true) {
// hold in an infinite loop
}
}
radio.stopConstCarrier(); // in case MCU was reset while radio was emitting carrier wave
radio.setAutoAck(false); // Don't acknowledge arbitrary signals
radio.disableCRC(); // Accept any signal we find
radio.setAddressWidth(2); // A reverse engineering tactic (not typically recommended)
for (uint8_t i = 0; i < 6; ++i) {
radio.openReadingPipe(i, noiseAddress[i]);
}

radio.begin();
radio.setAutoAck(false);
// set the data rate
Serial.print(F("Select your Data Rate. "));
Serial.print(F("Enter '1' for 1 Mbps, '2' for 2 Mbps, '3' for 250 kbps. "));
Serial.println(F("Defaults to 1Mbps."));
while (!Serial.available()) {
// wait for user input
}
uint8_t dataRate = Serial.parseInt();
if (dataRate == 50) {
Serial.println(F("Using 2 Mbps."));
radio.setDataRate(RF24_2MBPS);
} else if (dataRate == 51) {
Serial.println(F("Using 250 kbps."));
radio.setDataRate(RF24_250KBPS);
} else {
Serial.println(F("Using 1 Mbps."));
radio.setDataRate(RF24_1MBPS);
}
Serial.println(F("***Enter a channel number to emit a constant carrier wave."));
Serial.println(F("***Enter a negative number to switch back to scanner mode."));

// Get into standby mode
radio.startListening();
radio.stopListening();
radio.printDetails();

//delay(1000);
// Print out header, high then low digit
int i = 0;
while (i < num_channels) {
Serial.print(i >> 4, HEX);
++i;
}
Serial.println();
i = 0;
while (i < num_channels) {
Serial.print(i & 0xf, HEX);
++i;
}
Serial.println();
//delay(1000);
}
radio.flush_rx();

//
// Loop
//
// printf_begin();
// radio.printPrettyDetails();
// delay(1000);

const int num_reps = 100;
bool constCarrierMode = 0;
// Print out vertical header
printHeader();
}

void loop(void) {
/****************************************/
// Send g over Serial to begin CCW output
// Configure the channel and power level below
// Send a number over Serial to begin Constant Carrier Wave output
// Configure the power amplitude level below
if (Serial.available()) {
char c = Serial.read();
if (c == 'g') {
int8_t c = Serial.parseInt();
if (c >= 0) {
c = min(125, max(0, c)); // clamp channel to supported range
constCarrierMode = 1;
radio.stopListening();
delay(2);
Serial.println("Starting Carrier Out");
radio.startConstCarrier(RF24_PA_LOW, 40);
} else if (c == 'e') {
Serial.print("\nStarting Carrier Wave Output on channel ");
Serial.println(c);
// for non-plus models, startConstCarrier() changes address on pipe 0 and sets address width to 5
radio.startConstCarrier(RF24_PA_LOW, c);
} else {
constCarrierMode = 0;
radio.stopConstCarrier();
Serial.println("Stopping Carrier Out");
radio.setAddressWidth(2); // reset address width
radio.openReadingPipe(0, noiseAddress[0]); // ensure address is looking for noise
Serial.println("\nStopping Carrier Wave Output");
printHeader();
}

// discard any CR and LF sent
while (Serial.peek() != -1) {
if (Serial.peek() == '\r' || Serial.peek() == '\n') {
Serial.read();
} else { // got a charater that isn't a line feed
break; // handle it on next loop() iteration
}
}
}

/****************************************/

if (constCarrierMode == 0) {
Expand All @@ -125,27 +185,52 @@ void loop(void) {
// Listen for a little
radio.startListening();
delayMicroseconds(128);
bool foundSignal = radio.testRPD();
radio.stopListening();

// Did we get a carrier?
if (radio.testCarrier()) {
// Did we get a signal?
if (foundSignal || radio.testRPD() || radio.available()) {
++values[i];
radio.flush_rx(); // discard packets of noise
}
}
}


// Print out channel measurements, clamped to a single hex digit
int i = 0;
while (i < num_channels) {
for (int i = 0; i < num_channels; ++i) {
if (values[i])
Serial.print(min(0xf, values[i]), HEX);
else
Serial.print(F("-"));

++i;
}
Serial.println();

} //If constCarrierMode == 0
}
} // if constCarrierMode == 0
else {
// show some output to prove that the program isn't bricked
Serial.print(F("."));
delay(1000); // delay a second to keep output readable
}
} // end loop()

void printHeader() {
// Print the hundreds digits
for (uint8_t i = 0; i < num_channels; ++i)
Serial.print(i / 100);
Serial.println();

// Print the tens digits
for (uint8_t i = 0; i < num_channels; ++i)
Serial.print((i % 100) / 10);
Serial.println();

// Print the singles digits
for (uint8_t i = 0; i < num_channels; ++i)
Serial.print(i % 10);
Serial.println();

// Print the header's divider
for (uint8_t i = 0; i < num_channels; ++i)
Serial.print(F("~"));
Serial.println();
}
Loading

0 comments on commit ef08a40

Please sign in to comment.