Skip to content

IC-7610 (Icom) — CI-V manual vs implementation

Manual: Icom IC-7610 CI-V Reference Guide rev 1a (2021 printing) — full command table (cmds 0027, 1A 05 00xx menu) + command formats. Source: docs/validation/cat-audits/manuals/ic7610.txt (extracted from the official Icom Japan PDF IC-7610_ENG_CI-V_1a.pdf, retrieved via the radiomanual.info mirror — Icom's own download endpoint serves an HTML/JS shell to curl, not the PDF; the mirror's bytes are the official document). Driver: src/rigplane/runtime/radio.py (IcomRadio + mixins) · scope in src/rigplane/runtime/_scope_runtime.py · dual-RX in src/rigplane/runtime/_dual_rx_runtime.py. Backend assembly src/rigplane/backends/icom7610/. Profile: rigs/ic7610.toml. Validation: src/rigplane/validation/registry/*. Live run: /tmp/ic7610.live.json — 70 checks: 59 pass · 3 fail (scope_dual.set, scope_vbw.set, scope_rbw.set) · 8 manual_required. (core 2.9.0, mode=hardware, tx_allowed, LAN 192.168.55.40:50001.)

Protocol: Icom CI-V, FE FE 98 E0 … FD framing (transceiver addr 0x98). @9 in the manual = "Command 29 supported" → dual-RX targeting via the 0x29 <00|01> prefix; the profile's [cmd29] block routes 26 commands this way. Set-then-read round-trips (RMVR) are the harness's strongest signal; many implemented controls only get a *.presence check because no RMVR is registered.


Command matrix (operator-facing set)

CI-V cmd · Documented S(et)/R(ead) · Backend method (or —) · Profile cap/cmd · Validation check_id + live status.

CI-V cmd Doc Backend method Profile Validation (live)
03 read freq / 05 set freq S/R get_freq/set_freq get_freq/set_freq freq.write RMVR ✅ · freq.reverse_sync ✅ · discovery.identify
04 read mode / 06 set mode S/R get_mode/set_mode get_mode/set_mode mode.set RMVR ✅
02 band edge R get_band_edge_freq band_edge cap band_edge.presence
07 B0/B1 swap/equalize S swap_main_sub/equalize_main_sub [vfo] (via vfo_slot.set RMVR ✅)
07 C0/C1/C2 dualwatch S/R get_dual_watch/set_dual_watch dual_watch cap dual_watch.set RMVR ✅
07 D0/D1/D2 main/sub select S/R select_receiver/get_active_receiver [vfo] main/sub vfo_slot.set RMVR ✅
0F split S/R get_split/set_split split cap split.set RMVR ✅
10 tuning step S/R get_tuning_step/set_tuning_step tuning_step cap tuning_step.presence
11 attenuator S/R get_attenuator/set_attenuator attenuator cap attenuator.set RMVR ✅
12 00/01 ANT 1/2 + RX-ANT S/R get/set_antenna_1/2, get/set_rx_antenna_* antenna,rx_antenna antenna.presence ✅ · rx_antenna.presence
13 speech synth R get_speech (front-panel; not checked)
14 01 AF / 14 02 RF gain / 14 03 SQL S/R get/set_af_level, …rf_gain, …squelch yes af_level.setrf_gain.setsquelch.set✅ (RMVR)
14 05 APF pos S/R get/set_apf_type_level apf cap apf.presence
14 06 NR level S/R get/set_nr_level [commands] (none — NR level not round-tripped)
14 07/08 inner/outer PBT S/R get/set_pbt_inner/outer pbt cap pbt.presence
14 09 CW pitch S/R get/set_cw_pitch cw (none — pitch not round-tripped)
14 0A RF power S/R get/set_rf_power [commands] (none)
14 0B MIC gain S/R get/set_mic_gain [commands] (none)
14 0C keying speed S/R get/set_key_speed cw key_speed.set RMVR ✅
14 0D notch filter pos S/R get/set_notch_filter [commands] (none)
14 0E COMP level S/R get/set_compressor_level [commands] (none — see compressor.presence)
14 0F break-in delay S/R get/set_break_in_delay [commands] (none)
14 12 NB level S/R get/set_nb_level [commands] (none)
14 13 DIGI-SEL shift S/R get/set_digisel_shift [commands] (none)
14 14 DRIVE gain S/R get/set_drive_gain drive_gain cap drive_gain.presence
14 15 MONI level S/R get/set_monitor_gain [commands] (none)
14 16 VOX gain S/R get/set_vox_gain [commands] vox_gain.set manual_required (TX-gated)
14 17 Anti-VOX gain S/R get/set_anti_vox_gain [commands] (none)
14 19 LCD backlight S/R (device front panel)
15 01 SQL status R get_s_meter_sql_status meters meters.read ✅ (S-meter)
15 02 S-meter R get_s_meter meters meters.read READ ✅
15 05 various SQL R get_various_squelch meters
15 07 OVF R get_overflow_status meters
15 11/12/13/14/15/16 PO/SWR/ALC/COMP/Vd/Id R get_power_meter/get_swr/get_alc_meter/get_comp_meter/get_vd_meter/get_id_meter meters (streamed; not individually checked)
16 02 preamp S/R get/set_preamp preamp cap preamp.set RMVR ✅
16 12 AGC time const S/R get/set_agc (speed) agc cap agc.set RMVR ✅
16 22 NB S/R get/set_nb nb cap nb.set RMVR ✅
16 32 audio peak filter S/R get/set_audio_peak_filter [commands] (none — polled only)
16 40 NR S/R get/set_nr nr cap nr.set RMVR ✅
16 41 auto notch S/R get/set_auto_notch [commands] (polled; no check)
16 42/43 repeater tone / TSQL S/R get/set_repeater_tone/…tsql [commands] (cap not declared — see Gap D)
16 44 compressor S/R get/set_compressor compressor cap compressor.presence
16 45 monitor S/R get/set_monitor monitor cap monitor.presence
16 46 VOX S/R get/set_vox vox cap vox.read ✅ · vox.set manual_required
16 47 break-in S/R get/set_break_in break_in cap break_in.presence
16 48 manual notch S/R get/set_manual_notch notch cap notch.set RMVR ✅
16 4E DIGI-SEL S/R get/set_digisel digisel cap digisel.presence
16 4F twin peak filter S/R get/set_twin_peak_filter twin_peak cap twin_peak.presence
16 50 dial lock S/R get/set_dial_lock dial_lock cap dial_lock.set RMVR ✅
16 53 ANT-RX I/O S/R get/set_rx_antenna_* rx_antenna rx_antenna.presence
16 56 DSP IF filter type S/R get/set_filter_shape filter_shape cap filter_shape.presence
16 57 manual notch width S/R get/set_manual_notch_width [commands] (none)
16 58 SSB TX bandwidth S/R get/set_ssb_tx_bandwidth ssb_tx_bw cap ssb_tx_bw.presence
16 5E MAIN/SUB tracking S/R get/set_main_sub_tracking main_sub_tracking main_sub_tracking.presence
16 65 IP+ S/R get/set_ip_plus ip_plus cap ip_plus.presence
17 send CW message S send_cw_text/stop_cw_text send_cw (TX-gated; not checked)
18 00/01 power off/on S set_powerstat/get_powerstat power_on/off power_control.presence
19 transceiver ID R get_transceiver_id [commands] (used at discovery)
1A 00 memory contents S/R get/set_memory_contents (memory family — see Gap C note)
1A 01 band stacking reg S/R get/set_bsr bsr cap bsr.select manual_required (set-only)
1A 03 IF filter width S/R get/set_filter_width filter_width cap filter_width.set RMVR ✅
1A 04 AGC time const S/R get/set_agc_time_constant [commands] (none)
1A 05 0070 REF adjust S/R get/set_ref_adjust [commands] (none)
1A 05 0089/0090 USB/LAN MOD lvl S/R get/set_usb_mod_level/…lan_mod_level [commands] (none — audio-path; see memory note)
1A 05 0091-0094 DATA OFF/1/2/3 MOD S/R get/set_data_off_mod_inputdata3 [commands] (none; live-critical, see MEMORY.md)
1A 05 0112 CI-V Transceive S/R get/set_civ_transceive [commands] (config; not checked)
1A 05 0114 CI-V Output (ANT) S/R get/set_civ_output_ant [commands] (config)
1A 05 0158/0159/0162 date/time/UTC S/R get/set_system_date/…time/…utc_offset system_settings system_date.readsystem_time.read✅ (READ-only)
1A 05 0290/0291 NB depth/width S/R get/set_nb_depth/…nb_width [commands] (none)
1A 05 0292 VOX delay S/R get/set_vox_delay [commands] (none)
1A 05 0228 dot/dash ratio S/R get/set_dash_ratio [commands] (none)
1A 06 DATA mode w/ filter S/R get/set_data_mode data_mode cap data_mode.presence
1A 09 AF mute S/R get/set_af_mute [commands] (none)
1B 00/01 repeater/TSQL tone freq S/R get/set_tone_freq/…tsql_freq [commands] (cap not declared — Gap D)
1C 00 PTT (RX/TX) S/R set_ptt ptt_on/off tx.ptt manual_required (TX-gated)
1C 01 antenna tuner S/R get/set_tuner_status tuner cap tuner.tune manual_required (TX-gated)
1C 02 XFC (TX freq monitor) S/R get/set_xfc_status xfc cap xfc.presence
1C 03 read TX freq R get_tx_freq_monitor [commands] (none)
0E scan start/stop/resume S scan_start/scan_stop/scan_set_* scan cap scan.presence
21 00/01/02 RIT freq/on/ΔTX S/R get/set_rit_frequency/…rit_status/…rit_tx_status rit,xit rit.set RMVR ✅ · xit.set RMVR ✅
25 main/sub band freq S/R (via _dual_rx_runtime) get_selected_freq/unselected [commands] (covered by vfo_slot.set)
26 operating mode+filter (both) S/R (via dual_rx) get_selected_mode/unselected [commands]
27 10 scope ON/OFF S/R enable_scope/disable_scope scope cap scope.capture manual_required
27 11 scope data output S/R scope_stream [commands] (streamed)
27 12 main/sub scope S/R get/set_scope_receiver scope scope_receiver.set RMVR ✅
27 13 single/dual scope S/R get/set_scope_dual scope scope_dual.set RMVR ❌ FAIL
27 14 scope mode S/R get/set_scope_mode scope scope_mode.set RMVR ✅
27 15 span S/R get/set_scope_span scope scope_span.set RMVR ✅
27 16 edge number S/R get/set_scope_edge scope scope_edge.set RMVR ✅
27 17 scope hold S/R get/set_scope_hold scope scope_hold.set RMVR ✅
27 19 reference level S/R get/set_scope_ref scope [scope] scope_ref.set RMVR ✅
27 1A sweep speed S/R get/set_scope_speed scope scope_speed.set RMVR ✅
27 1B scope during TX S/R get/set_scope_during_tx scope scope_during_tx.set RMVR ✅
27 1C center type S/R get/set_scope_center_type scope scope_center_type.set RMVR ✅
27 1D VBW S/R get/set_scope_vbw scope scope_vbw.set RMVR ❌ FAIL
27 1E fixed edge freqs S/R get/set_scope_fixed_edge scope scope_fixed_edge.read READ ✅
27 1F RBW S/R get/set_scope_rbw scope scope_rbw.set RMVR ❌ FAIL
27 20 marker position S/R (NEW — see Gap C)

Intentionally OUT OF SCOPE (device front panel / non-operator — nothing to mirror into a browser UI)

  • 13 speech synthesizer (voice readout — front panel), 14 19 LCD backlight, 1A 02 memory keyer contents (CW message store — feature, not a live control).
  • 1A 05 menu tail (00220309, hundreds of params): beep/tone-control EQ, RTTY/PSK decode, recorder, keyboard/mouse, network (DHCP/IP/ports), display (LCD/LED/meter type/screen saver), scope cosmetics (waterfall colour/size/averaging/fixed-edge memory), antenna memory, USB SEND/keying routing. These are Set-mode configuration, not operator controls — out of harness scope by design (same policy as FTX-1's EX menu / Table 3).
  • 1E TX band-edge enumeration (regulatory band table — read-only metadata).
  • Memory channel family (08/09/0A/0B/1A 00) — backend methods exist (get/set_memory_mode, memory_write/to_vfo/clear, get/set_memory_contents) but memory ops are a deferred UI feature, not a CAT round-trip surface.

Gap lists (priority-ordered)

A. UNDER-DECLARED — backend implements, profile/registry can't round-trip it

The IC-7610 driver is very complete (≈150 get_/set_ methods). The recurring gap: a method exists and the profile declares either a [capabilities] feature or a [commands] string, but no RMVR check is registered — so the control is invisible to validation beyond, at best, a *.presence ping. Highest-value missing RMVRs (all backend + profile present, just no registry entry):

Control Backend (verified) Why it matters Ticket
RF power 14 0A get/set_rf_power core TX control, fully readable/writable, zero round-trip NEW
MIC gain 14 0B get/set_mic_gain primary TX-audio control NEW
COMP level 14 0E get/set_compressor_level only compressor.presence exists (on/off), level unchecked NEW
NR level / NB level 14 06/14 12 get/set_nr_level/…nb_level on/off has RMVR; the level (the operator-visible slider) does not NEW
CW pitch 14 09 get/set_cw_pitch RMVR-friendly (300–900 Hz), CW op control NEW
notch filter pos / manual-notch width 14 0D/16 57 get/set_notch_filter, …manual_notch_width notch.set only round-trips the on/off, not position/width NEW
monitor / drive / anti-VOX gain 14 15/14 14/14 17 resp. methods drive_gain only *.presence; monitor/anti-VOX no check NEW
PBT inner/outer 14 07/08 get/set_pbt_inner/outer pbt.presence only; pos is RMVR-able (0–255) NEW
AGC time constant 16 12/1A 04 get/set_agc, get/set_agc_time_constant agc.set round-trips speed; the 1A 04 selected-filter time-constant path is unchecked NEW
AF mute 1A 09 get/set_af_mute clean boolean RMVR, declared in [commands], no check NEW
USB/LAN/DATA MOD inputs 1A 05 0089-0094 get/set_usb_mod_level,…lan_mod_level,…data_off/1/2/3_mod_input live-critical — DATA-OFF MOD=LAN is the documented fix for the "web TX = noise" class of bug (see MEMORY.md); these have methods + [commands] strings but no round-trip guard NEW
tuning step / band edge 10/02 get/set_tuning_step, get_band_edge_freq tuning_step.presence/band_edge.presence only — step is a clean RMVR NEW (low)

Recommended fix (one ticket per cluster): add RMVR_SAFE_WRITE checks to the registry (_levels.py/_dsp.py/_tx.py/_audio.py) gated on the already-declared capabilities; for the MOD-input cluster, a dedicated _audio/_system round-trip since it guards a known field-failure mode.

B. VALIDATION GAPS — implemented + declared, but presence-only (no round-trip)

These have a capability and a registered check, but the check is *.presence (confirms the command answers) rather than set-then-verify. All pass live; upgrading to RMVR would catch silent write-failures.

Capability Backend Live Recommendation Ticket
compressor 16 44 get/set_compressor compressor.presence RMVR (toggle on/off) NEW
break_in 16 47 get/set_break_in break_in.presence RMVR (OFF/SEMI/FULL) NEW
filter_shape 16 56 get/set_filter_shape filter_shape.presence RMVR (SHARP/SOFT) NEW
ssb_tx_bw 16 58 get/set_ssb_tx_bandwidth ssb_tx_bw.presence RMVR (WIDE/MID/NAR) NEW
twin_peak 16 4F get/set_twin_peak_filter twin_peak.presence RMVR (guarded: only valid in RTTY 2125/170) NEW (low)
digisel/ip_plus 16 4E/16 65 resp. *.presence RMVR booleans NEW (low)
apf/pbt/drive_gain resp. *.presence level RMVR (folds into Gap A) NEW
data_mode 1A 06 get/set_data_mode data_mode.presence RMVR NEW (low)
main_sub_tracking 16 5E get/set_main_sub_tracking *.presence RMVR boolean NEW (low)
xfc 1C 02 get/set_xfc_status xfc.presence RMVR boolean NEW (low)
monitor 16 45 get/set_monitor monitor.presence RMVR boolean NEW (low)

C. MISSING BACKEND — documented operator command, no backend method

The driver is near-complete; genuinely-missing operator-facing commands are few. The rest of the manual's unimplemented commands are device-front-panel/config (listed OUT OF SCOPE above).

CI-V cmd Function Value Ticket
27 20 Scope marker position (Filter-center vs Carrier-point) Low — scope cosmetic but a live-changeable scope control, not a Set-mode-only param NEW (low)
13 speech / 1A 02 memory keyer / memory channel family voice readout · CW keyer store · memory ch Feature/front-panel — track as a UI feature, not a CAT gap — (out of scope)

D. MISMATCH / WRONG — declared/checked but behaves differently (the live FAILs)

CI-V cmd check_id Issue Ticket
27 13 single/dual scope_dual.set Set does not round-trip on the IC-7610. Per MOR-664 the dual-scope write needs the dual-RX precondition (the radio rejects/ignores the single→dual flip unless the second receiver is active), so read-back never matches the requested value. MOR-664
27 1D VBW scope_vbw.set Verified asymmetry: get_scope_vbw passes receiver= into _get_scope_vbw_cmd (runtime/_scope_runtime.py:410-421), but set_scope_vbw calls _scope_set_vbw_cmd(narrow, …) with no receiver (:423-429). When the scope source is SUB the set lands on the wrong RX and read-back mismatches. MOR-664
27 1F RBW scope_rbw.set Same receiver-prefix asymmetry: get_scope_rbw takes receiver= (:473-484) while set_scope_rbw (:486-492) omits it. MOR-664
(note) 27 1E fixed edge scope_fixed_edge.read Already mitigated for the read path — get_scope_fixed_edge injects a <range><edge> selector (range 1, edge 1) or the IC-7610 NAKs the read (fixed by MOR-662). Documented here so the pattern (selector/receiver-prefix on 0x27 sub-reads) is visible. — (fixed)
(note) 16 42/43, 1B 00/01 tone Repeater-tone / TSQL / tone-freq have backend methods + [commands] strings but the repeater_tone/tsql capabilities are NOT declared in [capabilities].features (IC-7610 is HF/6m, no FM-repeater CTCSS surfaced) — so no tone check runs. Correct intent, but the dangling [commands] entries are dead weight; either drop them or gate behind an explicit "no FM repeater" note. NEW (doc/cleanup, low)

The 3 red FAILs all trace to MOR-664 (already filed). MOR-659/660/661/662/663/665 were the live-found-and-fixed scope/read issues from the same session and are not re-filed.


Ticket coverage summary

  • 3 live FAILs (scope_dual.set / scope_vbw.set / scope_rbw.set) → MOR-664 (receiver-prefix on 0x27 1D/1F set + dual-RX precondition on 0x27 13). Verified in code (set-path omits the receiver= the get-path uses).
  • Gap A (under-declared, no RMVR): ~12 clusters of fully-implemented controls — headline = RF power / MIC gain / COMP level / NR+NB level / CW pitch / MOD-input routing. All NEW.
  • Gap B (presence-only → RMVR upgrade): ~11 capabilities, headline = compressor / break_in / filter_shape / ssb_tx_bw. All NEW.
  • Gap C (missing backend): only 27 20 marker position is a real (low-value) operator gap. NEW. Everything else is front-panel/feature, out of scope.
  • Gap D (mismatch): the 3 FAILs (MOR-664) + a doc-cleanup note on the dead tone [commands] entries (NEW, low).