SDR9700 Architecture
September 4, 2026 · View on GitHub
SDR9700 is a Qt 6 desktop application for controlling an Icom IC-9700 over the radio LAN interface.
High-Level Flow
IC-9700 LAN
|
v
src/radio/ IC-9700 UDP, CI-V, audio, and scope protocol handling
|
v
src/backend/ RadioBackend adapts radio events to app-facing signals
|
v
src/models/ RadioModel, VfoModel, and SpectrumScopeModel hold UI state
|
v
src/gui/ MainWindow, dialogs, VFO display, spectrum, and waterfall
Main Components
RadioBackend: owns the radio commander bridge, worker thread, and audio device selection.Commander/RadioCommander: parse IC-9700 CI-V responses and dispatch radio commands.CachingQueue: maintains the thread-safe radio-value cache and dispatches bounded, deduplicated cache-refresh work. It is not the authoritative path for every outbound command.UdpHandler,UdpCivData,UdpAudio,UdpBase: handle IC-9700 LAN UDP control, CI-V data, audio, scope, and network status packets.CivSequenceGate: suppresses duplicate CI-V UDP payload delivery while recording out-of-order arrivals. It does not delay payloads to reorder them.RadioRouter: converts parsed cache batches into receiver-specific model and UI signals while preserving MAIN/SUB routing.RadioState: holds the latest radio-derived shared and receiver-specific values and invalidates them at session and receiver-context boundaries.ScopeController: coalesces complete scope frames before forwarding them to the GUI thread.RadioSessionWatchdog: evaluates CI-V command/reply liveness independently from continuous UDP audio traffic.AudioConverter: performs bounded sample-format and sample-rate conversion for the Qt audio handlers.Ax25Decoder: decodes AX.25 frames for the data-inspection UI.ScopeAdapter: converts raw IC-9700 scope bytes to clamped native display levels in the range 0–160.RadioModel: app-level connection and radio state.VfoModel: active VFO state exposed to the UI.MeterController: tracks validity and values for receive, transmit, radio, and local microphone meters.SpectrumScopeModel: spectrum range and waterfall/scope data exposed to the UI.SpectrumScopeDisplay,SpectrumScopeCanvas, andWaterfallCanvas: display IC-9700 scope and waterfall data.SpectrumScopeControllerandWaterfallController: coordinate scope input, rendering state, and operator interaction.MainTitleBar: custom frameless window title bar housing the menu bar, volume/mute/lock controls, and window management buttons.DtmfDialog: floating DTMF send panel with PTT gating.MemoryController,MemorySyncController, andMemoryEditorController: synchronize, display, and edit the IC-9700's radio-backed memories.MemoryStore: validates and serializes memory records for CSV import/export.ApplicationLogandLoggingConfiguration: retain filtered in-application diagnostics and configure the independent console, file, and window logging destinations.AutomationServer,AutomationController, andAutomationUiDriver: expose the explicitly enabled local automation socket, enforce its non-transmitting command policy, and exercise visible controls through the GUI thread.IcomRC28Manager(optional, HAVE_HIDAPI): HID driver for the Icom RC-28 rotary controller; emits tuning step and button events, and accepts LED state.AppSettings: JSON-backed client settings at~/.config/SDR9700/sdr9700.jsonon Linux and~/Library/Preferences/SDR9700/sdr9700.jsonon macOS.
Threading
- GUI and models live on the main thread.
- The radio commander runs on a worker thread owned by
RadioBackend. CachingQueueowns a dedicatedstd::threadfor cache batching and queued refresh work.RadioRouterandScopeControllerlive on the radio-data thread so complete scope frames can be coalesced before crossing to the GUI.- Network control, CI-V, and LAN-audio stream objects live on the UDP-handler thread. Qt audio input/output and conversion use their own worker threads.
- Cross-thread communication should use queued Qt signals or
QMetaObject::invokeMethodwithQt::QueuedConnection. - Audio callbacks must not block on locks or perform expensive work.
Radio Definitions
The IC-9700 capability definition is a compiled C++ capability table used by
the radio commander. Startup does not depend on a runtime radios/ directory
or external radio definition files.
SDR9700 client settings use AppSettings; do not add app-owned QSettings
persistence.
Spectrum Data
IC-9700 scope data is converted to display bins by ScopeAdapter::toLevels
before it is emitted to the models/UI. The adapter preserves native values in
the range 0–160 and clamps larger bytes to 160:
levels[i] = std::min(byte, 160);
The scope and waterfall renderers interpret those values against their own display geometry; they are not calibrated dBm measurements.
Current Constraints
- The application controls one IC-9700 session while maintaining distinct MAIN and SUB receiver state. Receiver-less CI-V replies require serialized receiver-context operations because the radio does not identify MAIN/SUB in those payloads.
- Imported design documents may describe features that do not exist in SDR9700. They are not architecture until they are validated and promoted.
resources/manuals/is research material only.