Просмотр исходного кода

Split span zoom from sample rate control

master
Jan Svabenik 4 дней назад
Родитель
Сommit
57f9b6d8cc
4 измененных файлов: 56 добавлений и 9 удалений
  1. +5
    -0
      cmd/sdrd/main.go
  2. +14
    -4
      internal/sdrplay/sdrplay.go
  3. +23
    -4
      web/app.js
  4. +14
    -1
      web/index.html

+ 5
- 0
cmd/sdrd/main.go Просмотреть файл

@@ -363,6 +363,7 @@ func runDSP(ctx context.Context, src sdr.Source, cfg config.Config, det *detecto
dcEnabled := cfg.DCBlock dcEnabled := cfg.DCBlock
iqEnabled := cfg.IQBalance iqEnabled := cfg.IQBalance


gotSamples := false
for { for {
select { select {
case <-ctx.Done(): 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) log.Printf("read IQ: %v", err)
continue continue
} }
if !gotSamples {
log.Printf("received IQ samples")
gotSamples = true
}
if dcEnabled { if dcEnabled {
dcBlocker.Apply(iq) dcBlocker.Apply(iq)
} }


+ 14
- 4
internal/sdrplay/sdrplay.go Просмотреть файл

@@ -70,6 +70,7 @@ import (
"fmt" "fmt"
"runtime/cgo" "runtime/cgo"
"sync" "sync"
"time"
"unsafe" "unsafe"


"sdr-visual-suite/internal/sdr" "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 { 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) 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 return nil
} }


@@ -200,11 +206,15 @@ func (s *Source) Stop() error {
} }


func (s *Source) ReadIQ(n int) ([]complex64, 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 //export goStreamCallback


+ 23
- 4
web/app.js Просмотреть файл

@@ -16,6 +16,7 @@ const detailSpectrogram = document.getElementById('detailSpectrogram');
const configStatusEl = document.getElementById('configStatus'); const configStatusEl = document.getElementById('configStatus');
const centerInput = document.getElementById('centerInput'); const centerInput = document.getElementById('centerInput');
const spanInput = document.getElementById('spanInput'); const spanInput = document.getElementById('spanInput');
const sampleRateSelect = document.getElementById('sampleRateSelect');
const fftSelect = document.getElementById('fftSelect'); const fftSelect = document.getElementById('fftSelect');
const gainRange = document.getElementById('gainRange'); const gainRange = document.getElementById('gainRange');
const gainInput = document.getElementById('gainInput'); const gainInput = document.getElementById('gainInput');
@@ -87,7 +88,11 @@ function applyConfigToUI(cfg) {
if (!cfg) return; if (!cfg) return;
isSyncingConfig = true; isSyncingConfig = true;
centerInput.value = toMHz(cfg.center_hz).toFixed(6); 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); fftSelect.value = String(cfg.fft_size);
gainRange.value = cfg.gain_db; gainRange.value = cfg.gain_db;
gainInput.value = cfg.gain_db; gainInput.value = cfg.gain_db;
@@ -214,6 +219,9 @@ function renderSpectrum() {
const span = sample_rate / zoom; const span = sample_rate / zoom;
const startHz = center_hz - span / 2 + pan * span; const startHz = center_hz - span / 2 + pan * span;
const endHz = 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 minDb = -120;
const maxDb = 0; const maxDb = 0;
@@ -465,11 +473,22 @@ centerInput.addEventListener('change', () => {


spanInput.addEventListener('change', () => { spanInput.addEventListener('change', () => {
const mhz = parseFloat(spanInput.value); 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', () => { fftSelect.addEventListener('change', () => {
const size = parseInt(fftSelect.value, 10); const size = parseInt(fftSelect.value, 10);
if (Number.isFinite(size)) { if (Number.isFinite(size)) {


+ 14
- 1
web/index.html Просмотреть файл

@@ -30,7 +30,20 @@


<label class="control-label" for="spanInput">Span (MHz)</label> <label class="control-label" for="spanInput">Span (MHz)</label>
<div class="control-row"> <div class="control-row">
<input id="spanInput" type="number" step="0.1" min="0.1" />
<input id="spanInput" type="number" step="0.05" min="0.05" />
</div>

<label class="control-label" for="sampleRateSelect">Sample Rate (MHz)</label>
<div class="control-row">
<select id="sampleRateSelect">
<option value="0.5">0.5</option>
<option value="1.0">1.0</option>
<option value="1.536">1.536</option>
<option value="2.048">2.048</option>
<option value="2.5">2.5</option>
<option value="3.072">3.072</option>
<option value="4.096">4.096</option>
</select>
</div> </div>


<label class="control-label" for="fftSelect">FFT Size</label> <label class="control-label" for="fftSelect">FFT Size</label>


Загрузка…
Отмена
Сохранить