|
|
|
@@ -110,6 +110,7 @@ type PlutoDriver struct { |
|
|
|
phyDev uintptr // iio_device* (ad9361-phy) |
|
|
|
chanI uintptr // iio_channel* TX I |
|
|
|
chanQ uintptr // iio_channel* TX Q |
|
|
|
chanLO uintptr // iio_channel* TX LO (altvoltage1), cached for Tune() |
|
|
|
buf uintptr // iio_buffer* |
|
|
|
bufSize int // samples per buffer push |
|
|
|
|
|
|
|
@@ -204,6 +205,7 @@ func (d *PlutoDriver) Configure(_ context.Context, cfg platform.SoapyConfig) err |
|
|
|
|
|
|
|
// TX LO frequency |
|
|
|
phyChanLO := d.findChannel(phyDev, "altvoltage1", true) // TX LO |
|
|
|
d.chanLO = phyChanLO // cache for Tune() |
|
|
|
if phyChanLO != 0 { |
|
|
|
freqHz := int64(cfg.CenterFreqHz) |
|
|
|
if freqHz <= 0 { |
|
|
|
@@ -371,14 +373,21 @@ func (d *PlutoDriver) Flush(_ context.Context) error { return nil } |
|
|
|
func (d *PlutoDriver) Tune(_ context.Context, freqHz float64) error { |
|
|
|
d.mu.Lock() |
|
|
|
defer d.mu.Unlock() |
|
|
|
if d.phyDev == 0 { |
|
|
|
return fmt.Errorf("pluto: not configured") |
|
|
|
if !d.configured || d.chanLO == 0 { |
|
|
|
return fmt.Errorf("pluto: not configured or LO channel not available") |
|
|
|
} |
|
|
|
if d.lib.pChannelAttrWriteLongLong == nil { |
|
|
|
return fmt.Errorf("pluto: iio_channel_attr_write_longlong not loaded") |
|
|
|
} |
|
|
|
phyChanLO := d.findChannel(d.phyDev, "altvoltage1", true) |
|
|
|
if phyChanLO == 0 { |
|
|
|
return fmt.Errorf("pluto: TX LO channel not found") |
|
|
|
cAttr, _ := syscall.BytePtrFromString("frequency") |
|
|
|
ret, _, _ := d.lib.pChannelAttrWriteLongLong.Call( |
|
|
|
d.chanLO, |
|
|
|
uintptr(unsafe.Pointer(cAttr)), |
|
|
|
uintptr(int64(freqHz)), |
|
|
|
) |
|
|
|
if int32(ret) < 0 { |
|
|
|
return fmt.Errorf("pluto: LO tune to %.0f Hz failed (iio rc=%d)", freqHz, int32(ret)) |
|
|
|
} |
|
|
|
d.writeChanAttrLL(phyChanLO, "frequency", int64(freqHz)) |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
@@ -420,6 +429,7 @@ func (d *PlutoDriver) cleanup() { |
|
|
|
d.disableChannel(d.chanQ) |
|
|
|
d.chanQ = 0 |
|
|
|
} |
|
|
|
d.chanLO = 0 // config-only channel, no disable needed |
|
|
|
if d.ctx != 0 && d.lib.pDestroyCtx != nil { |
|
|
|
d.lib.pDestroyCtx.Call(d.ctx) |
|
|
|
d.ctx = 0 |
|
|
|
|