overwrite remote with local version
This commit is contained in:
@@ -1,103 +0,0 @@
|
||||
## Potential bugs / edge cases (firmware + UI)
|
||||
|
||||
**Scope**: This file lists things that look *potentially* wrong, brittle, or surprising in the current codebase. None of these are confirmed failures on your hardware; they are review notes and future-hardening targets.
|
||||
|
||||
---
|
||||
|
||||
### 1. Capture / replay concurrency and timing
|
||||
|
||||
- **Non-atomic shared counters between ISR and main loop**
|
||||
- `capIdx`, `capTransitions`, and `capLongRuns` are updated in `capRecordISR()` and read from the main loop / OLED / HTTP handlers without any critical section.
|
||||
- On ESP32, aligned 32‑bit loads/stores are usually atomic, but you can still observe off‑by‑one or partially updated values when reading while the ISR is running.
|
||||
- **Risk**: Displayed progress / bitrate / squelch metrics can be slightly wrong or jittery while recording. Functionally low‑risk, but it’s technically a race.
|
||||
|
||||
- **~~Capture analysis first bit~~** — addressed: bit 0 is now included in the `ones` count.
|
||||
|
||||
- **Bitrate assumptions vs real keyfob signals**
|
||||
- Capture is hard‑wired at `CAP_SAMPLE_HZ = 100000` (100 kHz) with a fixed 4‑second window.
|
||||
- Many car fobs run significantly faster than 10 kbit/s; very high data‑rate or very short packets can alias or barely fill the buffer before the squelch decides “signal caught”.
|
||||
- **Risk**: Certain high‑rate or exotic protocols may be captured with degraded timing or not detected by the long‑run squelch at all.
|
||||
|
||||
---
|
||||
|
||||
### 2. Interaction between jamming and capture / replay
|
||||
|
||||
- **State restoration depends on `capPrevJamming` flag only**
|
||||
- `startCapture()` and `startReplay()` store `capPrevJamming = jammingEnabled` before calling `stopJamming()`, and `stopCapture()` uses that flag to restart jamming.
|
||||
- If another part of the system toggles `jammingEnabled` while capture is in progress (e.g. a web API call), `capPrevJamming` can become stale and the final jamming state after STOP may not match user expectations.
|
||||
- **Risk**: Rare UX bug where jamming ends up on/off opposite to what the web UI last requested when you mix capture/replay and manual toggles aggressively.
|
||||
|
||||
- **GDO0 direction flips vs noise ISR**
|
||||
- `noiseISR()` drives both `CC1101_*_GDO0` pins every 20 µs during jamming, but capture/replay reconfigures those same pins as input/output for bit‑banging.
|
||||
- The code tries to prevent overlap by calling `stopJamming()` before touching the capture timer and then restoring pin direction, but this depends on `stopJamming()` always fully killing `s_noiseTimer` first.
|
||||
- **Risk**: If `stopJamming()` ever early‑returns or is modified later, you could get noise ISR writes colliding with capture/replay GPIO direction changes. Right now it looks correct, but it’s a fragile area to touch.
|
||||
|
||||
---
|
||||
|
||||
### 3. Fast sweep / VCO cache (removed in current firmware)
|
||||
|
||||
Jamming is **fixed dual-carrier** (315 MHz + 433.92 MHz); `buildSweepTable`, `tickSweepFast`, and sweep tables are **not present**. The web “Apply Sweep” path still stores dwell/steps/span in NVS but does **not** affect jam TX.
|
||||
|
||||
If sweeps are **reintroduced**, restore bounded step counts, `setFrequency` error checks, and VCO cal timeouts.
|
||||
|
||||
---
|
||||
|
||||
### 3b. CC1101 (TI SWRS061) — fixed-carrier notes
|
||||
|
||||
- **LO / PLL**: Channel frequency is `FREQ2:FREQ1:FREQ0` after RadioLib `setFrequency`. Large temperature swing can drift the VCO vs a trim-heavy fob RX; optional future work is periodic `SCAL` or re-init (not done here).
|
||||
- **DEVIAT**: FM deviation for the LFSR async TX path is `JAM_DEV_KHZ_R1_NARROW` vs `JAM_DEV_KHZ_R2_WIDE` in `config.h`. If 315 MHz jam feels weak, raise R1 deviation toward R2.
|
||||
- **PATABLE**: Explicit burst PATABLE is used for **OOK replay** only; jam uses direct async + RadioLib defaults unless you add more SPI.
|
||||
- **SPI / GDO0**: Noise ISR only toggles GDO0 GPIOs; register SPI stays on the main thread — keep it that way when editing `stopJamming` / capture.
|
||||
|
||||
---
|
||||
|
||||
### 4. Timer usage and ISR safety
|
||||
|
||||
- **Multiple hardware timers, no central ownership tracking**
|
||||
- Timer 2 is used for `noiseISR()`; timer 3 is used for `capRecordISR()`/`capReplayISR()`. Each `*_Start()` tears down and re‑creates its timer instance.
|
||||
- There is no global check to prevent future code from reusing the same timer IDs for something else; reuse would race with the existing teardown, especially if done from another task.
|
||||
- **Risk**: Currently safe as long as no new timers are introduced. Future features must avoid timer IDs 2 and 3 or add a small timer allocation helper.
|
||||
|
||||
- **GPIO driver calls from ISRs**
|
||||
- `noiseISR()` and `capReplayISR()` call `gpio_set_level()` directly from IRAM ISRs.
|
||||
- On ESP32 the GPIO driver is generally ISR‑safe and IRAM‑resident, but this depends on IDF/Arduino internals. If the platform evolves or gets misconfigured (e.g. non‑IRAM gpio functions), these ISRs could start hitting flash and cause WDT resets under load.
|
||||
- **Risk**: Low on current IDF/Arduino, but this is one of the first places to check if you ever see random WDT resets under heavy jamming.
|
||||
|
||||
---
|
||||
|
||||
### 5. Web UI / HTTP handlers
|
||||
|
||||
- **Log text is built with `String` and served as a big blob**
|
||||
- `getLogsText()` builds a single large `String` (`reserve(4096)`) and returns it for `/log` downloads.
|
||||
- On its own this is fine, but if log lines become much longer than expected or you ever increase `LOG_LINES`, the 4 KB reserve may under‑estimate and cause heap fragmentation again.
|
||||
- **Risk**: Potential future fragmentation if log length grows substantially; currently appears safe with short 100‑line logs.
|
||||
|
||||
- **AP password is a hard‑coded weak string**
|
||||
- `WIFI_AP_PASS` is literally `"password"`.
|
||||
- **Risk**: Anyone in RF range can connect to the AP and control the jammer UI. For a lab toy this is fine; for anything outside a controlled environment this is a security hole.
|
||||
|
||||
---
|
||||
|
||||
### 6. OLED and rotary encoder
|
||||
|
||||
- **Encoder ISR uses `digitalRead()` twice per detent**
|
||||
- `encISR()` calls `digitalRead(ENC_CLK_PIN)` and `digitalRead(ENC_DT_PIN)` directly; those are relatively slow, and they’re called from an ISR.
|
||||
- **Risk**: Under high interrupt storm (very fast dial spins) you could see jitter or missed ticks. This is more of a performance nit than a hard bug, but it’s the weak point of the input path.
|
||||
|
||||
- **Notifications can delay page auto‑advance longer than expected**
|
||||
- `oledNotify()` sets `oledPageMs = notifEnd`, and the auto‑advance check uses `now > notifEnd && now - oledPageMs >= 8000`.
|
||||
- After a long notification (e.g. multiple back‑to‑back events), page cycling waits an extra 8 seconds after the last notification before moving again.
|
||||
- **Risk**: UX oddity where pages seem “stuck” on status after a burst of notifications; not a functional bug.
|
||||
|
||||
---
|
||||
|
||||
### 7. Miscellaneous assumptions
|
||||
|
||||
- **Radio init retries are hard‑coded to 3 attempts**
|
||||
- `startJamming()` retries `radio.begin(...)` up to 3 times with 50 ms between attempts.
|
||||
- **Risk**: If a board needs a longer warm‑up (slow 3V3 rail, bad caps), you might hit a permanent “Init failed” state when a slightly longer retry or backoff would have recovered.
|
||||
|
||||
- **Power math in health screen clips at 9999 mW**
|
||||
- Effective mW is computed from dBm and then clamped at 9999: any higher values silently display `XXXX / 9999mW` style numbers.
|
||||
- **Risk**: Pure cosmetic; if you ever configured absurd gain values in the UI the display no longer reflects the math exactly.
|
||||
|
||||
@@ -24,81 +24,40 @@
|
||||
// Web server
|
||||
#define WEB_PORT 80
|
||||
|
||||
// Jamming configuration
|
||||
#define JAMMING_ENABLED true // Start jamming immediately on boot
|
||||
// CC1101 only accepts 8 discrete power levels (index 0-7):
|
||||
// { -30, -20, -15, -10, 0, 5, 7, 10 } dBm
|
||||
// Jamming: max CC1101 TX (+10 dBm). External PA removed — radiated power is chip + antenna gain only.
|
||||
#define DEFAULT_AUTO_START_JAM false // NVS key autoStartJam; do not jam until user enables or saves auto-start
|
||||
// CC1101 only accepts 8 discrete power levels (index 0-7); jam path always uses max (10 dBm).
|
||||
#define JAM_POWER_LEVELS 8
|
||||
#define DEFAULT_JAM_POWER_IDX 7 // index into power table (7 = 10 dBm, max)
|
||||
// External amplifier gain in dB (used only for display — does not affect CC1101 output)
|
||||
#define DEFAULT_AMP_GAIN_DB 20
|
||||
#define DEFAULT_JAM_POWER_IDX 7 // 10 dBm — full device output (see TI SWRS061 PATABLE / output power)
|
||||
|
||||
// Modulation parameters for jamming (LFSR drives GDO0 in direct async TX)
|
||||
#define JAM_BITRATE_KBPS 250.0f // baseband / channel filter context for RadioLib begin()
|
||||
#define JAM_FREQ_DEV_KHZ 380.0f // default passed to begin(); per-radio deviation applied after init
|
||||
#define JAM_RX_BW_KHZ 812.0f // wide RX BW for begin()
|
||||
|
||||
// Fixed dual-carrier jamming — NO sweep: each radio holds one frequency at full TX power.
|
||||
// CC1101: see TI doc SWRS061 (single-chip low-cost UHF transceiver). FM deviation maps
|
||||
// to DEVIAT; carrier to FREQ2:0; async serial TX uses GDO0 as modulator input (RadioLib).
|
||||
// R2 (433.92) uses max deviation = loudest/widest noise; R1 (315) uses narrow deviation.
|
||||
// Fixed dual-carrier jamming: each radio holds one frequency at full TX power (TI CC1101 freq + deviation).
|
||||
#define JAM_LOCK_FREQ_1_MHZ 315.0f
|
||||
#define JAM_LOCK_FREQ_2_MHZ 433.92f
|
||||
#define JAM_DEV_KHZ_R2_WIDE 380.0f // CC1101 max — "baby screaming" on EU/global fob channel
|
||||
#define JAM_DEV_KHZ_R1_NARROW 25.0f // minimal FM swing — energy concentrated on NA 315 MHz
|
||||
|
||||
// Legacy sweep constants (NVS + API still accept them; firmware no longer hops)
|
||||
// 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
|
||||
//
|
||||
// With 1 MHz/hop: 25 steps × 0.83 MHz spacing → solid overlap, 75ms full cycle at 3ms dwell
|
||||
#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, well within 1 MHz hop bandwidth
|
||||
|
||||
// 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
|
||||
//
|
||||
// With 1 MHz/hop: 60 steps × 0.77 MHz spacing → no gaps, 180ms full cycle at 3ms dwell
|
||||
#define SWEEP_2_CENTER_MHZ 413.0f
|
||||
#define SWEEP_2_SPAN_MHZ 46.0f // 390–436 MHz
|
||||
#define SWEEP_2_STEPS 60 // increased from 47 for guaranteed overlap
|
||||
|
||||
// Dwell per hop — 3ms balances CC1101 lock time vs cycle speed
|
||||
// Full cycle: R1 = 75ms, R2 = 180ms → any target frequency is jammed at least every 180ms
|
||||
// Car fob TX window is typically 200–500ms so every transmission gets hit
|
||||
#define SWEEP_DWELL_MS 3
|
||||
#define JAM_DEV_KHZ_R2_WIDE 380.0f
|
||||
#define JAM_DEV_KHZ_R1_NARROW 25.0f
|
||||
|
||||
// 0.96" SSD1306 OLED display — I2C via SW_I2C (any free GPIO)
|
||||
// Wiring: VCC→3V3, GND→GND, SDA→GPIO17, SCL→GPIO18
|
||||
#define OLED_SDA_PIN 17
|
||||
#define OLED_SCL_PIN 18
|
||||
|
||||
// Rotary encoder — dial to cycle OLED pages
|
||||
// Wiring: CLK→GPIO14, DT→GPIO21, GND→GND (both pins use internal pull-ups)
|
||||
#define ENC_CLK_PIN 14
|
||||
#define ENC_DT_PIN 21
|
||||
|
||||
// Signal capture / replay
|
||||
// Samples GDO0 (CC1101 demodulated output) at CAP_SAMPLE_HZ during direct RX mode.
|
||||
// Bit-packed into a static buffer. Replay drives GDO0 in direct TX mode at same rate.
|
||||
#define CAP_SAMPLE_HZ 100000 // 100 kHz sample clock
|
||||
#define CAP_DURATION_S 4 // max capture window (seconds)
|
||||
#define CAP_BUF_BYTES ((CAP_SAMPLE_HZ * CAP_DURATION_S) / 8 + 8) // ~50 KB
|
||||
#define CAP_SAMPLE_HZ 100000
|
||||
#define CAP_DURATION_S 4
|
||||
#define CAP_BUF_BYTES ((CAP_SAMPLE_HZ * CAP_DURATION_S) / 8 + 8)
|
||||
#define CAP_HISTORY_MAX 8
|
||||
|
||||
// ESP-NOW mesh: auto-discover other boards on same firmware (same AP WiFi channel)
|
||||
#define ESPNOW_BEACON_MS 750 // broadcast presence interval
|
||||
#define ESPNOW_PEER_STALE_MS 12000 // drop peer if silent this long
|
||||
#define ESPNOW_MAX_PEERS 8 // max other nodes tracked (4+ boards)
|
||||
// ESP-NOW mesh
|
||||
#define ESPNOW_BEACON_MS 750
|
||||
#define ESPNOW_PEER_STALE_MS 12000
|
||||
#define ESPNOW_MAX_PEERS 8
|
||||
|
||||
#endif
|
||||
|
||||
772
src/main.cpp
772
src/main.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user