| @@ -87,6 +87,7 @@ type Source struct { | |||||
| centerHz float64 | centerHz float64 | ||||
| gainDb float64 | gainDb float64 | ||||
| agc bool | agc bool | ||||
| buf []complex64 | |||||
| } | } | ||||
| func New(sampleRate int, centerHz float64, gainDb float64) (sdr.Source, error) { | func New(sampleRate int, centerHz float64, gainDb float64) (sdr.Source, error) { | ||||
| @@ -135,11 +136,6 @@ 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 | ||||
| } | } | ||||
| @@ -206,14 +202,39 @@ func (s *Source) Stop() error { | |||||
| } | } | ||||
| func (s *Source) ReadIQ(n int) ([]complex64, error) { | func (s *Source) ReadIQ(n int) ([]complex64, error) { | ||||
| select { | |||||
| case buf := <-s.ch: | |||||
| if len(buf) >= n { | |||||
| return buf[:n], nil | |||||
| deadline := time.Now().Add(1500 * time.Millisecond) | |||||
| for { | |||||
| s.mu.Lock() | |||||
| if len(s.buf) >= n { | |||||
| out := make([]complex64, n) | |||||
| copy(out, s.buf[:n]) | |||||
| s.buf = s.buf[n:] | |||||
| s.mu.Unlock() | |||||
| return out, nil | |||||
| } | |||||
| s.mu.Unlock() | |||||
| remaining := time.Until(deadline) | |||||
| if remaining <= 0 { | |||||
| s.mu.Lock() | |||||
| if len(s.buf) > 0 { | |||||
| out := make([]complex64, len(s.buf)) | |||||
| copy(out, s.buf) | |||||
| s.buf = nil | |||||
| s.mu.Unlock() | |||||
| return out, errors.New("timeout waiting for full IQ buffer") | |||||
| } | |||||
| s.mu.Unlock() | |||||
| return nil, errors.New("timeout waiting for IQ samples") | |||||
| } | |||||
| select { | |||||
| case buf := <-s.ch: | |||||
| s.mu.Lock() | |||||
| s.buf = append(s.buf, buf...) | |||||
| s.mu.Unlock() | |||||
| case <-time.After(remaining / 4): | |||||
| } | } | ||||
| return buf, nil | |||||
| case <-time.After(1500 * time.Millisecond): | |||||
| return nil, errors.New("timeout waiting for IQ samples") | |||||
| } | } | ||||
| } | } | ||||