Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
0.7.0 — 2026-02-26¶
Added¶
- Internal PCM<->Opus transcoder foundation (
icom_lan._audio_transcoder) for upcoming high-level PCM audio APIs. - Typed audio exceptions for actionable codec/format failures:
AudioCodecBackendError,AudioFormatError,AudioTranscodeError. - High-level async PCM audio APIs on
IcomRadio: - RX:
start_audio_rx_pcm()/stop_audio_rx_pcm() - TX:
start_audio_tx_pcm()/push_audio_tx_pcm()/stop_audio_tx_pcm()RX callbacks receive decoded PCM frame bytes (orNonegap placeholders). - Audio capability introspection API:
IcomRadio.audio_capabilities()(async and sync wrappers)get_audio_capabilities()andAudioCapabilitiesexport- CLI command:
icom-lan audio capswith optional--jsonoutput. - Runtime audio stats API:
AudioStream.get_audio_stats()andIcomRadio.get_audio_stats()- JSON-friendly metrics for packet loss, jitter, underrun/overrun, and latency.
- CLI
--statssupport for audio capabilities output: icom-lan audio caps --stats(and--json --stats) performs a short RX probe and includes runtime audio stats.- CLI audio subcommands:
icom-lan audio rx --out rx.wav --seconds 10icom-lan audio tx --in tx.wavicom-lan audio loopback --seconds 10with shared--sample-rate,--channels,--json, and--statsflags.- Rigctld WSJT-X compatibility option:
icom-lan serve --wsjtx-compat(optional DATA pre-warm on first client when base mode is USB/LSB/RTTY). - Golden protocol response test suite (
tests/golden/protocol_golden.json): 45 parametrized fixtures covering every rigctld command, both normal and extended wire format, plus all error paths (EINVAL, ENIMPL, EACCESS, EIO, ETIMEOUT). - TCP server wire integration tests (
tests/test_server_wire.py): asyncio-based end-to-end tests exercising realRigctldServerover TCP sockets — get/set roundtrips, multi-command sequences, quit, read-only rejection, CRLF tolerance, level queries, and power conversions.
Changed¶
- Audio low-level API names are now explicit with
_opussuffix:start_audio_rx_opus(),stop_audio_rx_opus(),start_audio_tx_opus(),push_audio_tx_opus(),stop_audio_tx_opus(), plus full-duplexstart_audio_opus()/stop_audio_opus(). - Added parameter validation for high-level PCM TX startup and clearer runtime errors when PCM TX is pushed before startup.
- Added parameter validation for high-level PCM RX startup
(
sample_rate,channels,frame_ms,jitter_depth, callback). - Audio defaults now come from deterministic capability rules: codec preference order, highest sample rate, and channels implied by codec.
- Rigctld mode mapping now includes
PKTRTTYand packet-mode semantics no longer force DATA-off for unrelated mode changes. - Rigctld server/poller reliability improvements for CAT clients: lazy poller lifecycle, packet transition hold window, and cancellation-aware command queue behavior.
Fixed¶
- Reduced first-TX latency spikes in WSJT-X-like CAT/PTT workflows when transitioning from plain USB/LSB into packet DATA mode.
- Prevented abandoned timed-out/cancelled rigctld requests from continuing to execute in the background command queue.
Deprecated¶
- Ambiguous audio aliases are deprecated (still functional during a two-minor-release window):
start_audio_rx(),stop_audio_rx(),start_audio_tx(),push_audio_tx(),stop_audio_tx(),start_audio(),stop_audio(). - Synchronous wrapper aliases are likewise deprecated in favor of
icom_lan.sync.IcomRadio.*_opus()names.
0.6.0 — 2026-02-25¶
Added¶
- Scope/waterfall API — real-time spectrum data from the radio:
ScopeFramedataclass with receiver, mode, frequency range, pixel amplitudesScopeAssembler— reassembles multi-sequence CI-V0x27 0x00bursts into complete framesIcomRadio.on_scope_data(callback)— register callback for assembled scope framesIcomRadio.enable_scope()/disable_scope()— control scope display and data output- Scope command builders:
scope_on,scope_off,scope_data_output,scope_main_sub,scope_single_dual,scope_set_mode,scope_set_span,scope_set_edge,scope_set_hold,scope_set_ref,scope_set_speed,scope_set_vbw,scope_set_rbw - IC-7610: up to 689 pixels, 15 sequences/frame, dual receiver support
- Scope rendering (
pip install icom-lan[scope]):render_spectrum()— spectrum plot (amplitude vs frequency) with grid and labelsrender_waterfall()— heatmap waterfall display, newest frame at toprender_scope_image()— combined spectrum + waterfall PNG- Color themes:
classic(WSJT-X style) andgrayscale, extensible via THEMES dict capture_scope_frame()/capture_scope_frames()— convenience capture methods
- CLI
icom-lan scope:--output,--frames,--theme,--spectrum-only,--width,--json,--capture-timeout
- Mock radio server (
tests/mock_server.py) — full UDP emulator for integration testing:- Two-port protocol (control + CI-V), complete handshake lifecycle
- CI-V command responses: frequency, mode, power, meters, ATT, PREAMP, DIGI-SEL
MockIcomRadiowith configurable state and error injection (auth_fail,response_delay)- 30 new integration tests (
tests/test_mock_integration.py)
Changed¶
ScopeFrame.pixelsusesbytes(notlist[int]) for memory efficiencyenable_scope()/disable_scope()now verify ACK and raiseCommandErroron NAK- Scope callback persists through disconnect (user manages lifecycle)
0.5.1 — 2026-02-25¶
Fixed¶
_ensure_audio_transport()now raisesConnectionError("Audio port not available")when audio port is unresolved (0) instead of silently guessing a default port and hanging on network timeout.- Fix
rufflint warnings: remove unused imports, add new symbols to__all__.
0.5.0 — 2026-02-25¶
Added¶
- Command29 support for dual-receiver radios (IC-7610):
build_cmd29_frame()— builds CI-V frames with0x29 <receiver>prefix.RECEIVER_MAIN(0x00) /RECEIVER_SUB(0x01) constants.parse_civ_frame()now transparently unwraps Command29 responses.
- Attenuator CLI (
icom-lan att [VALUE]):- Get current attenuation level (
icom-lan att) - Set level in dB:
icom-lan att 18(0–45 in 3 dB steps) - Toggle:
icom-lan att on,icom-lan att off - JSON output:
icom-lan att --json
- Get current attenuation level (
- Preamp CLI (
icom-lan preamp [VALUE]):- Get current preamp level (
icom-lan preamp) - Set level:
icom-lan preamp 0(off),1(PRE1),2(PRE2) - JSON output:
icom-lan preamp --json
- Get current preamp level (
get_attenuator()command builder (was missing — only set existed).
Changed¶
- ATT/PREAMP/DIGI-SEL commands now use Command29 framing by default:
get_preamp(),set_preamp(),get_attenuator(),set_attenuator_level(),set_attenuator(),get_digisel(),set_digisel()all acceptreceiver=parameter.- Fixes "Radio rejected preamp level 1" on IC-7610 (the radio requires Command29 receiver context for these commands).
- Radio API methods (
IcomRadio.get_preamp(),.set_preamp(),.get_attenuator_level(),.set_attenuator_level(),.set_attenuator()) now acceptreceiver=parameter.
0.4.0 — 2026-02-25¶
Changed¶
- Faster non-audio connect path:
- CI-V port resolution no longer waits for audio-port negotiation.
- Audio port initialization is lazy (resolved on first audio use).
- CLI/API non-audio operations (e.g.,
status) are significantly faster.
Added¶
- Additional integration stress coverage for concurrent commander operations.
0.3.2 — 2026-02-25¶
Added¶
- Commander layer (
icom_lan.commander):- priority CI-V queue (
IMMEDIATE/NORMAL/BACKGROUND) - command pacing (
ICOM_CIV_MIN_INTERVAL_MS) - dedupe keys for background polling
- transaction helper (
snapshot -> body -> restore)
- priority CI-V queue (
- New radio APIs:
get_mode_info(),get_filter(),set_filter()get_attenuator(),get_preamp()snapshot_state(),restore_state(),run_state_transaction()
- Integration coverage expansion:
- CW stop interrupt test
- VFO exchange/equalize integration scenarios
- full-duplex audio orchestration test
- TX audio payload test
- guarded power off/on cycle test (
ICOM_ALLOW_POWER_CONTROL=1) - reconnect + audio recovery test
- soak test with JSON timeout/recovery logging (
ICOM_SOAK_SECONDS)
Improved¶
- CI-V reliability on real hardware via serialized command execution and pacing.
- Audio stream bring-up reliability (including audio OpenClose behavior).
- Integration guardrails to restore safe baseline state after risky tests.
0.3.0 — 2026-02-25¶
Added¶
- Audio streaming (Phase 3):
AudioCodecenum: uLaw, PCM 8/16-bit, Opus 1ch/2chJitterBuffer: reorder out-of-order packets, gap detection, overflow protection- Full-duplex audio: simultaneous RX + TX
start_audio()/stop_audio()convenience API- Configurable
audio_codecandaudio_sample_rateonIcomRadio
- Synchronous API (
icom_lan.sync):- Blocking
IcomRadiowrapper with context manager - Full API parity with async version
- Blocking
- Radio model presets (
icom_lan.radios):- IC-7610 (0x98), IC-7300 (0x94), IC-705 (0xA4), IC-9700 (0xA2), IC-R8600 (0x96), IC-7851 (0x8E)
get_civ_addr()helper function
- Token renewal: background task every 60s (matches wfview protocol)
- Auto-reconnect: watchdog + exponential backoff reconnect (opt-in)
auto_reconnect,reconnect_delay,reconnect_max_delay,watchdog_timeoutparams
Improved¶
- Test suite: 180 → 401 tests, coverage 63% → 88%
- Code quality: all ruff errors fixed, ack/nak checks added
- ACK/NAK verification for attenuator and preamp commands
Security¶
- Removed private IP addresses from all source and git history
- Internal development docs excluded from public repository
0.2.0 — 2026-02-25¶
Added¶
- CLI tool (
icom-lan) with commands:status,freq,mode,power,meter,ptt,cw,power-on,power-off,discover - VFO control:
select_vfo(),vfo_equalize(),vfo_exchange(),set_split_mode() - RF controls:
set_attenuator(),set_preamp() - CW keying:
send_cw_text(),stop_cw_text()— with auto-chunking - Power control:
power_control()for remote power on/off - Network discovery: broadcast-based autodiscovery of Icom radios
__main__.pyforpython -m icom_lanexecution- JSON output option (
--json) for CLI commands - Frequency parsing with k/m suffix (
14.074m,7074k)
Changed¶
- Bumped version to 0.2.0
0.1.0 — 2026-02-24¶
Added¶
- Transport layer: async UDP connection with discovery handshake
- Dual-port architecture: control port (50001) + CI-V port (50002)
- Full authentication: login → token ack → conninfo exchange → status
- CI-V commands:
get/set_frequency(),get/set_mode(),get/set_power() - Meters:
get_s_meter(),get_swr(),get_alc() - PTT:
set_ptt(on/off) - Keep-alive: automatic ping loop (500ms) and retransmit handling
- Sequence tracking: gap detection and retransmit requests
- Context manager:
async with IcomRadio(...) as radio: - Custom exceptions:
ConnectionError,AuthenticationError,CommandError,TimeoutError - Type annotations: full
py.typedmarker - 151 unit tests with mocked transport (no hardware required)
- Integration tests for IC-7610
Technical¶
- Clean-room implementation of the Icom LAN UDP protocol
- Protocol knowledge from wfview reverse engineering (GPLv3 reference only)
- BCD frequency encoding/decoding
- Icom credential substitution-table obfuscation
- Waterfall/echo filtering in CI-V response handling
- GUID echo in conninfo exchange (required for CI-V port discovery)