sdr

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 13, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package sdr defines the abstract Device interface for IQ sources and the pool that supervises a fleet of dongles. Concrete drivers (RTL-SDR, mock, future HackRF/Airspy) live in subpackages and register themselves here.

Index

Constants

View Source
const MockDriverName = "mock"
View Source
const MockFloat32DriverName = "mock-f32"

Variables

This section is empty.

Functions

func Register

func Register(d Driver)

Types

type Device

type Device interface {
	Info() Info
	SetCenterFreq(hz uint32) error
	SetSampleRate(hz uint32) error
	SetGain(tenthDB int) error // -1 selects automatic gain control
	SetPPM(ppm int) error
	// SetBiasTee toggles the dongle's 5V bias-tee output (used to
	// power external LNAs through the antenna SMA). Devices without
	// the circuit silently no-op. Implementations should return nil
	// if the underlying driver doesn't model bias-tee at all.
	SetBiasTee(enable bool) error
	StreamIQ(ctx context.Context) (<-chan []complex64, error)
	Close() error
}

Device is the per-dongle handle. Implementations must be safe for the goroutines that call StreamIQ; concurrent SetCenterFreq during streaming is allowed (the underlying USB transport handles it).

type Driver

type Driver interface {
	Name() string
	Enumerate() ([]Info, error)
	Open(idx int) (Device, error)
}

Driver is the factory each backend exposes.

func DriverByName

func DriverByName(name string) (Driver, error)

func Drivers

func Drivers() []Driver

type Hint

type Hint struct {
	Serial  string
	Role    Role
	PPM     int
	Gain    int // tenths of dB; negative = auto
	BiasTee bool
	// contains filtered or unexported fields
}

Hint guides role assignment when opening devices. Match by serial first; fall back to first-found.

PPM, Gain, and BiasTee carry per-device tuning that Pool.Open applies once the device is opened. Gain follows the Device.SetGain convention: a negative value selects automatic gain control. PPM is in parts-per-million; 0 is fine for the TCXO-equipped NESDR Smart v5 and similar dongles.

func (Hint) WithGain

func (h Hint) WithGain(tenthDB int) Hint

WithGain returns a copy of h with Gain set and the gain-set flag flipped so Pool.Open knows to apply it.

type Info

type Info struct {
	Driver       string
	Index        int
	Serial       string
	Manufacturer string
	Product      string
	TunerName    string
	Gains        []int
}

Info describes a discovered device, returned by drivers' enumeration.

func EnumerateAll

func EnumerateAll() []Info

EnumerateAll asks every registered driver to list its devices.

type MockDevice

type MockDevice struct {
	// contains filtered or unexported fields
}

MockDevice replays a single .cfile in real time.

func (*MockDevice) Close

func (d *MockDevice) Close() error

func (*MockDevice) Info

func (d *MockDevice) Info() Info

func (*MockDevice) SetBiasTee

func (d *MockDevice) SetBiasTee(bool) error

func (*MockDevice) SetCenterFreq

func (d *MockDevice) SetCenterFreq(uint32) error

func (*MockDevice) SetGain

func (d *MockDevice) SetGain(int) error

func (*MockDevice) SetPPM

func (d *MockDevice) SetPPM(int) error

func (*MockDevice) SetSampleRate

func (d *MockDevice) SetSampleRate(hz uint32) error

func (*MockDevice) StreamIQ

func (d *MockDevice) StreamIQ(ctx context.Context) (<-chan []complex64, error)

StreamIQ reads the file in chunks of ~16 KiB and meters delivery to roughly match the configured sample rate. Closing the channel signals EOF.

type MockDriver

type MockDriver struct {
	Files []string
}

MockDriver replays unsigned-8-bit IQ files (.cfile / .iq) from a directory. Each file becomes one logical "device". Used for tests and offline replay.

func (*MockDriver) Enumerate

func (m *MockDriver) Enumerate() ([]Info, error)

func (*MockDriver) Name

func (m *MockDriver) Name() string

func (*MockDriver) Open

func (m *MockDriver) Open(idx int) (Device, error)

type MockFloat32Driver

type MockFloat32Driver struct {
	Files []string
}

MockFloat32Driver replays interleaved-float32 IQ files (GNU Radio cfile).

func (*MockFloat32Driver) Enumerate

func (m *MockFloat32Driver) Enumerate() ([]Info, error)

func (*MockFloat32Driver) Name

func (m *MockFloat32Driver) Name() string

func (*MockFloat32Driver) Open

func (m *MockFloat32Driver) Open(idx int) (Device, error)

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool holds a fleet of opened SDR devices and assigns roles.

func NewPool

func NewPool(logger *slog.Logger) *Pool

NewPool constructs an empty pool. The optional bus is used to publish events.KindSDRAttached / events.KindSDRDetached as devices come and go; pass nil to disable that side effect (tests and the `gophertrunk sdr list` CLI both run without a bus).

func (*Pool) AllByRole

func (p *Pool) AllByRole(r Role) []*PoolEntry

AllByRole returns every device with the given role.

func (*Pool) Close

func (p *Pool) Close() error

func (*Pool) Entries

