- R1 locks 315 MHz with narrow FM deviation + LFSR; R2 locks 433.92 with max deviation - Remove VCO sweep tables, tickSweepFast, and hop loop; ~2.4KB RAM saved - Telemetry jam_fixed + graph centers on lock freqs; UI/OLED/README updated - Apply Sweep only persists NVS; power changes re-apply lock freqs/deviations Made-with: Cursor
438 lines
15 KiB
Markdown
438 lines
15 KiB
Markdown
# CAR-KEY-KILLER
|
|
|
|
Dual-band RF jamming system for automotive key fob frequencies.
|
|
ESP32-S3 + dual CC1101 + external amplifiers + OLED display + web interface.
|
|
|
|
---
|
|
|
|
## WHAT IT DOES
|
|
|
|
Most car key fobs that matter for NA vs EU/global boil down to two on-air
|
|
channels: about **315 MHz** (North America) and **433.92 MHz** (Europe and much
|
|
of the rest of the world).
|
|
|
|
This firmware **does not sweep** those bands anymore. Each CC1101 **locks** on
|
|
one frequency and stays there at full configured TX power:
|
|
|
|
Radio 1 315.000 MHz Narrow FM deviation + Galois LFSR on GDO0
|
|
(energy concentrated on the NA fob channel)
|
|
|
|
Radio 2 433.920 MHz Maximum CC1101 FM deviation + same LFSR
|
|
(wide, loud noise on the dominant EU/global ISM fob channel)
|
|
|
|
Both antennas scream continuously while jamming is enabled — no hopping, no
|
|
dwell time, no split energy across a span. The web UI and OLED show these as
|
|
locked carriers (`jam_fixed` in telemetry).
|
|
|
|
---
|
|
|
|
## HARDWARE
|
|
|
|
[BILL OF MATERIALS]
|
|
|
|
1 x ESP32-S3 DevKitC-1 (16MB Flash, 8MB PSRAM)
|
|
2 x CC1101 transceiver module (Texas Instruments)
|
|
2 x RF power amplifier module (+20 dB gain, 433/315 MHz rated)
|
|
1 x 0.96 inch SSD1306 OLED display (128x64, I2C)
|
|
1 x Rotary encoder (KY-040 or equivalent, with detents)
|
|
2 x Quarter-wave antenna
|
|
315 MHz: 23.8 cm wire or tuned whip
|
|
433 MHz: 17.3 cm wire or tuned whip
|
|
1 x USB power supply, 5V 2A minimum
|
|
|
|
---
|
|
|
|
## PIN MAPPING
|
|
|
|
[SPI BUS - shared between both CC1101 modules]
|
|
|
|
GPIO 11 MOSI
|
|
GPIO 12 SCK
|
|
GPIO 13 MISO
|
|
|
|
[CC1101 NUMBER 1 - 315 MHz locked jam]
|
|
|
|
GPIO 7 CS (chip select, dedicated)
|
|
GPIO 4 GDO0 (LFSR noise into direct async TX)
|
|
3V3 VCC
|
|
GND GND
|
|
|
|
[CC1101 NUMBER 2 - 433.92 MHz locked jam]
|
|
|
|
GPIO 8 CS (chip select, dedicated)
|
|
GPIO 5 GDO0 (LFSR noise into direct async TX)
|
|
3V3 VCC
|
|
GND GND
|
|
|
|
[RF AMPLIFIERS]
|
|
|
|
Inline between each CC1101 ANT pin and its antenna.
|
|
VCC from 3V3 or 5V depending on amplifier module spec.
|
|
+20 dB gain each. Default effective output: 10 + 20 = 30 dBm.
|
|
|
|
[OLED DISPLAY - 0.96 inch SSD1306]
|
|
|
|
GPIO 17 SDA
|
|
GPIO 18 SCL
|
|
3V3 VCC
|
|
GND GND
|
|
|
|
[ROTARY ENCODER]
|
|
|
|
GPIO 14 CLK
|
|
GPIO 21 DT
|
|
GND GND
|
|
(internal pull-ups active, no external resistors needed)
|
|
|
|
---
|
|
|
|
## JAMMING PARAMETERS
|
|
|
|
[RF CONFIGURATION]
|
|
|
|
Carrier plan Radio 1 locked 315.000 MHz, Radio 2 locked 433.920 MHz
|
|
Modulation FM from Galois LFSR bitstream on GDO0 (direct async TX)
|
|
Deviation R1 25 kHz (narrow — energy on 315)
|
|
Deviation R2 380 kHz (CC1101 max — wide noise on 433.92)
|
|
LFSR clock 50 kHz (hardware timer ISR)
|
|
Bitrate (RadioLib) 250 kbps context for begin()
|
|
RX bandwidth 812 kHz (maximum)
|
|
TX power -30 / -20 / -15 / -10 / 0 / 5 / 7 / 10 dBm (8 steps)
|
|
Default TX power 10 dBm
|
|
Amplifier gain +20 dB (configurable in web UI)
|
|
Effective output 30 dBm / ~1 Watt (with amplifiers, at 10 dBm TX)
|
|
|
|
[LEGACY SWEEP SETTINGS IN WEB UI / NVS]
|
|
|
|
Dwell, steps, and span are still saved to NVS if you use Apply Sweep.
|
|
Fixed-carrier jamming does not use them. Tunables are in config.h:
|
|
JAM_LOCK_FREQ_1_MHZ, JAM_LOCK_FREQ_2_MHZ, JAM_DEV_KHZ_R1_NARROW,
|
|
JAM_DEV_KHZ_R2_WIDE.
|
|
|
|
---
|
|
|
|
## OLED DISPLAY
|
|
|
|
The 0.96 inch OLED runs three cycling pages. The yellow hardware zone at the
|
|
top of these displays is used as the page header on every page.
|
|
Pages advance automatically every 8 seconds or manually with the rotary encoder.
|
|
Three dot indicators in the header show the current page.
|
|
|
|
[PAGE 0 - STATUS] (default)
|
|
|
|
Header: inverted bar reading LOCKED JAM when running, STANDBY when not
|
|
Row 1: ANT1 current frequency in MHz with animated radio-wave arcs
|
|
Row 2: ANT2 current frequency in MHz with animated radio-wave arcs
|
|
Row 3: TX power breakdown: radio dBm + amp gain = effective dBm
|
|
Row 4: 315 + 433.92 LOCK badge when both radios active, else temp and heap
|
|
Row 5: uptime since boot
|
|
|
|
[PAGE 1 - FREQ AND HOPS]
|
|
|
|
Header: FREQ AND HOPS
|
|
R1 current frequency and total hop count since boot
|
|
R2 current frequency and total hop count since boot
|
|
Estimated total hops per second
|
|
|
|
[PAGE 2 - SYSTEM HEALTH]
|
|
|
|
Header: SYS HEALTH
|
|
Temperature (ESP32-S3 internal sensor, Celsius)
|
|
Heap: current free KB and minimum recorded KB
|
|
Uptime: hours, minutes, seconds
|
|
Effective power: dBm and milliwatts
|
|
WiFi clients connected to the AP
|
|
|
|
[BOOT SEQUENCE]
|
|
|
|
The display shows synchronous status messages during boot:
|
|
SPI init, WiFi AP start, Radio 1 init, Radio 2 init, final state.
|
|
|
|
[NOTIFICATIONS]
|
|
|
|
Full-screen inverted overlay appears for 2.5 seconds on:
|
|
- Jamming started or stopped
|
|
- TX power level changed
|
|
- Radio reinitialization triggered by watchdog
|
|
- Signal detected during capture
|
|
- Capture/Replay started or stopped
|
|
|
|
---
|
|
|
|
## CAPTURE AND REPLAY
|
|
|
|
The system includes a fully autonomous signal capture mode for recording and
|
|
replaying raw fob signals directly into the ESP32 RAM.
|
|
|
|
[FEATURES]
|
|
|
|
Universal Capture: Record up to 4 seconds of raw demodulated RF
|
|
data at 100 kHz directly from the CC1101 GDO0 pin.
|
|
|
|
Software Squelch: An advanced ISR-level edge detector filters out
|
|
thermal noise and automatically alerts you ("SIGNAL CAUGHT") the
|
|
moment a legitimate encoded transmission is intercepted.
|
|
|
|
Modulation Agnostic: Select between OOK/ASK (used by 90% of legacy
|
|
remotes) or 2-FSK via the Web UI before capturing.
|
|
|
|
Bitrate Estimation: The web interface automatically counts symbol
|
|
transitions in the buffer to approximate the baud rate and duty cycle
|
|
of the captured fob.
|
|
|
|
Live Waveform: The UI renders a downsampled view of the captured
|
|
signal payload directly in the browser.
|
|
|
|
Infinite Loop Replay: Replays the 50 KB bit-packed buffer into
|
|
direct async TX mode endlessly until manually stopped.
|
|
|
|
---
|
|
|
|
## WEB INTERFACE
|
|
|
|
Connect to the WiFi access point, then open the control panel in a browser.
|
|
|
|
SSID: killer
|
|
Password: password
|
|
IP: 192.168.4.1
|
|
mDNS: http://killer.local
|
|
OTA port: 3232
|
|
|
|
[CONTROLS]
|
|
|
|
Start / Stop jamming toggle
|
|
TX power selector (8 levels: -30 dBm to 10 dBm)
|
|
Amplifier gain input (dB, affects displayed effective power only)
|
|
Sweep tuning fields (legacy — stored in NVS only, not used for jam)
|
|
All settings persist to NVS on save
|
|
|
|
[VISUALIZATIONS]
|
|
|
|
Two canvas displays show a narrow window around each locked carrier (markers
|
|
for common fob channels still drawn where they fall in range).
|
|
Canvas height 90px, updates every 1 second with telemetry.
|
|
|
|
Two sparkline charts showing 2-minute rolling history:
|
|
Temperature (Celsius)
|
|
Free heap (KB)
|
|
|
|
[METRICS GRID - stats updated every 1 second]
|
|
|
|
Effective TX power (dBm)
|
|
Radio 1 status
|
|
Radio 2 status
|
|
ESP32 temperature (color coded: white normal, yellow warn, red critical)
|
|
Free heap KB (color coded)
|
|
Minimum heap KB recorded
|
|
Hop count Radio 1 (total since boot)
|
|
Hop count Radio 2 (total since boot)
|
|
Hop counters (stay at 0 in fixed-carrier mode; kept for API compatibility)
|
|
WiFi clients on AP
|
|
Nodes (ESP-NOW): count of other boards running this firmware in range
|
|
Jam mode: LOCKED when jam_fixed is true in telemetry
|
|
Uptime
|
|
24-hour mission progress bar in the header
|
|
|
|
[LOGS]
|
|
|
|
Timestamped log ring buffer, last 50 entries.
|
|
Format: [HH:MM:SS] message
|
|
Refreshes every 5 seconds.
|
|
Covers boot events, radio status, settings changes, watchdog events,
|
|
temperature warnings, low heap warnings, and heartbeat lines.
|
|
|
|
---
|
|
|
|
## ESP-NOW NODE MESH
|
|
|
|
Multiple boards running the same firmware discover each other automatically
|
|
over ESP-NOW. No MAC address entry and no pairing step.
|
|
|
|
How it works:
|
|
Each unit broadcasts a small beacon every 750 ms to the ESP-NOW
|
|
broadcast address. The payload starts with a fixed magic signature
|
|
so only this firmware is counted.
|
|
When a unit hears a valid beacon, it records the sender MAC and
|
|
refreshes a last-seen time. The web UI metric "Nodes (ESP-NOW)" is
|
|
the number of other units heard within the last 12 seconds.
|
|
The OLED health page shows the same count after "ESPNOW".
|
|
|
|
Requirements for links to work:
|
|
All units must share the same Wi-Fi radio channel as the soft-AP.
|
|
This build starts the AP on channel 1. Do not run different channel
|
|
settings on different boards unless you change the code consistently.
|
|
Range is typical 2.4 GHz ESP-NOW range (often tens of meters indoors,
|
|
more line-of-sight).
|
|
|
|
Note: This release only counts peers and logs new MACs. It does not yet
|
|
sync jamming state or share telemetry over ESP-NOW.
|
|
|
|
---
|
|
|
|
## RELIABILITY FEATURES (24-HOUR OPERATION)
|
|
|
|
The system is designed to run unattended at full power indefinitely.
|
|
|
|
Watchdog timer Detects radio lock-up, reinitializes both CC1101s
|
|
Low heap protection Reboots cleanly if free heap drops below 15 KB
|
|
Temperature alarm Logs warning if internal temp exceeds 75 C
|
|
Temperature alarm rate limit Warning logged at most once per minute
|
|
Radio status flags Tracks per-radio TX state, triggers reinit on fail
|
|
NVS persistence All settings survive power cycles and reboots
|
|
ArduinoOTA Firmware can be updated over WiFi without USB
|
|
Heap tracking Records minimum heap ever seen since boot
|
|
Hop counting Per-radio total hop counts logged and displayed
|
|
|
|
---
|
|
|
|
## BUILD AND FLASH
|
|
|
|
[REQUIREMENTS]
|
|
|
|
PlatformIO Core or PlatformIO IDE (VS Code extension)
|
|
USB cable to ESP32-S3 DevKitC-1
|
|
|
|
[COMMANDS]
|
|
|
|
pio run --target upload flash firmware
|
|
pio device monitor serial monitor at 115200 baud
|
|
pio run --target clean clean build artifacts
|
|
|
|
[BUILD NOTES]
|
|
|
|
The project sets build_dir to /Users/drjones/.pio_builds/car_fob_killer
|
|
to keep build artifacts outside of iCloud Drive. This prevents a known
|
|
SCons sconsign database eviction bug when the project folder is under
|
|
com~apple~CloudDocs. If you move the project, update build_dir in
|
|
platformio.ini accordingly.
|
|
|
|
[LIBRARIES]
|
|
|
|
RadioLib patched fork (CC1101 direct async TX support)
|
|
U8g2 OLED display driver
|
|
Preferences NVS storage wrapper
|
|
ArduinoOTA over-the-air firmware updates
|
|
Wire I2C bus for OLED
|
|
WebServer HTTP server for control panel
|
|
WiFi SoftAP mode
|
|
ESPmDNS killer.local hostname
|
|
|
|
---
|
|
|
|
## SOFTWARE ARCHITECTURE
|
|
|
|
[FILE STRUCTURE]
|
|
|
|
src/main.cpp all firmware logic
|
|
include/config.h pin definitions, frequency and RF parameters, defaults
|
|
platformio.ini build config, library dependencies, build_dir override
|
|
|
|
[KEY FUNCTIONS IN MAIN.CPP]
|
|
|
|
startJamming() initializes both CC1101s, locks freqs, sets deviation, async TX
|
|
oledTick() OLED update loop, handles pages and notifications
|
|
oledDrawStatus() page 0 renderer
|
|
oledDrawFreq() page 1 renderer
|
|
oledDrawHealth() page 2 renderer
|
|
oledNotify() queues a full-screen notification
|
|
oledBootMsg() synchronous boot status message
|
|
encISR() rotary encoder interrupt service routine
|
|
handleToggle() HTTP handler: start/stop jamming
|
|
handleSettings() HTTP handler: update TX power
|
|
handleTelemetry() HTTP handler: JSON status for web UI polling
|
|
handleLogs() HTTP handler: timestamped log ring buffer
|
|
handleRoot() HTTP handler: serves embedded web UI HTML
|
|
logLine() timestamped log entry to ring buffer and Serial
|
|
loop() ESP-NOW tick, HTTP, OLED, capture FSM, watchdog
|
|
|
|
[JAM TIMING]
|
|
|
|
Carriers are fixed after startJamming(); no hop loop. LFSR ISR runs at 50 kHz.
|
|
|
|
---
|
|
|
|
## CONFIGURATION REFERENCE
|
|
|
|
Key defines in include/config.h:
|
|
|
|
CC1101_1_CS GPIO 7 chip select, Radio 1
|
|
CC1101_1_GDO0 GPIO 4 data pin, Radio 1
|
|
CC1101_2_CS GPIO 8 chip select, Radio 2
|
|
CC1101_2_GDO0 GPIO 5 data pin, Radio 2
|
|
SPI_MOSI_PIN GPIO 11
|
|
SPI_SCK_PIN GPIO 12
|
|
SPI_MISO_PIN GPIO 13
|
|
OLED_SDA_PIN GPIO 17
|
|
OLED_SCL_PIN GPIO 18
|
|
ENC_CLK_PIN GPIO 14
|
|
ENC_DT_PIN GPIO 21
|
|
|
|
WIFI_AP_SSID killer
|
|
WIFI_AP_PASS password
|
|
WEB_PORT 80
|
|
|
|
JAM_BITRATE_KBPS 250.0
|
|
JAM_FREQ_DEV_KHZ 380.0 (CC1101 maximum)
|
|
JAM_RX_BW_KHZ 812.0 (CC1101 maximum)
|
|
SWEEP_DWELL_MS 3
|
|
SWEEP_1_CENTER_MHZ 310.0
|
|
SWEEP_1_SPAN_MHZ 20.0
|
|
SWEEP_1_STEPS 25
|
|
SWEEP_2_CENTER_MHZ 413.0
|
|
SWEEP_2_SPAN_MHZ 46.0
|
|
SWEEP_2_STEPS 60
|
|
DEFAULT_JAM_POWER_IDX 7 (index into CC1101 power table, 7 = 10 dBm)
|
|
DEFAULT_AMP_GAIN_DB 20
|
|
JAMMING_ENABLED true (start transmitting immediately on boot)
|
|
|
|
---
|
|
|
|
## TROUBLESHOOTING
|
|
|
|
[Radios not initializing]
|
|
Check SPI wiring: MOSI=11, SCK=12, MISO=13.
|
|
Verify CS pins: GPIO7 for Radio1, GPIO8 for Radio2.
|
|
Both CC1101s must be powered from 3V3, not 5V.
|
|
Check serial output at 115200 baud for specific RadioLib error codes.
|
|
|
|
[OLED blank after flash]
|
|
Verify wiring: SDA=GPIO17, SCL=GPIO18, VCC=3V3.
|
|
Firmware probes both 0x3C and 0x3D. Check serial for OLED found message.
|
|
Most 0.96 inch SSD1306 modules run on 3V3 VCC.
|
|
|
|
[Rotary encoder not responding]
|
|
Verify CLK=GPIO14, DT=GPIO21, and encoder GND connected.
|
|
No pull-up resistors needed, internal pull-ups are enabled in firmware.
|
|
Turn slowly - one detent at a time changes page.
|
|
|
|
[Web UI not loading]
|
|
Connect to WiFi SSID "killer", password "password".
|
|
Navigate to http://192.168.4.1 or http://killer.local.
|
|
Only one device can use the AP at a time.
|
|
|
|
[OTA update failing]
|
|
Device must be powered on and jamming (or standby).
|
|
Use PlatformIO OTA upload target, hostname "killer", port 3232.
|
|
|
|
[Build fails with sconsign error]
|
|
iCloud Drive evicts SCons temp files. Ensure build_dir in platformio.ini
|
|
points to a non-iCloud path. Current setting: /Users/drjones/.pio_builds/car_fob_killer
|
|
|
|
---
|
|
|
|
## LEGAL
|
|
|
|
Operation of intentional radio frequency jammers is illegal in most jurisdictions
|
|
without specific government authorization. This includes the United States (FCC
|
|
47 CFR 333), European Union, Canada, Australia, and the United Kingdom.
|
|
|
|
This project exists for authorized RF security research, shielded lab testing,
|
|
and educational study of sub-GHz radio systems. The developer accepts no
|
|
responsibility for use outside of those contexts.
|
|
|
|
---
|
|
|
|
## REPOSITORY
|
|
|
|
https://gitea.thetempleofdoom.com/drjones/car-key-killer.git
|