diff --git a/include/config.h b/include/config.h index 020611d..968b65c 100644 --- a/include/config.h +++ b/include/config.h @@ -40,18 +40,29 @@ #define JAM_FREQ_DEV_KHZ 120.0f // Wide deviation = covers ~240 kHz per hop #define JAM_RX_BW_KHZ 812.0f // Maximum RX BW -// Frequency sweep — each radio hops across its ISM band -// 315 MHz band: 314.0 – 316.0 MHz (US key fobs cluster here) -#define SWEEP_1_CENTER_MHZ 315.0f -#define SWEEP_1_SPAN_MHZ 1.0f // ±0.5 MHz around center -#define SWEEP_1_STEPS 5 // number of hop points +// Frequency sweep — full coverage of all known car-key-fob sub-GHz bands +// +// Radio 1 (CC1101 #1) — 300–320 MHz [CC1101 Band 1: 300–348 MHz] +// Honda/Acura (US): 303.825 MHz +// Chamberlain/LiftMaster: 310.0 MHz +// Toyota/Lexus/Scion: 314.98 MHz +// Ford/GM/Chrysler/Dodge/Jeep: 315.0 MHz +// Linear Delta-3 / LiftMaster: 318.0 MHz +#define SWEEP_1_CENTER_MHZ 310.0f +#define SWEEP_1_SPAN_MHZ 20.0f // 300–320 MHz +#define SWEEP_1_STEPS 25 // ~0.83 MHz/step — overlaps 812 kHz RX BW -// 433 MHz band: 433.05 – 434.79 MHz (EU/global key fobs) -#define SWEEP_2_CENTER_MHZ 433.92f -#define SWEEP_2_SPAN_MHZ 1.0f -#define SWEEP_2_STEPS 5 +// Radio 2 (CC1101 #2) — 390–436 MHz [CC1101 Band 2: 387–464 MHz] +// Chamberlain/LiftMaster: 390.0 MHz +// Holtek-based remotes: 418.0 MHz +// Somfy RTS / SMC 5326: 433.42 MHz +// Global standard (BMW/VW/Audi/Mercedes/Hyundai/Kia…): 433.92 MHz +// Nero Radio / some Asian fobs: 434.42 MHz +#define SWEEP_2_CENTER_MHZ 413.0f +#define SWEEP_2_SPAN_MHZ 46.0f // 390–436 MHz +#define SWEEP_2_STEPS 47 // ~1 MHz/step // How long to dwell on each hop frequency (ms) -#define SWEEP_DWELL_MS 8 +#define SWEEP_DWELL_MS 5 #endif diff --git a/src/main.cpp b/src/main.cpp index 334c691..8a92cb6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,6 +108,9 @@ static String jsonEscape(const String& in) { return out; } +// Forward declarations +static void noiseGenStart(); + // Manually probe a CC1101 via raw SPI to verify bus connectivity. // Reads the VERSION register (0xF1 = burst read of reg 0x31). // Returns the raw byte, or 0xFF if bus appears dead. @@ -185,32 +188,36 @@ static void startJamming() { int stTx1 = RADIOLIB_ERR_NONE; int stTx2 = RADIOLIB_ERR_NONE; + // Start async direct TX — GDO0 becomes serial-data input, LEDC drives it with + // a 120 kHz square wave producing ±120 kHz FM noise instead of narrow-band CW. + noiseGenStart(); + if (radio1Status == 1) { - stTx1 = radio1.transmitDirect(); + stTx1 = radio1.transmitDirectAsync(); if (stTx1 != RADIOLIB_ERR_NONE) { radio1Status = -1; radio1Error = "Transmit failed: " + String(stTx1); - logLine("[R1] transmitDirect failed: " + String(stTx1)); + logLine("[R1] transmitDirectAsync failed: " + String(stTx1)); } else { radio1Status = 2; // Transmitting } } if (radio2Status == 1) { - stTx2 = radio2.transmitDirect(); + stTx2 = radio2.transmitDirectAsync(); if (stTx2 != RADIOLIB_ERR_NONE) { radio2Status = -1; radio2Error = "Transmit failed: " + String(stTx2); - logLine("[R2] transmitDirect failed: " + String(stTx2)); + logLine("[R2] transmitDirectAsync failed: " + String(stTx2)); } else { radio2Status = 2; // Transmitting } } if (radio1Status == 2 || radio2Status == 2) { - logLine("[JAM] Jamming active:"); - logLine("[JAM] Radio 1: 315 MHz at " + String(jamPower) + " dBm (status: " + String(radio1Status == 2 ? "TX" : "FAIL") + ")"); - logLine("[JAM] Radio 2: 433.92 MHz at " + String(jamPower) + " dBm (status: " + String(radio2Status == 2 ? "TX" : "FAIL") + ")"); + logLine("[JAM] Jamming active (async FM noise mode):"); + logLine("[JAM] Radio 1: sweep 300-320 MHz at " + String(jamPower) + " dBm (status: " + String(radio1Status == 2 ? "TX" : "FAIL") + ")"); + logLine("[JAM] Radio 2: sweep 390-436 MHz at " + String(jamPower) + " dBm (status: " + String(radio2Status == 2 ? "TX" : "FAIL") + ")"); } else { logLine("[JAM] Both radios failed to start - check SPI connections"); logLine("[JAM] R1 error: " + radio1Error); @@ -251,10 +258,30 @@ static void stopJamming() { } } + // Release GDO0 noise PWM so pins return to normal GPIO + ledcDetachPin(CC1101_1_GDO0); + ledcDetachPin(CC1101_2_GDO0); + jammingEnabled = false; logLine("[JAM] Jamming stopped"); } +// Drive each CC1101's GDO0 pin with a 120 kHz square wave (LEDC channels 0 & 1). +// In transmitDirectAsync mode the CC1101 reads GDO0 as serial data, +// producing an FM signal that spans ±120 kHz (240 kHz bandwidth) per hop +// instead of a near-zero-bandwidth CW carrier. +static void noiseGenStart() { + ledcDetachPin(CC1101_1_GDO0); // safe no-op if not yet attached + ledcDetachPin(CC1101_2_GDO0); + // 120 kHz = CC1101 deviation → full ±f_dev FM modulation, 50% duty = symmetric 2-tone + ledcSetup(0, 120000, 8); // LEDC channel 0: 120 kHz, 8-bit + ledcAttachPin(CC1101_1_GDO0, 0); + ledcWrite(0, 128); // 50% duty cycle (128/256) + ledcSetup(1, 120000, 8); // LEDC channel 1: same + ledcAttachPin(CC1101_2_GDO0, 1); + ledcWrite(1, 128); +} + // Update jamming power; idx is 0-7 mapping to kPowerTable dBm values. static void updateJamPower(uint8_t idx) { if (idx >= JAM_POWER_LEVELS) idx = JAM_POWER_LEVELS - 1; @@ -343,7 +370,7 @@ const char kHtml[] = R"HTML(

CC1101 JAMMER

-
ESP32-S3 • 315 MHz + 433.92 MHz • Dual-band simultaneous sweep
+
ESP32-S3 • 300-320 MHz + 390-436 MHz • Dual-band FM-noise sweep
@@ -374,12 +401,12 @@ const char kHtml[] = R"HTML(

Live Frequency Sweep

-
Radio 1 — 315 MHz band
+
Radio 1 — 300–320 MHz (US: Honda 303.8, Toyota 315, Ford/GM 315, Linear 318)
-
Radio 2 — 433.92 MHz band
+
Radio 2 — 390–436 MHz (LiftMaster 390, Holtek 418, Somfy 433.4, EU 433.9, Nero 434.4)
@@ -390,12 +417,12 @@ const char kHtml[] = R"HTML(

Radio Status

-
Radio 1 — 315 MHz
+
Radio 1 — 300–320 MHz
-
Radio 2 — 433.92 MHz
+
Radio 2 — 390–436 MHz
@@ -440,8 +467,8 @@ const char kHtml[] = R"HTML(
- - + +
@@ -521,8 +548,8 @@ function applyTelemetry(t) { bt.textContent='JAMMING ACTIVE'; bt.style.color='#86f28a'; const freqs=[]; - if (t.radio1_active) freqs.push('315 MHz'); - if (t.radio2_active) freqs.push('433.92 MHz'); + if (t.radio1_active) freqs.push('300-320 MHz'); + if (t.radio2_active) freqs.push('390-436 MHz'); bs.textContent=freqs.length ? `${freqs.join(' + ')} | ${t.jam_power} dBm + ${t.amp_gain_db}dB = ${t.eff_power_dbm}dBm (${(t.eff_power_w*1000).toFixed(0)} mW)` : 'No radios active'; bs.style.color=freqs.length?'#86f28a':'#bf4f59'; } else { @@ -856,7 +883,7 @@ void setup() { uptimeStart = millis(); // Load preferences - preferences.begin("jammer3", false); + preferences.begin("jammer4", false); jammingEnabled = preferences.getBool("jamEnabled", JAMMING_ENABLED); jamPowerIdx = (uint8_t)preferences.getInt("jamPowerIdx", DEFAULT_JAM_POWER_IDX); ampGainDb = (int8_t) preferences.getInt("ampGainDb", DEFAULT_AMP_GAIN_DB); @@ -987,11 +1014,12 @@ static void tickSweep(CC1101& radio, uint8_t& step, uint8_t steps, if (now - lastMs < sweepDwellMs) return; lastMs = now; - float freq = center - (span / 2.0f) + (span / max((uint8_t)2, steps) - 1) * step; + const float divisor = (steps > 1) ? (float)(steps - 1) : 1.0f; + float freq = center - (span / 2.0f) + (span / divisor) * (float)step; if (fabsf(freq - curFreq) > 0.001f) { radio.standby(); if (radio.setFrequency(freq) == RADIOLIB_ERR_NONE) { - radio.transmitDirect(); + radio.transmitDirectAsync(); curFreq = freq; } } @@ -1042,8 +1070,8 @@ void loop() { } else if (cmd == "status") { Serial.println("Jamming: " + String(jammingEnabled ? "ON" : "OFF")); Serial.println("Power: " + String(jamPower) + " dBm"); - Serial.println("Radio 1 (315 MHz): " + String(jammingEnabled ? "TRANSMITTING" : "STANDBY")); - Serial.println("Radio 2 (433.92 MHz): " + String(jammingEnabled ? "TRANSMITTING" : "STANDBY")); + Serial.println("Radio 1 (300-320 MHz): " + String(jammingEnabled ? "TRANSMITTING" : "STANDBY")); + Serial.println("Radio 2 (390-436 MHz): " + String(jammingEnabled ? "TRANSMITTING" : "STANDBY")); } } }