# 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
