sdrconnect

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 27, 2026 License: MIT Imports: 12 Imported by: 0

README

sdrconnect

Go client library for the SDRconnect WebSocket API.

Install

go get github.com/carlos-andres-osorio/sdrconnect

Usage

import "github.com/carlos-andres-osorio/sdrconnect"

cfg := &sdrconnect.Config{Host: "localhost", Port: 5454}
client := sdrconnect.NewClient(cfg, nil)

ctx := context.Background()
if err := client.Connect(ctx); err != nil {
    log.Fatal(err)
}
defer client.Close()

props := sdrconnect.NewProperties(ctx, client, nil)

hz, err := props.GetVFOFrequency(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("VFO: %d Hz\n", hz)

API

  • Client — manages the persistent WebSocket connection with automatic reconnection
  • Properties — typed get/set helpers (GetVFOFrequency, SetLNAState, etc.) with response correlation
  • Streamer — demuxes binary frames (IQ, audio, spectrum FFT) into typed buffers

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrClientClosed = errors.New("sdrconnect: client closed")

ErrClientClosed is returned by Send when the client has been shut down.

View Source
var ErrGetTimeout = errors.New("sdrconnect: get_property timed out")

ErrGetTimeout is returned by GetProperty when no response arrives within the deadline.

Functions

This section is empty.

Types

type BinaryFrame

type BinaryFrame struct {
	Type    FrameType
	Payload []byte // everything after the 2-byte type prefix
}

BinaryFrame is a raw binary WebSocket frame with its type tag parsed.

type Client

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

Client manages a persistent WebSocket connection to SDRconnect.

func NewClient

func NewClient(cfg *Config, logger *slog.Logger) *Client

NewClient creates a Client. Call Connect to establish the WebSocket connection.

func (*Client) Binary

func (c *Client) Binary() <-chan BinaryFrame

Binary returns the channel for incoming binary frames from SDRconnect.

func (*Client) Close

func (c *Client) Close() error

Close initiates graceful shutdown. It is idempotent.

func (*Client) Connect

func (c *Client) Connect(ctx context.Context) error

Connect dials SDRconnect and starts background goroutines. It blocks until the first connection succeeds or ctx is cancelled.

func (*Client) Connected

func (c *Client) Connected() bool

Connected reports whether the client currently has an active WebSocket connection.

func (*Client) Done

func (c *Client) Done() <-chan struct{}

Done returns a channel that closes when the client has fully shut down.

func (*Client) Send

func (c *Client) Send(ctx context.Context, env Envelope) error

Send enqueues an Envelope to be sent as a JSON text frame. Returns ErrClientClosed if the client has been shut down.

func (*Client) Text

func (c *Client) Text() <-chan Envelope

Text returns the channel for incoming JSON messages from SDRconnect.

type Config

type Config struct {
	Host string // WebSocket host (e.g. "localhost")
	Port int    // WebSocket port (e.g. 5454)
}

Config holds the connection parameters for a Client.

type DemodMode

type DemodMode string

DemodMode represents a demodulator mode string accepted by the "demodulator" property.

const (
	DemodAM  DemodMode = "AM"
	DemodUSB DemodMode = "USB"
	DemodLSB DemodMode = "LSB"
	DemodCW  DemodMode = "CW"
	DemodSAM DemodMode = "SAM"
	DemodNFM DemodMode = "NFM"
	DemodWFM DemodMode = "WFM"
)

Demodulator modes accepted by the "demodulator" property.

type Envelope

type Envelope struct {
	EventType EventType    `json:"event_type"`
	Property  PropertyName `json:"property"`
	Value     string       `json:"value"`
}

Envelope is the common JSON wrapper for all SDRconnect WebSocket messages.

func NewGetProperty

func NewGetProperty(prop PropertyName) Envelope

NewGetProperty builds a get_property envelope.

func NewSetDemodulator

func NewSetDemodulator(mode DemodMode) Envelope

NewSetDemodulator builds a set_property envelope for the demodulator property.

func NewSetProperty

func NewSetProperty(prop PropertyName, value string) Envelope

NewSetProperty builds a set_property envelope.

func NewStartRecording

func NewStartRecording(rt RecordingType) Envelope

NewStartRecording builds a start_recording envelope for the given recording format.

func NewStopRecording

func NewStopRecording() Envelope

NewStopRecording builds a stop_recording envelope.

func NewStreamControl

func NewStreamControl(event EventType, enable bool) Envelope

NewStreamControl builds a stream-enable/disable envelope. Valid event types: EventIQStreamEnable, EventAudioStreamEnable, EventSpectrumEnable, EventDeviceStreamEnable.

type EventType

type EventType string

EventType identifies the kind of WebSocket message.

const (
	EventSetProperty          EventType = "set_property"
	EventGetProperty          EventType = "get_property"
	EventIQStreamEnable       EventType = "iq_stream_enable"
	EventAudioStreamEnable    EventType = "audio_stream_enable"
	EventSpectrumEnable       EventType = "spectrum_enable"
	EventDeviceStreamEnable   EventType = "device_stream_enable"
	EventStartRecording       EventType = "start_recording"
	EventStopRecording        EventType = "stop_recording"
	EventApplyDeviceProfile   EventType = "apply_device_profile"
	EventSelectedDevice       EventType = "selected_device"
	EventSelectedDeviceSerial EventType = "selected_device_serial"
)

Client-to-server event types.

const (
	EventPropertyChanged     EventType = "property_changed"
	EventGetPropertyResponse EventType = "get_property_response"
)

Server-to-client event types.

type FrameType

type FrameType uint16

FrameType is the little-endian uint16 tag prefixed to binary WebSocket frames.

const (
	FrameAudio    FrameType = 1 // Signed 16-bit PCM stereo @ 48 kHz, interleaved L R L R
	FrameIQ       FrameType = 2 // Signed 16-bit interleaved IQ (I Q I Q)
	FrameSpectrum FrameType = 3 // Unsigned 8-bit spectrum FFT bins, normalised to visible range
)

Binary frame type tags (little-endian uint16 prefix on binary WebSocket frames).

type Properties

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

Properties wraps Client with typed get/set helpers and response correlation. It consumes the client's Text() channel and fans messages out to registered subscribers and pending GetProperty waiters.

func NewProperties

func NewProperties(ctx context.Context, client *Client, logger *slog.Logger) *Properties

NewProperties creates a Properties dispatcher backed by client and starts its internal dispatch goroutine. The dispatcher runs until ctx is cancelled. Pass nil for logger to use slog.Default().

func (*Properties) GetCenterFrequency

func (p *Properties) GetCenterFrequency(ctx context.Context) (uint64, error)

GetCenterFrequency returns device_center_frequency as a uint64 (Hz).

func (*Properties) GetDemodulator

func (p *Properties) GetDemodulator(ctx context.Context) (DemodMode, error)

GetDemodulator returns the current demodulator mode.

func (*Properties) GetFilterBandwidth

func (p *Properties) GetFilterBandwidth(ctx context.Context) (int, error)

GetFilterBandwidth returns filter_bandwidth as an int (Hz).

func (*Properties) GetLNAState

func (p *Properties) GetLNAState(ctx context.Context) (int, error)

GetLNAState returns lna_state as an int.

func (*Properties) GetLNAStateMax

func (p *Properties) GetLNAStateMax(ctx context.Context) (int, error)

GetLNAStateMax returns lna_state_max as an int (maximum valid LNA state index).

func (*Properties) GetLNAStateMin

func (p *Properties) GetLNAStateMin(ctx context.Context) (int, error)

GetLNAStateMin returns lna_state_min as an int (minimum valid LNA state index).

func (*Properties) GetOverload

func (p *Properties) GetOverload(ctx context.Context) (bool, error)

GetOverload returns the overload property as a bool. true means the ADC is currently overloaded.

func (*Properties) GetProperty

func (p *Properties) GetProperty(ctx context.Context, name PropertyName) (string, error)

GetProperty sends a get_property request and waits for the matching get_property_response. If ctx has no deadline, a 5-second timeout is applied.

Note: SDRconnect has no request correlation IDs, so a stale echo arriving after a reconnect may satisfy a fresh waiter. Callers should re-read critical properties after detecting a reconnect.

func (*Properties) GetSignalPower

func (p *Properties) GetSignalPower(ctx context.Context) (float64, error)

GetSignalPower returns signal_power as a float64 (dBm).

func (*Properties) GetSignalSNR

func (p *Properties) GetSignalSNR(ctx context.Context) (float64, error)

GetSignalSNR returns signal_snr as a float64 (dB).

func (*Properties) GetVFOFrequency

func (p *Properties) GetVFOFrequency(ctx context.Context) (uint64, error)

GetVFOFrequency returns device_vfo_frequency as a uint64 (Hz).

func (*Properties) SetAGCEnable

func (p *Properties) SetAGCEnable(ctx context.Context, enable bool) error

SetAGCEnable sets agc_enable.

func (*Properties) SetAGCThreshold

func (p *Properties) SetAGCThreshold(ctx context.Context, db int) error

SetAGCThreshold sets agc_threshold (dBm).

func (*Properties) SetAudioMute

func (p *Properties) SetAudioMute(ctx context.Context, mute bool) error

SetAudioMute sets audio_mute.

func (*Properties) SetAudioVolume

func (p *Properties) SetAudioVolume(ctx context.Context, percent int) error

SetAudioVolume sets audio_volume_percent (0–100).

func (*Properties) SetCenterFrequency

func (p *Properties) SetCenterFrequency(ctx context.Context, hz uint64) error

SetCenterFrequency sets device_center_frequency.

func (*Properties) SetDemodulator

func (p *Properties) SetDemodulator(ctx context.Context, mode DemodMode) error

SetDemodulator sets the demodulator mode.

func (*Properties) SetFilterBandwidth

func (p *Properties) SetFilterBandwidth(ctx context.Context, hz int) error

SetFilterBandwidth sets filter_bandwidth.

func (*Properties) SetLNAState

func (p *Properties) SetLNAState(ctx context.Context, state int) error

SetLNAState sets lna_state.

func (*Properties) SetNoiseReductionEnable

func (p *Properties) SetNoiseReductionEnable(ctx context.Context, enable bool) error

SetNoiseReductionEnable sets noise_reduction_enable.

func (*Properties) SetNoiseReductionStrength

func (p *Properties) SetNoiseReductionStrength(ctx context.Context, strength int) error

SetNoiseReductionStrength sets noise_reduction_strength.

func (*Properties) SetProperty

func (p *Properties) SetProperty(ctx context.Context, name PropertyName, value string) error

SetProperty sends a set_property request. It returns nil once the request has been enqueued for transmission, not once SDRconnect has applied the value. Callers that need confirmation should follow up with GetProperty.

func (*Properties) SetSquelchEnable

func (p *Properties) SetSquelchEnable(ctx context.Context, enable bool) error

SetSquelchEnable sets squelch_enable.

func (*Properties) SetSquelchThreshold

func (p *Properties) SetSquelchThreshold(ctx context.Context, db int) error

SetSquelchThreshold sets squelch_threshold (dBm).

func (*Properties) SetVFOFrequency

func (p *Properties) SetVFOFrequency(ctx context.Context, hz uint64) error

SetVFOFrequency sets device_vfo_frequency.

func (*Properties) Subscribe

func (p *Properties) Subscribe() <-chan Envelope

Subscribe returns a channel that receives all incoming text messages. The channel has a buffer; slow readers silently drop messages. There is no unsubscribe mechanism — the channel and its goroutine must remain live for the lifetime of the Properties dispatcher.

type PropertyName

type PropertyName string

PropertyName identifies a controllable or readable SDRconnect property.

const (
	PropVFOFrequency      PropertyName = "device_vfo_frequency"
	PropCenterFrequency   PropertyName = "device_center_frequency"
	PropSampleRate        PropertyName = "device_sample_rate"
	PropLNAState          PropertyName = "lna_state"
	PropLNAStateMin       PropertyName = "lna_state_min"
	PropLNAStateMax       PropertyName = "lna_state_max"
	PropFilterBandwidth   PropertyName = "filter_bandwidth"
	PropDemodulator       PropertyName = "demodulator"
	PropDemodMaxBandwidth PropertyName = "demod_max_bandwidth"
	PropStarted           PropertyName = "started"
	PropOverload          PropertyName = "overload"
	PropCanControl        PropertyName = "can_control"
)

Device and tuning properties.

const (
	PropAudioVolumePercent PropertyName = "audio_volume_percent"
	PropAudioMute          PropertyName = "audio_mute"
	PropAudioLimiters      PropertyName = "audio_limiters"
	PropAudioFilter        PropertyName = "audio_filter"
	PropSquelchEnable      PropertyName = "squelch_enable"
	PropSquelchThreshold   PropertyName = "squelch_threshold"
	PropAGCEnable          PropertyName = "agc_enable"
	PropAGCThreshold       PropertyName = "agc_threshold"
	PropWFMStereoEnable    PropertyName = "wfm_stereo_enable"
)

Audio and squelch properties.

const (
	PropSignalPower PropertyName = "signal_power"
	PropSignalSNR   PropertyName = "signal_snr"
	PropWFMStereo   PropertyName = "wfm_stereo"
)

Signal measurement properties (read-only).

const (
	PropNoiseReductionEnable   PropertyName = "noise_reduction_enable"
	PropNoiseReductionStrength PropertyName = "noise_reduction_strength"
	PropNFMDeemphasisEnable    PropertyName = "nfm_deemphasis_enable"
)

Signal processing properties.

const (
	PropSpectrumRefLevel PropertyName = "spectrum_ref_level"
	PropSpectrumBase     PropertyName = "spectrum_base"
)

Spectrum display properties.

const (
	PropRDSPS     PropertyName = "rds_ps"
	PropRDSPI     PropertyName = "rds_pi"
	PropRDSEnable PropertyName = "rds_enable"
)

RDS properties.

const (
	PropAMLowcutFrequency  PropertyName = "am_lowcut_frequency"
	PropSSBLowcutFrequency PropertyName = "ssb_lowcut_frequency"
	PropNFMLowcutFrequency PropertyName = "nfm_lowcut_frequency"
)

Low-cut filter properties.

type RecordingType

type RecordingType string

RecordingType represents a recording format accepted by start_recording.

const (
	RecordingIQ              RecordingType = "iq"
	RecordingAudio           RecordingType = "audio"
	RecordingCompressedAudio RecordingType = "compressed_audio"
)

Recording types accepted by start_recording.

type Streamer

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

Streamer demuxes binary frames from a Client and buffers the latest spectrum, audio, and IQ snapshots.

func NewStreamer

func NewStreamer(ctx context.Context, c *Client, logger *slog.Logger) *Streamer

NewStreamer starts consuming binary frames from c in the background. It stops when ctx is cancelled or Close is called.

func (*Streamer) Close

func (s *Streamer) Close()

Close stops the streamer and waits for the background goroutine to exit.

func (*Streamer) DisableAudio

func (s *Streamer) DisableAudio(ctx context.Context) error

DisableAudio sends an audio_stream_enable=false command to SDRconnect.

func (*Streamer) DisableDeviceStream

func (s *Streamer) DisableDeviceStream(ctx context.Context) error

DisableDeviceStream sends a device_stream_enable=false command to SDRconnect.

func (*Streamer) DisableIQ

func (s *Streamer) DisableIQ(ctx context.Context) error

DisableIQ sends an iq_stream_enable=false command to SDRconnect.

func (*Streamer) DisableSpectrum

func (s *Streamer) DisableSpectrum(ctx context.Context) error

DisableSpectrum sends a spectrum_enable=false command to SDRconnect.

func (*Streamer) EnableAudio

func (s *Streamer) EnableAudio(ctx context.Context) error

EnableAudio sends an audio_stream_enable=true command to SDRconnect.

func (*Streamer) EnableDeviceStream

func (s *Streamer) EnableDeviceStream(ctx context.Context) error

EnableDeviceStream sends a device_stream_enable=true command to SDRconnect. Device streaming must be enabled before the device produces any signal data.

func (*Streamer) EnableIQ

func (s *Streamer) EnableIQ(ctx context.Context) error

EnableIQ sends an iq_stream_enable=true command to SDRconnect.

func (*Streamer) EnableSpectrum

func (s *Streamer) EnableSpectrum(ctx context.Context) error

EnableSpectrum sends a spectrum_enable=true command to SDRconnect.

func (*Streamer) LatestAudio

func (s *Streamer) LatestAudio() []byte

LatestAudio returns a copy of the most recently received PCM audio payload, or nil if no frame has been received yet.

func (*Streamer) LatestIQ

func (s *Streamer) LatestIQ() []byte

LatestIQ returns a copy of the most recently received IQ payload, or nil if no frame has been received yet. The payload is signed 16-bit little-endian interleaved I/Q pairs (I Q I Q …).

func (*Streamer) LatestSpectrum

func (s *Streamer) LatestSpectrum() []byte

LatestSpectrum returns a copy of the most recently received spectrum FFT payload, or nil if no frame has been received yet.

func (*Streamer) StartRecording

func (s *Streamer) StartRecording(ctx context.Context, rt RecordingType) error

StartRecording sends a start_recording command to SDRconnect.

func (*Streamer) StopRecording

func (s *Streamer) StopRecording(ctx context.Context) error

StopRecording sends a stop_recording command to SDRconnect.

Jump to

Keyboard shortcuts

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