diff --git a/cmd/sdrd/main.go b/cmd/sdrd/main.go index a93709a..2ded0b9 100644 --- a/cmd/sdrd/main.go +++ b/cmd/sdrd/main.go @@ -363,6 +363,7 @@ func runDSP(ctx context.Context, src sdr.Source, cfg config.Config, det *detecto dcEnabled := cfg.DCBlock iqEnabled := cfg.IQBalance + gotSamples := false for { select { case <-ctx.Done(): @@ -385,6 +386,10 @@ func runDSP(ctx context.Context, src sdr.Source, cfg config.Config, det *detecto log.Printf("read IQ: %v", err) continue } + if !gotSamples { + log.Printf("received IQ samples") + gotSamples = true + } if dcEnabled { dcBlocker.Apply(iq) } diff --git a/internal/sdrplay/sdrplay.go b/internal/sdrplay/sdrplay.go index 0b3c95f..1ec53c4 100644 --- a/internal/sdrplay/sdrplay.go +++ b/internal/sdrplay/sdrplay.go @@ -70,6 +70,7 @@ import ( "fmt" "runtime/cgo" "sync" + "time" "unsafe" "sdr-visual-suite/internal/sdr" @@ -134,6 +135,11 @@ func (s *Source) configure(sampleRate int, centerHz float64, gainDb float64) err if err := cErr(C.sdrplay_api_Init(s.dev.dev, &cb, unsafe.Pointer(uintptr(s.handle)))); err != nil { return fmt.Errorf("sdrplay_api_Init: %w", err) } + // Apply initial settings explicitly to ensure streaming starts. + updateReasons := C.int(C.sdrplay_api_Update_Dev_Fs | C.sdrplay_api_Update_Tuner_Frf | C.sdrplay_api_Update_Tuner_Gr | C.sdrplay_api_Update_Ctrl_Agc) + if err := cErr(C.sdrplay_update(unsafe.Pointer(s.dev.dev), updateReasons)); err != nil { + return fmt.Errorf("sdrplay_api_Update: %w", err) + } return nil } @@ -200,11 +206,15 @@ func (s *Source) Stop() error { } func (s *Source) ReadIQ(n int) ([]complex64, error) { - buf := <-s.ch - if len(buf) >= n { - return buf[:n], nil + select { + case buf := <-s.ch: + if len(buf) >= n { + return buf[:n], nil + } + return buf, nil + case <-time.After(1500 * time.Millisecond): + return nil, errors.New("timeout waiting for IQ samples") } - return buf, nil } //export goStreamCallback diff --git a/web/app.js b/web/app.js index ec5d932..cbabf10 100644 --- a/web/app.js +++ b/web/app.js @@ -16,6 +16,7 @@ const detailSpectrogram = document.getElementById('detailSpectrogram'); const configStatusEl = document.getElementById('configStatus'); const centerInput = document.getElementById('centerInput'); const spanInput = document.getElementById('spanInput'); +const sampleRateSelect = document.getElementById('sampleRateSelect'); const fftSelect = document.getElementById('fftSelect'); const gainRange = document.getElementById('gainRange'); const gainInput = document.getElementById('gainInput'); @@ -87,7 +88,11 @@ function applyConfigToUI(cfg) { if (!cfg) return; isSyncingConfig = true; centerInput.value = toMHz(cfg.center_hz).toFixed(6); - spanInput.value = toMHz(cfg.sample_rate).toFixed(3); + if (sampleRateSelect) { + sampleRateSelect.value = toMHz(cfg.sample_rate).toFixed(3).replace(/\.0+$/, '').replace(/\.$/, ''); + } + const spanMHz = toMHz(cfg.sample_rate / zoom); + spanInput.value = spanMHz.toFixed(3); fftSelect.value = String(cfg.fft_size); gainRange.value = cfg.gain_db; gainInput.value = cfg.gain_db; @@ -214,6 +219,9 @@ function renderSpectrum() { const span = sample_rate / zoom; const startHz = center_hz - span / 2 + pan * span; const endHz = center_hz + span / 2 + pan * span; + if (!isSyncingConfig && spanInput) { + spanInput.value = (span / 1e6).toFixed(3); + } const minDb = -120; const maxDb = 0; @@ -465,11 +473,22 @@ centerInput.addEventListener('change', () => { spanInput.addEventListener('change', () => { const mhz = parseFloat(spanInput.value); - if (Number.isFinite(mhz) && mhz > 0) { - queueConfigUpdate({ sample_rate: Math.round(fromMHz(mhz)) }); - } + if (!Number.isFinite(mhz) || mhz <= 0) return; + const baseRate = currentConfig ? currentConfig.sample_rate : (latest ? latest.sample_rate : 0); + if (!baseRate) return; + zoom = Math.max(0.25, Math.min(20, baseRate / fromMHz(mhz))); + timelineDirty = true; }); +if (sampleRateSelect) { + sampleRateSelect.addEventListener('change', () => { + const mhz = parseFloat(sampleRateSelect.value); + if (Number.isFinite(mhz) && mhz > 0) { + queueConfigUpdate({ sample_rate: Math.round(fromMHz(mhz)) }); + } + }); +} + fftSelect.addEventListener('change', () => { const size = parseInt(fftSelect.value, 10); if (Number.isFinite(size)) { diff --git a/web/index.html b/web/index.html index a26654e..000451e 100644 --- a/web/index.html +++ b/web/index.html @@ -30,7 +30,20 @@