Skip to content

Xiegu X6200 — CAT (CI-V) reference vs implementation

Manual: Radioddity "XIEGU X6200 CI-V implementation V1.0.6" (Firmware V1.0.6, dated 2025-06-20, 13 pp.) — official, tabular, CONFIRMED for its documented subset. Cross-referenced against Hamlib rigs/icom/xiegu.c (x6100_priv_caps, reused by X6200; RIG_MODEL_X6200 = 3091). Sources + verbatim extract: manuals/x6200.txt (+ committed manuals/x6200_civ_v1.0.6.pdf). Confidence: high for documented opcodes; Hamlib X108G_LEVELS/FUNCS over-advertise — the Radioddity table wins. Driver: no x6200/ dir — X6200 routes through Ic705SerialRadio (src/rigplane/backends/ic705/serial.py) → _IcomSerialRadioBaseCoreRadio (src/rigplane/runtime/radio.py, all get_/set_ live here). Factory: backends/factory.py:85 maps model in ("IC-705","X6200") to Ic705SerialRadio; personality comes from rigs/x6200.toml (model="X6200"), not a distinct class. Profile: rigs/x6200.toml (CI-V addr 0xA4, 19200 bps SERIAL-B). Validation: src/rigplane/validation/registry/*. Live run: not run — live serial access unavailable to this audit. All statuses are doc-vs-code; every "live" column is not run.

Protocol: CI-V-derived (FE FE A4 00 .. FD), narrower than Icom. Disambiguated from IC-705 (same 0xA4) by Xiegu-only 0x1D 0x19 model-ID → 6200. CH342 dual-UART. 0x18 power on/off intentionally absent (the documented wedge trigger — MOR-170).

Routing fact that drives the gaps below: CoreRadio setters/getters build CI-V frames from hardcoded opcodes in commands/* builders, not from the profile [commands] map (the cmd_map= path is never passed for these). The profile gate is _require_capability(<feature>). So a declared [capabilities] feature activates a method whose opcode is fixed in code — which may not match a Xiegu-documented opcode. The [commands] opcode table in x6200.toml is largely descriptive, not wired for the legacy freq/mode/func paths.


Command matrix (operator-facing)

Legend — Documented: ✅ in Radioddity V1.0.6 table · ⚠️ narrative-only / uncertain · ❌ absent. Validation: RMVR = round-trip readback check · presence = <cap>.presence only · — = no check / cap absent · structural = capability="".

CAT (X6200 opcode) Documented Backend method (CoreRadio) Profile cap / cmd Validation check_id · live
0x25 0x00/0x01 selected/unselected freq get_selected_freq/set_selected_freq/_unselected_ (dual-RX mixin) get/set_selected_freq, get/set_unselected_freq freq.write,freq.reverse_sync (structural) · not run
0x03/0x05 freq (legacy) ⚠️ narrative only get_freq/set_freqmain RX path uses hardcoded 0x03/0x05 get_freq=[0x03],set_freq=[0x05] (declared, not wired) via freq.* structural · not run
0x26 0x00/0x01 selected/unselected mode get_selected_mode/set_selected_mode/_unselected_ get/set_selected_mode,get/set_unselected_mode mode.set (structural) · not run
0x04/0x06 mode (legacy) ❌ (not in table) get_mode/set_modemain path hardcoded 0x04/0x06 get_mode=[0x04],set_mode=[0x06] (declared, not wired) mode.set · not run
0x02 RX freq range get_band_edge_freq get_band_edge_freq=[0x02]
0x07 0x00/0x01 VFO A/B select; 0x07 0xB0 swap get/set_vfo_slot (DualRxRuntimeMixin), swap_vfo_ab get/set_vfo=[0x07]; [vfo] scheme="ab" vfo_slot.set (structural RMVR) · not run
0x0F 0x00/0x01 split ✅ (set only) set_split/get_split (hardcoded 0x0F) split; set_split=[0x0F] split.set RMVR · not run
0x11 attenuator on/off get/set_attenuator attenuator; get/set_attenuator=[0x11] attenuator.set RMVR · not run
0x16 0x02 preamp get/set_preamp preamp; get/set_preamp=[0x16,0x02] preamp.set RMVR · not run
0x16 0x12 AGC get/set_agc agc; get/set_agc=[0x16,0x12] agc.set RMVR · not run
0x16 0x22 noise blanker get/set_nb nb; get/set_nb=[0x16,0x22] nb.set RMVR · not run
0x16 0x40 NR on/off get/set_nr (hardcoded 0x16 0x40) nr nr.set RMVR · not run
0x16 0x44 COMP on/off get/set_compressor (hardcoded 0x16 0x44) compressor presence-only · not run
0x16 0x50 key/dial lock get/set_dial_lock dial_lock; get/set_dial_lock=[0x16,0x50] dial_lock.set RMVR · not run
0x14 0x01 AF get/set_af_level af_level; [0x14,0x01] af_level.set RMVR · not run
0x14 0x02 RF gain get/set_rf_gain rf_gain; [0x14,0x02] rf_gain.set RMVR · not run
0x14 0x03 squelch get/set_squelch squelch; [0x14,0x03] squelch.set RMVR · not run
0x14 0x06 NR level get/set_nr_level nr; [0x14,0x06] — (cap nr covered by nr.set on/off only)
0x14 0x09 CW pitch get/set_cw_pitch cw; [0x14,0x09]
0x14 0x0A TX power get/set_rf_power tx; [0x14,0x0A] — (no rf_power RMVR check)
0x14 0x0B mic gain get/set_mic_gain [0x14,0x0B]
0x14 0x0C keyer speed get/set_key_speed cw; [0x14,0x0C] key_speed.set RMVR · not run
0x14 0x0D DNF/notch FC get/set_notch_filter (hardcoded 0x14 0x0D) notch (no cmd string) (see notch row below)
0x14 0x0F QSK hang get/set_break_in_delay (Icom uses 0x14 0x10?) break_in (no cmd string)
0x14 0x12 NB level get/set_nb_level nb; [0x14,0x12]
0x14 0x15 MONI level get/set_monitor_gain [0x14,0x15]
0x15 0x02/0x11/0x12/0x15 S/pwr/SWR/Vd meters get_s_meter/get_power_meter/get_swr/get_vd_meter meters; [0x15,..] meters.read RO · not run
0x1A 0x01 band/spectrum + band-stacking set get_band_spectrum_display / set_bsr get_band_spectrum_display=[0x1A,0x01] bsr.select (cap bsr not declared → resolves UNSUPPORTED) · not run
0x1A 0x03 IF filter width (read) get_filter_width (set_filter_width exists) get_filter_width=[0x1A,0x03]; cap filter_width not declared — (filter_width.set skipped: cap absent)
0x1A 0x05 (00 62) LCD/key LOCK (no dedicated method; overlaps dial_lock 0x16 0x50)
0x1C 0x00 PTT set_ptt/get_transceiver_status tx; ptt_on/off=[0x1C,0x00] tx.ptt (MANUAL) · not run
0x1C 0x01 ATU (off/on/auto-tune) get/set_tuner_status tuner; get/set_tuner_status=[0x1C,0x01] tuner.tune (MANUAL) · not run
0x19 0x00 radio ID get_transceiver_id get_transceiver_id=[0x19,0x00] discovery.identify (structural) · not run
0x1D 0x19 Xiegu model ID → 6200 (discovery probe probe_xiegu_model_id) get_xiegu_model_id=[0x1D,0x19] discovery-only · not run
DNF on/off 0x16 0x41 no methodnotch cap routes to set_manual_notch (0x16 0x48, NOT X6200) notch declared notch.set RMVR → wrong opcode (D)
break-in (QSK) on/off ✅ only as 0x14 0x0F hang time get/set_break_in → hardcoded 0x16 0x47 (NOT X6200) break_in declared presence-only · not run (D)
VOX ❌ no CI-V get/set_vox → hardcoded 0x16 0x46 (NOT X6200) vox declared vox.read/vox.set(TX-blocked) · not run (D)
repeater tone / TSQL / tone freq ❌ no 0x1B/0x16 0x42-43 get/set_repeater_tone/_tsql/_tone_freq0x16 0x42/43, 0x1B 0x00 (NOT X6200) repeater_tone,tsql declared repeater_tone.set,tone_freq.set,tsql.set,tsql_freq.set RMVR → all wrong opcode (D)
RIT / XIT 0x21 ❌ no CI-V get/set_rit_frequency/_tx_status → hardcoded 0x21 rit,xit; [validation] write_only_controls=["rit","xit","notch"] rit.set,xit.set RMVR (write-only) · not run (D)
scope 0x27 ❌ no CI-V scope mixin (gated) cap scope not declared (intentional) scope.* resolve UNSUPPORTED · correct
pbt (PBT 0x14 0x08/0x09) ❌ no CI-V get/set_pbt_inner/outer (hardcoded 0x14 0x08/09) pbt declared; [controls.pbt_inner/outer] no registry check → presence-only (D)
data_mode 0x26 data-flag / 0x1A 0x06 partial (via 0x26 byte) get/set_data_mode (hardcoded 0x1A 0x06) data_mode declared no registry check → presence-only
scan ❌ no CI-V none scan declared no registry check → presence-only

Intentionally skipped (memory / scan / menu / display — nothing to mirror into the browser UI)

  • Band-stacking register set (0x1A 0x01 D0+D1) — band-recall UI, not a control round-trip (registry bsr exists but cap undeclared).
  • LCD backlight (0x14 0x19) and 0x1A 0x05 LOCK — front-panel display state.
  • No memory family, no scan-table CI-V documented for X6200 — nothing to audit.

Gap lists (priority-ordered)

A. UNDER-DECLARED — backend implements + opcode is X6200-documented, but profile/registry can't see it

CAT (X6200) rigplane symbol Fix Ticket
0x1A 0x03 filter width get/set_filter_width exist + get_filter_width=[0x1A,0x03] in toml, but filter_width is not a declared capability → filter_width.set check skipped entirely Declare filter_width cap once the segmented BCD index tables (Table 2-4) are confirmed on hardware; the profile comment already flags this as deferred pending HW. Until then: keep as-is. NEW (low)
0x14 0x0A TX power · 0x14 0x0B mic gain · 0x14 0x09 CW pitch · 0x14 0x15 MONI methods exist, opcodes documented & in toml, but no RMVR registry check for rf_power/mic_gain/cw_pitch/monitor Optional: add level RMVR checks (these are clean read/set BCD-255 pairs). Low — operator-visible but already wired. NEW (low)
0x16 0x40 NR on/off · 0x16 0x44 COMP on/off set_nr/set_compressor use exactly the documented opcodes; compressor is presence-only and nr.set covers NR Add compressor.set RMVR (get/set_compressor, opcode is correct for X6200). NEW (med)

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

CAT (X6200) rigplane symbol Why presence-only Ticket
0x16 0x44 COMP get/set_compressor compressor cap has no registry check → compressor.presence NEW (med) — opcode is X6200-correct, safe to RMVR
0x14 0x08/0x09 PBT get/set_pbt_inner/_outer pbt cap has no registry check; opcodes are generic-Icom and not in the X6200 table → presence masks a likely-unsupported control NEW (med) — verify PBT on HW before promoting; may belong in C/D
0x1A 0x06 data mode get/set_data_mode data_mode cap has no registry check → presence NEW (low)
(n/a) scan scan cap declared, no method, no CI-V NEW (low) — drop cap or implement

C. MISSING BACKEND — X6200-documented operator command, no (correct) backend method

CAT (X6200) Function Value Ticket
0x16 0x41 DNF on/off Digital notch toggle — the X6200's real notch. No method binds it; notch cap mis-binds to 0x16 0x48 (manual notch, Icom-only). Med — primary noise-reduction control NEW (med) → see D
0x14 0x0D DNF centre freq Notch FC 100-3000 Hz. get/set_notch_filter exists at 0x14 0x0D (correct!) but is not surfaced via the notch cap path. Low NEW (low)
0x1A 0x05 (00 62) key/LCD LOCK Distinct from 0x16 0x50 dial lock; documented separately. Low — overlaps dial_lock NEW (low)
0x1C 0x01 0x02 ATU auto-tune set_tuner_status likely only sends on/off; the 0x02 auto-tune action value may be unreached. Med — verify auto-tune value path NEW (med)

D. MISMATCH / WRONG — declared/checked but the opcode is NOT in the X6200 documented set

These are the high-value finds: a capability is declared, a registry RMVR check is generated (and would run on live HW), but the hardcoded backend opcode is one the X6200 firmware does not document → the check would likely time out / NAK, or worse, silently hit an unrelated register. All need a live capture to confirm true behavior.

CAT path rigplane symbol Issue Ticket
tone/CTCSS family repeater_tone.set,tone_freq.set,tsql.set,tsql_freq.set RMVR checks (caps repeater_tone,tsql declared) Backend sends 0x16 0x42/0x43 + 0x1B 0x00. None are in the X6200 table — no 0x1B, no tone funcs. 4 RMVR checks point at undocumented opcodes. NEW (high) — drop repeater_tone/tsql caps from x6200.toml (or gate behind HW confirm)
manual notch notch.set RMVR (cap notch) Routes to set_manual_notch = 0x16 0x48 (Icom manual notch). X6200's notch is DNF 0x16 0x41 + FC 0x14 0x0D. Check targets the wrong register. NEW (high) — repoint notch to DNF 0x16 0x41; add get/set DNF methods
VOX vox.read/vox.set/vox_gain.set (cap vox) get/set_vox = 0x16 0x46, vox-gain 0x14 0x16neither documented for X6200. NEW (med) — drop vox cap, or confirm on HW
break-in break_in cap (presence-only) get/set_break_in = 0x16 0x47 (Icom CW BK-IN mode). X6200 documents only QSK hang time 0x14 0x0F, not a BK-IN-mode register. NEW (med) — remap to QSK-hang or drop cap
RIT/XIT rit.set,xit.set write-only checks (caps rit,xit) 0x21 RIT/XIT — not in the X6200 table. Already partly hedged via [validation] write_only_controls=["rit","xit","notch"] ("SET accepted but GET times out", MOR-179/207 — those were raw-CIV-confirmed on other Icoms, not X6200). For X6200 the SET itself is undocumented. NEW (med) — confirm 0x21 on X6200 HW; if absent, drop rit/xit caps
legacy mode 0x04/0x06 get_mode/set_mode main path (hardcoded 0x04/0x06) X6200 table documents mode only via 0x26. Main RX mode read/write may not answer on 0x04/0x06. The dual-RX 0x26 path is correct; the legacy main path is the risk. NEW (high) — confirm 0x04 responds on HW; if not, route main mode through 0x26 0x00
legacy freq 0x03/0x05 get_freq/set_freq main path (hardcoded 0x03/0x05) 0x03 appears only in the page-4 narrative example, not Table 1. Likely works (example is explicit) but unconfirmed; 0x25 0x00 is the table-blessed path. NEW (med) — confirm; prefer 0x25 0x00 for main if 0x03 is flaky
pbt get/set_pbt_inner/_outer (0x14 0x08/0x09) Generic-Icom PBT opcodes, absent from X6200 table; cap declared with [controls.pbt_inner/outer] ranges. NEW (med) — confirm PBT on HW; drop cap if unsupported

Correctly handled (no gap)

  • 0x18 power on/off — intentionally omitted from x6200.toml (MOR-170 wedge). power_control cap undeclared → no powerstat path. ✅
  • 0x27 scopescope cap undeclared; all scope.* checks resolve UNSUPPORTED. Matches doc (no scope CI-V). ✅
  • NB 0x16 0x22, NR 0x16 0x40, AGC 0x16 0x12, preamp 0x16 0x02, ATT 0x11, AF/RF/SQL 0x14 0x01/02/03, key-lock 0x16 0x50, meters 0x15, PTT/ATU 0x1C — opcodes match the X6200 table; checks are sound. ✅

Documentation quality note

The Radioddity V1.0.6 PDF is the single authoritative source and is high quality for what it covers: every opcode above marked ✅ is verbatim from Table 1. The audit's confidence is therefore high on presence/absence of opcodes but the following need a live X6200 capture before acting on the D-list:

  1. Legacy 0x03/0x04 (main freq/mode): 0x03 is narrative-only; 0x04 is fully absent. Does the firmware still answer them (Icom-compat), or only 0x25/0x26? This decides whether the legacy main paths are silently broken.
  2. 0x16 0x41 DNF vs 0x16 0x48 manual-notch: confirm the X6200 NAKs 0x48 (so the notch.set check is a real failure, not a coincidental hit).
  3. Tone/CTCSS, VOX, break-in, RIT/XIT (0x1B, 0x16 0x42/43/46/47, 0x21): confirmed doc-absent; a live NAK capture would let us safely drop the four caps (repeater_tone, tsql, vox, plus break_in/rit/xit review) from x6200.toml.
  4. PBT 0x14 0x08/0x09: doc-absent but cap-declared with full control ranges — most likely a copied-from-IC-705 over-declaration.
  5. 0x1A 0x03 filter width + 0x1C 0x01 0x02 ATU auto-tune: documented but un-surfaced / partially wired; capture to confirm the segmented BCD index and the auto-tune action value.

Headline: the X6200 profile is over-declared — it inherited several IC-705-class capabilities (repeater_tone, tsql, vox, break_in, rit, xit, notch→manual, pbt) whose hardcoded backend opcodes are not in the X6200 CI-V table. On live hardware these generate RMVR checks that would target undocumented registers. The fix is profile-side (drop/remap caps) once a single live capture confirms the NAKs — no backend changes are needed for the correctly-wired majority.