func (p *Pool) Entries() []*PoolEntry

func (*Pool) FindBySerial

func (p *Pool) FindBySerial(serial string) *PoolEntry

FindBySerial returns the entry whose info.Serial matches, or nil. Used by the demod-pipeline composer to look up a Voice device that the engine has just bound to a call.

func (*Pool) FirstByRole

func (p *Pool) FirstByRole(r Role) *PoolEntry

FirstByRole returns the first device with the given role, or nil.

func (*Pool) Open

func (p *Pool) Open(hints []Hint) error

Open enumerates every registered driver, opens devices that match the supplied hints (or simply all of them when hints is empty), and assigns roles. The first opened device gets RoleControl unless a hint says otherwise; subsequent devices get RoleVoice.

func (*Pool) SetBus

func (p *Pool) SetBus(bus *events.Bus)

SetBus attaches an events bus so the pool can publish attach/detach events. Idempotent; passing nil silently disables publishing.

func (*Pool) Snapshot

func (p *Pool) Snapshot() []SDRStatus

Snapshot returns a status payload for every entry currently in the pool. Safe to call concurrently with Open / Close.

type PoolEntry

type PoolEntry struct {
	Driver Driver
	Device Device
	Info   Info
	Role   Role
	Hint   Hint
}

PoolEntry tracks a single discovered-and-opened device along with its role.

Hint carries the per-device tuning the pool applied at Open time so a later Snapshot can render gain/PPM/bias-tee state without having to query the underlying chip.

func (*PoolEntry) Snapshot

func (e *PoolEntry) Snapshot(attached bool) SDRStatus

Snapshot returns the wire-format status payload for this entry. Used by the API's GET /api/v1/devices handler and the bus payload on the sdr.attached / sdr.detached events.

attached == true is the normal "device is in the pool" case; the detached snapshot published by Pool.Close passes false.

type Role

type Role int
const (
	RoleAuto Role = iota
	RoleControl
	RoleVoice
)

func ParseRole

func ParseRole(s string) Role

func (Role) String

func (r Role) String() string

type SDRStatus

type SDRStatus struct {
	Driver       string `json:"driver"`
	Serial       string `json:"serial"`
	Manufacturer string `json:"manufacturer,omitempty"`
	Product      string `json:"product,omitempty"`
	TunerName    string `json:"tuner_name,omitempty"`
	Role         string `json:"role"`
	Attached     bool   `json:"attached"`

	// Configured hint values applied at open time. PPM is in
	// parts-per-million; GainTenthDB follows the SetGain convention
	// (negative = AGC). BiasTee reflects whether the YAML asked the
	// pool to enable the 5 V output.
	GainTenthDB int  `json:"gain_tenth_db"`
	GainAuto    bool `json:"gain_auto"`
	PPM         int  `json:"ppm"`
	BiasTee     bool `json:"bias_tee"`

	// Gains is the tuner's quantized gain ladder (tenths of dB),
	// useful for UIs that want to render valid choices.
	Gains []int `json:"gains,omitempty"`
}

SDRStatus is the per-device snapshot the pool publishes on the events bus when a device is opened or closed, and the same payload returned by GET /api/v1/devices. Fields that are unknown at snapshot time (e.g. the daemon never programmed a gain because the YAML left it blank) are zero-valued; consumers should treat that as "default" / "unset" rather than "explicitly zero".

The shape mirrors the `gophertrunk.v1.SDRStatus` proto message but keeps the JSON layer self-contained so the api package doesn't have to import the pb generated types just to render the response.

Directories

Path Synopsis
purego
Package purego is the pure-Go RTL-SDR driver — the sdr.Device / sdr.Driver implementation that composes the platform USB transport (internal/sdr/rtlsdr/usb), the RTL2832U register layer (internal/sdr/rtlsdr/rtl2832u), and the per-chip tuner drivers (internal/sdr/rtlsdr/tuners).
Package purego is the pure-Go RTL-SDR driver — the sdr.Device / sdr.Driver implementation that composes the platform USB transport (internal/sdr/rtlsdr/usb), the RTL2832U register layer (internal/sdr/rtlsdr/rtl2832u), and the per-chip tuner drivers (internal/sdr/rtlsdr/tuners).
rtl2832u
Package rtl2832u is the pure-Go register / I2C-bridge layer that sits between the platform USB transport (internal/sdr/rtlsdr/usb) and the per-tuner drivers.
Package rtl2832u is the pure-Go register / I2C-bridge layer that sits between the platform USB transport (internal/sdr/rtlsdr/usb) and the per-tuner drivers.
tuners
Package tuners houses the per-chip tuner drivers that sit between the RTL2832U register layer (internal/sdr/rtlsdr/rtl2832u) and the top-level [sdr.Device].
Package tuners houses the per-chip tuner drivers that sit between the RTL2832U register layer (internal/sdr/rtlsdr/rtl2832u) and the top-level [sdr.Device].
usb
Package usb is the platform-abstraction layer that the pure-Go RTL-SDR driver speaks to.
Package usb is the platform-abstraction layer that the pure-Go RTL-SDR driver speaks to.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL