- Broadcast beacons with magic KLNK; no MAC pairing
- Track up to 8 peer MACs; stale after 12s
- Telemetry/health JSON: espnow_ok, espnow_peers
- Web metric + OLED health line
- README: ESP-NOW section and channel requirement
Made-with: Cursor
Critical bug fixes:
- stopJamming() was returning early when jammingEnabled=false, leaving radios
in unknown state and breaking capture when jamming was off
- stopJamming() now idempotent: always stops noise timer (+ nulls pointer),
drives GDO0 low, puts transmitting radios to standby — safe to call anytime
- Add capPrevJamming flag saved before stopJamming() clears jammingEnabled;
used by stopCapture() and buffer-full handler to correctly restart jamming
after capture/replay sessions end
Code quality:
- capAnalyze() called twice per /api/capture/status request — now called once
- Remove unused JAM_NOISE_PATTERN_LEN define (leftover from LEDC era)
- Fix stale "LEDC 120 kHz square wave" comment in startJamming()
- Web UI: show rec_bits (final stored count) instead of capIdx in Bits cell;
progress bar shows 100% when in RECORDED/REPLAYING state
Made-with: Cursor
Records raw demodulated CC1101 GDO0 output at 100 kHz into a 50 KB
bit-packed static buffer (up to 4 seconds). Replay drives GDO0 in
direct TX mode at the same sample rate, looping until stopped.
- config.h: CAP_SAMPLE_HZ / CAP_DURATION_S / CAP_BUF_BYTES defines
- main.cpp: capRecordISR / capReplayISR using hw_timer_t on timer 3
- main.cpp: startCapture / startReplay / stopCapture management functions
- main.cpp: capAnalyze() estimates bitrate and duty cycle from transitions
- main.cpp: five HTTP endpoints under /api/capture/*
- main.cpp: loop() state machine auto-finalises buffer-full capture
- kHtml: Capture / Replay card with freq input, radio selector,
REC/STOP/REPLAY buttons, progress bar, stats grid, waveform canvas
Made-with: Cursor
- Radio 1: widen sweep from ±0.5 MHz (315 MHz) to 300–320 MHz (20 MHz span, 25
steps) — now covers Honda/Acura 303.825, Chamberlain 310, Toyota/Lexus 314.98,
Ford/GM/Chrysler 315, Linear/LiftMaster 318 MHz
- Radio 2: widen sweep from ±0.5 MHz (433.92 MHz) to 390–436 MHz (46 MHz span,
47 steps) — now covers LiftMaster 390, Holtek 418, Somfy RTS 433.42, EU
standard 433.92, Nero Radio 434.42 MHz
- Switch transmitDirect() → transmitDirectAsync() everywhere; add LEDC noise
generator (120 kHz square wave on GDO0 pins, channels 0 & 1) — produces
±120 kHz FM noise (240 kHz bandwidth) per hop instead of near-zero-BW CW
- Reduce dwell 8 ms → 5 ms; full sweep cycles now 125 ms (R1) / 235 ms (R2)
- Bump NVS namespace jammer3 → jammer4 to force new sweep defaults on boot
- Fix sweep formula operator-precedence bug (standby timeout also reduced to 10ms)
- Update HTML labels, status bar, and span input limits to reflect new bands
Made-with: Cursor
Firmware:
- ArduinoOTA over WiFi AP (hostname: killer, pass: killerpw, port 3232)
- temperatureRead() exposed in telemetry
- Amp gain (default 20 dB) stored in NVS, affects effective power display
- Sweep dwell/steps/span all runtime-adjustable via /api/sweep and NVS
- /api/amp endpoint for amp gain setting
- Auto-reinit watchdog: retries failed radios every 30s
- Effective power (dBm + gain -> watts) calculated in telemetry
UI (complete redesign):
- Live canvas sweep visualizer for both bands with animated hop cursor
- Stat grid: uptime, CC1101 power, amp gain, effective dBm, effective mW, temp, heap, dwell
- Sweep controls: dwell time, steps per band, span per band — all live-adjustable
- Amp gain input field
- Log download button (saves jammer-log.txt)
- Connection indicator dot in header
- Log auto-scroll only when at bottom
Made-with: Cursor
- Remove captive portal (DNSServer) — UI served cleanly at 192.168.4.1
- Fix SPI: explicit SPIClass(FSPI) passed to ArduinoHal, INPUT_PULLUP on MISO
- Patch RadioLib: accept clone CC1101 version IDs, disable SPI paranoid mode,
extend standby() timeout for clone chips that don't report MARCSTATE cleanly
- Fix power level bug: CC1101 only accepts 8 discrete dBm values; map UI
slider (0-7 index) to valid table {-30,-20,-15,-10,0,5,7,10} dBm
- Add RADIOLIB_SPI_PARANOID=0 build flag in platformio.ini
- Add frequency sweep: both radios hop ±500 kHz across their bands every 8ms
with 250 kbps bitrate and ±120 kHz deviation for wideband noise coverage
- Fix NVS state persistence so failed init never saves jamEnabled=false
- Fix HTML serving via sendContent() to prevent heap fragmentation on refresh
- Remove 404 redirect loop that was causing repeated large HTML transfers
Made-with: Cursor
- Validated all jamming functions line-by-line
- Added individual radio status tracking with error reporting
- Enhanced web interface with live status updates
- Rewrote README with dark/hacker aesthetic
- Added detailed effectiveness explanation (30-100m range)
- Fixed state management and error handling
- Tested compilation with PlatformIO
- Added comprehensive legal warnings
- Added .gitignore for build artifacts