Re-implements envelope detection on top of the rewritten Morse decoder.
Addresses PR #160 review feedback:
- Rebase: rebuilt on current upstream/main (lifecycle state machine)
- Gap thresholds: 2.0/5.0 for envelope only; goertzel keeps 2.6/6.0
- Frequency validation: max_mhz=1766 for envelope, 30 for goertzel
- Tests: EnvelopeDetector unit tests + envelope-mode decoder test
- Envelope uses direct magnitude threshold (no SNR/noise ref)
- Goertzel path completely unchanged
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the stop POST timed out (5s), lifecycle was set to 'idle' on error,
allowing checkStatus to see running=true and reconnect SSE. Now:
- stop .then() stays in 'stopping' on timeout/error instead of going idle
- checkStatus skips reconnect when lifecycle is 'stopping' post-timeout
but still transitions to idle when server confirms running=false
- LOCAL_STOP_TIMEOUT_MS raised from 5s to 12s to match server cleanup time
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous stopPromise guard only prevented new polls from being
dispatched. Polls already in-flight before stop was clicked could still
return with running=true and override the stopping lifecycle, causing
SSE reconnection and an apparent restart loop. Add a second guard in
the .then() handler to check stopPromise/lifecycle before acting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Guard checkStatus() against in-flight stop to prevent status poller
from overriding stopping state and reconnecting SSE. Lower SNR floor
from 1.3 to 1.15 to accommodate weaker CW signals. Add SNR/noise_ref
to scope events and metrics for real-time threshold debugging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Widen noise detector offset from ±100Hz to ±200Hz to reduce spectral
leakage into the noise reference, and scale threshold_multiplier for
SNR space (2.8 → 1.54) so real CW signals reliably trigger tone
detection instead of producing all-E's at 60 WPM.
Fix misleading "decoder startup" timeout message on stop requests and
increase stop timeout from 2.2s to 5s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rtl_fm prints device info, tuning, and errors to stderr but the morse
route only logged these server-side. Now stderr lines are forwarded to
the morse queue as info events, displayed in a compact diagnostic log
below the scope canvas. After 10s with no audio data, the scope text
escalates to prompt the user to check the SDR log.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace blocking rtl_stdout.read() with select()+os.read() so the
decoder thread emits diagnostic heartbeat scope events when rtl_fm
produces no PCM data (common in direct sampling mode). Add waiting-state
rendering in the scope canvas and hide the generic placeholder/status
bar for morse mode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable direct sampling (-D 2) for RTL-SDR at HF frequencies below 24 MHz
so rtl_fm can actually receive CW signals. Add startup health check to
detect immediate rtl_fm failures. Push stopped status event from decoder
thread on EOF so the frontend auto-resets. Add frequency placeholder and
help text. Fix stop button silently swallowing errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix "What's New" section shifting up/down on smaller screens (#157) by
isolating the logo pulse animation to its own compositing layer, stabilizing
the scrollbar gutter, and pinning the welcome container dimensions.
Morse mode improvements: relocate scope and decoded output panels to the
main content area, use shared SDR device controls, and reduce panel heights
for better layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use run-btn/stop-btn classes and bottom placement instead of
btn-primary/btn-danger in a flex section, and preset-btn class
for band presets. Aligns with all other mode panels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New signal mode for decoding Morse code (CW) transmissions via SDR.
Includes route blueprint, utility decoder, frontend UI, and tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>