aboutsummaryrefslogtreecommitdiff
path: root/src-arduino/rf
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/rf
parent1f800b74329d4f8b1511b4cf2a0d031439e1038d (diff)
restructure to use rust source tree primarily
Diffstat (limited to 'src-arduino/rf')
-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
4 files changed, 599 insertions, 0 deletions
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);