Commands Module¶
Low-level CI-V command encoding and decoding. Most users should use the high-level Radio API (via create_radio).
cmd_map is required¶
Every command builder takes cmd_map as a required, keyword-only parameter — there is no
hardcoded fallback path. Checked directly against every non-underscore function defined in
src/rigplane/commands/*.py (excluding _frame.py): 244 distinct builder functions require
cmd_map (256 counting names re-exported twice for backward compatibility, e.g.
antenna.py: get_antenna aliasing get_antenna_1); the remaining 33 exported functions are
parse_* response decoders, which take no cmd_map because they decode a frame the radio
already sent, with nothing left to look up.
Calling a builder without a real map — cmd_map omitted, or passed explicitly as None —
raises TypeError rather than silently building a wrong frame. Both shapes are handled by
commands/_frame.py: require_cmd_map, applied to every migrated builder: a call missing
cmd_map entirely gets Python's own missing-argument TypeError with an explanation appended,
and a call passing cmd_map=None gets a dedicated TypeError before the builder body ever runs.
from rigplane.commands import get_af_level
get_af_level(to_addr=0x98) # TypeError: missing keyword-only argument 'cmd_map'
get_af_level(to_addr=0x98, cmd_map=None) # TypeError: cmd_map is None -- ...
Calling a builder directly¶
from pathlib import Path
from rigplane.rig_loader import load_rig
from rigplane.commands import get_af_level
cfg = load_rig(Path("rigs/ic7300.toml"))
cmd_map = cfg.to_command_map()
frame = get_af_level(to_addr=0x94, cmd_map=cmd_map)
Recommended: BoundCommands¶
commands/bound.py: BoundCommands binds a radio's CommandMap once, at construction, so call
sites never pass cmd_map themselves:
from rigplane.commands.bound import BoundCommands
bound = BoundCommands(cmd_map)
frame = bound.get_af_level(to_addr=0x94)
runtime/radio.py: CoreRadio constructs one BoundCommands per radio and uses it for every
migrated builder.
The undeclared-command policy (three states, not two)¶
A command a profile's CommandMap does not declare is not silently ignored. BoundCommands
classifies every miss into one of three states:
- Declared — the profile has an entry; the builder sends its bytes.
- Declared absent — the profile records the radio as confirmed not to have this command,
naming a source; calling it raises
core.exceptions.CommandErrorquoting that source. - Unknown — neither declared nor recorded absent. This state is not expected to exist in a
released profile (a coverage test enumerates every builder against every profile), but if
reached,
BoundCommandsrefuses the same way as state 2 and, once, invokes the optionalon_undeclaredhook before raising.
Neither state 2 nor state 3 logs and continues: both raise CommandError, so a caller cannot
observe a command that silently did nothing.
See docs/api/rig-loader.md for the CommandMap class reference.
rigplane.commands
¶
CI-V command encoding and decoding for Icom transceivers.
CI-V frame format::
FE FE <to> <from> <cmd> [<sub>] [<data>...] FD
For dual-receiver radios (IC-7610), commands marked Command29=true use::
FE FE <to> <from> 29 <receiver> <cmd> [<sub>] [<data>...] FD
where receiver = 0x00 (MAIN) or 0x01 (SUB).
Reference: wfview icomcommander.cpp, IC-7610.rig
bcd_decode(data)
¶
Decode Icom BCD-encoded frequency bytes to Hz.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
5 bytes of BCD-encoded frequency. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Frequency in Hz. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If data is not exactly 5 bytes or contains invalid BCD. |
Examples:
bcd_encode_value(value, *, byte_count)
¶
Encode an integer as packed BCD using a fixed byte width.
build_civ_frame(to_addr, from_addr, command, sub=None, data=None)
¶
Build a CI-V frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
to_addr
|
int
|
Destination CI-V address. |
required |
from_addr
|
int
|
Source CI-V address. |
required |
command
|
int
|
CI-V command byte. |
required |
sub
|
int | None
|
Optional sub-command byte. |
None
|
data
|
bytes | None
|
Optional payload data. |
None
|
Returns:
| Type | Description |
|---|---|
bytes
|
Complete CI-V frame bytes. |
build_cmd29_frame(to_addr, from_addr, command, sub=None, data=None, receiver=RECEIVER_MAIN)
¶
Build a Command29-wrapped CI-V frame for dual-receiver radios.
For commands marked Command29=true in IC-7610.rig, the frame format is::
FE FE <to> <from> 29 <receiver> <cmd> [<sub>] [<data>...] FD
The 0x29 prefix tells the radio which receiver (MAIN/SUB) the command targets, without requiring a VFO select first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
to_addr
|
int
|
Destination CI-V address. |
required |
from_addr
|
int
|
Source CI-V address. |
required |
command
|
int
|
Original CI-V command byte (e.g. 0x11 for ATT, 0x16 for PREAMP). |
required |
sub
|
int | None
|
Optional sub-command byte. |
None
|
data
|
bytes | None
|
Optional payload data. |
None
|
receiver
|
int
|
RECEIVER_MAIN (0x00) or RECEIVER_SUB (0x01). |
RECEIVER_MAIN
|
Returns:
| Type | Description |
|---|---|
bytes
|
Complete CI-V frame bytes with Command29 prefix. |
build_memory_clear(channel, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to clear memory channel (0x0B).
Note
The 2-byte BCD channel payload appended here is contradicted by all four Icom manuals, which document 0x0B as a bare command with no data field -- see MOR-2055 for the payload question. This migration re-plumbs the command-map lookup only and does not change these wire bytes.
build_memory_contents_get(channel, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to get memory contents (0x1A 0x00).
build_memory_contents_set(mem, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to set memory contents (0x1A 0x00).
build_memory_mode_get(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to get current memory mode (0x08).
build_memory_mode_set(channel, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to set memory mode (0x08).
build_memory_to_vfo(channel, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to load memory to VFO (0x0A).
Note
The 2-byte BCD channel payload appended here is contradicted by all four Icom manuals, which document 0x0A as a bare command with no data field -- see MOR-2055 for the payload question. This migration re-plumbs the command-map lookup only and does not change these wire bytes.
build_memory_write(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to write VFO to memory (0x09).
command_carries_sub(command)
¶
Whether command's wire bytes include a CI-V sub-command byte.
The one place this question is answered: :func:decode_wire_tuple
(splitting a declared [commands] tuple) and :func:parse_civ_frame
(splitting a received frame's payload) both call this, so a tuple
split for a request and a frame split for its reply agree on where
the sub-command byte is.
filter_hz_to_index(hz, *, segments)
¶
Convert a filter width in Hz to a CI-V index using profile segments.
filter_index_to_hz(index, *, segments)
¶
Convert a CI-V filter-width index to Hz using profile segments.
get_af_level(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'read AF output level' CI-V command (0x14 0x01).
get_af_mute(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read AF Mute command.
get_agc(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read AGC mode command.
get_agc_time_constant(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read AGC time constant command.
get_alc(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'read ALC meter' CI-V command.
get_antenna_1(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build ANT1 select/read command (0x12 0x00) WITHOUT data byte.
get_antenna_2(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build ANT2 select/read command (0x12 0x01) WITHOUT data byte.
get_anti_vox_gain(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Anti-Vox Gain command.
get_apf_type_level(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read APF Type Level command.
get_attenuator(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to read attenuator level (Command29-aware).
get_audio_peak_filter(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read audio peak filter mode command.
get_auto_notch(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read auto-notch status command.
get_band_edge_freq(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read band-edge frequency command (0x02).
get_break_in_delay(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Break-In Delay command.
get_bsr(band, register, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to get band stacking register (0x1A 0x01).
get_comp_meter(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read compressor meter command (0x15 0x14).
get_compressor_level(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Compressor Level command.
get_cw_pitch(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read CW Pitch command.
get_dash_ratio(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Dash Ratio command.
get_data_mode(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get DATA mode' CI-V command (0x1A 0x06).
get_digisel(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to read DIGI-SEL status (Command29-aware).
get_digisel_shift(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read DIGI-SEL Shift command.
get_drive_gain(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Drive Gain command.
get_dual_watch(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to query dual watch status.
Unlike the setter, the getter needs no key split: every profile that
declares dual watch reads it back through one unified entry
(IC-7610's [0x07, 0xC2], IC-9700's [0x16, 0x59]), since only
the write side needs a separate address per direction.
get_filter_shape(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read DSP IF filter shape command.
get_filter_width(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, cmd_map)
¶
Build a 'get DSP IF filter width' CI-V command (0x1A 0x03, cmd29).
get_freq(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get frequency' CI-V command.
get_id_meter(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Id (drain current) meter command (0x15 0x16).
get_ip_plus(to_addr, from_addr=CONTROLLER_ADDR, *, command29=True, cmd_map)
¶
Build CI-V command to read IP+ status.
get_key_speed(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Key Speed command.
get_main_sub_band(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get main/sub band' CI-V command (0x07 0xD2).
get_main_sub_tracking(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Main/Sub Tracking status command (0x16 0x5E).
get_manual_notch_width(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'get manual notch width' CI-V command (0x16 0x57).
get_mic_gain(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Mic Gain command.
get_mode(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get mode' CI-V command.
get_monitor_gain(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Monitor Gain command.
get_nb(to_addr, from_addr=CONTROLLER_ADDR, *, command29=True, cmd_map)
¶
Build CI-V command to read NB status.
get_nb_depth(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read NB Depth command.
get_nb_level(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read NB Level command.
get_nb_width(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read NB Width command.
get_notch_filter(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read Notch Filter level command.
get_nr(to_addr, from_addr=CONTROLLER_ADDR, *, command29=True, cmd_map)
¶
Build CI-V command to read NR status.
get_nr_level(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read NR Level command.
get_overflow_status(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read overflow status command.
get_pbt_inner(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read PBT Inner command.
get_pbt_outer(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read PBT Outer command.
get_power_meter(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read RF power meter command (0x15 0x11).
get_powerstat(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to query radio power status (0x18 GET).
get_preamp(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to read preamp status (Command29-aware).
get_quick_dual_watch(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Read the persistent Quick Dual Watch menu toggle.
See get_quick_split -- same ruling, same shape.
get_quick_split(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Read the persistent Quick Split menu toggle (0x1A 0x05
MOR-2007 ruling 2: bench-confirmed on the live IC-7300, this menu item
is readable, writable and persistent (restored across power cycles) --
not the one-shot trigger the pre-migration quick_split() name
implied. That builder always sent this same bare-GET frame (the menu
address alone, no data byte) and its only caller
(runtime/radio.py) never read the reply, so it fired nothing;
deleted along with quick_dual_watch() below.
get_ref_adjust(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read REF Adjust command.
get_repeater_tone(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to get repeater tone status (0x16 0x42).
get_repeater_tsql(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to get repeater TSQL status (0x16 0x43).
get_rf_gain(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'read RF gain' CI-V command (0x14 0x02).
get_rf_power(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get RF power' CI-V command.
get_rit_frequency(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read RIT frequency offset command (0x21 0x00).
get_rx_antenna_ant1(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build read RX ANT state for ANT1 (0x12 0x00). Warning: also selects ANT1.
get_rx_antenna_ant2(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build read RX ANT state for ANT2 (0x12 0x01). Warning: also selects ANT2.
get_s_meter(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'read S-meter' CI-V command.
get_s_meter_sql_status(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read S-meter squelch status command.
get_scope_center_type(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a bare 'get scope center type' CI-V command (0x27 0x1C).
Takes no receiver argument (MOR-1981, MOR-2002 step 2b-vfo-scope):
0x1C is outside SCOPE_RECEIVER_SELECTOR_SUBS, so a receiver byte on
this read is a SET, not a selector -- see _scope_selector_data.
get_scope_data_output_enabled(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Query whether CI-V scope waveform output is currently enabled.
get_scope_enabled(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Query whether the radio's panel scope is currently enabled.
get_selected_freq(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get selected receiver frequency' CI-V command (0x25 0x00).
get_selected_mode(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get selected receiver mode' CI-V command (0x26 0x00).
get_speech(what=0, *, to_addr, from_addr=CONTROLLER_ADDR, cmd_map)
¶
Build a speech announcement CI-V command (0x13).
Fire-and-forget. Triggers the IC-7610 voice synthesizer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
what
|
int
|
0 = all (S-meter, frequency, mode), 1 = frequency + S-meter, 2 = mode. |
0
|
get_split(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to read split state (0x0F).
get_squelch(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'get squelch level' CI-V command (0x14 0x03).
get_ssb_tx_bandwidth(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read SSB TX bandwidth preset command.
get_swr(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'read SWR meter' CI-V command.
get_tone_freq(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map, ctcss_tones_centihz)
¶
Build CI-V command to get tone frequency (0x1B 0x00).
get_transceiver_id(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read transceiver ID command (0x19 0x00).
get_tsql_freq(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map, ctcss_tones_centihz)
¶
Build CI-V command to get TSQL frequency (0x1B 0x01).
get_tuner_status(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read tuner/ATU status command (0x1C 0x01).
get_tuning_step(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to get tuning step (0x10).
get_tx_band_count(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to query number of TX bands (0x1E 0x00).
get_tx_band_edge(band, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to query TX band N edge frequencies (0x1E 0x01).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
band
|
int
|
Band number (0-99, encoded as BCD byte). |
required |
to_addr
|
int
|
Radio CI-V address. |
required |
from_addr
|
int
|
Controller CI-V address. |
CONTROLLER_ADDR
|
cmd_map
|
CommandMap
|
The radio's bound command map. |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Complete CI-V frame bytes. |
get_unselected_freq(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get unselected receiver frequency' CI-V command (0x25 0x01).
get_unselected_mode(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get unselected receiver mode' CI-V command (0x26 0x01).
get_various_squelch(to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a read various-squelch status command (0x15 0x05, Command29).
get_vd_meter(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Vd (supply voltage) meter command (0x15 0x15).
get_vfo(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'get VFO' CI-V command (0x07 read back current VFO).
get_vox_delay(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read VOX Delay command (0x1A 0x05 0x02 0x92).
get_vox_gain(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read Vox Gain command.
get_xfc_status(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a read XFC status command (0x1C 0x02).
hz_to_table_index(hz, *, table)
¶
Convert Hz to the closest table-based filter-width index.
Returns the index whose table entry is closest to hz.
parse_ack_nak(frame)
¶
Check if frame is ACK (0xFB) or NAK (0xFA).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frame
|
CivFrame
|
Parsed CivFrame. |
required |
Returns:
| Type | Description |
|---|---|
bool | None
|
True for ACK, False for NAK, None if neither. |
parse_band_stack_response(frame)
¶
Parse band stacking register response (0x1A 0x01).
parse_bool_response(frame, *, command, sub=None, prefix=b'')
¶
Parse a boolean CI-V response payload.
parse_civ_frame(data)
¶
Parse a CI-V frame into a CivFrame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Raw CI-V frame bytes (including FE FE preamble and FD terminator). |
required |
Returns:
| Type | Description |
|---|---|
CivFrame
|
Parsed CivFrame. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If frame is malformed. |
parse_data_mode_response(frame)
¶
Parse a DATA mode response frame.
Returns:
| Type | Description |
|---|---|
bool
|
True if DATA mode is active (data[0] != 0x00), False otherwise. |
parse_frequency_response(frame)
¶
Parse a frequency response frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frame
|
CivFrame
|
Parsed CivFrame (command 0x02/0x03/0x00 with 5-byte BCD data). |
required |
Returns:
| Type | Description |
|---|---|
int
|
Frequency in Hz. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If frame is not a frequency response. |
parse_level_response(frame, *, command=_CMD_LEVEL, sub=None, prefix=b'', bcd_bytes=2)
¶
Parse a BCD-encoded level/config response.
parse_memory_contents_response(frame)
¶
Parse memory contents response (0x1A 0x00).
parse_memory_mode_response(frame)
¶
Parse memory mode response (0x08).
parse_meter_response(frame)
¶
Parse a meter response frame.
Returns:
| Type | Description |
|---|---|
int
|
Meter value 0-255. |
parse_mode_response(frame)
¶
Parse a mode response frame.
Returns:
| Type | Description |
|---|---|
tuple[Mode, int | None]
|
Tuple of (mode, filter_width or None). |
parse_powerstat(frame)
¶
Parse power status response (0x18 GET).
Returns:
| Type | Description |
|---|---|
bool
|
True if powered on, False if powered off. |
parse_rit_frequency_response(data)
¶
Parse RIT frequency response data (2-byte BCD + sign byte).
parse_scope_data_output_enabled_response(frame, *, command=_CMD_SCOPE, sub=_SUB_SCOPE_DATA_OUTPUT)
¶
Parse a 0x27 0x11 waveform-output state response.
parse_scope_enabled_response(frame, *, command=_CMD_SCOPE, sub=_SUB_SCOPE_ON)
¶
Parse a 0x27 0x10 panel-scope state response.
command/sub are the map-derived shape the caller's request used
(runtime/_scope_runtime.py: ScopeRuntimeMixin.get_scope_session_state
via runtime/radio.py: CoreRadio._expect_shape); they default to the
shared hardcoded constants only so a caller that never passes one --
runtime/_civ_rx.py's unsolicited-frame decoding, and every
pre-migration direct test call -- keeps working unchanged. Every other
parse_scope_*_response function below takes the same two keywords
for the same reason.
parse_scope_ref_response(frame, *, command=_CMD_SCOPE, sub=_SUB_SCOPE_REF)
¶
Decode scope REF level from CI-V response.
Wire format (IC-7610 CI-V Reference p.15): byte 0: high nibble = 10 dB digit, low nibble = 1 dB digit byte 1: high nibble = 0.1 dB digit, low nibble = 0 byte 2: sign (0x00 = +, 0x01 = -)
parse_scope_span_response(frame, presets, *, command=_CMD_SCOPE, sub=_SUB_SCOPE_SPAN)
¶
Decode a 0x27 0x15 span reply into (receiver, span index).
presets is the radio's declared span table -- see
scope_set_span above for why it is a parameter and not a module
constant. Both reply shapes are bounded by it: the one-byte form is
already an index and is range-checked against len(presets), and
the five-byte BCD form is matched exactly against the table by
_span_index_for_hz. No match raises ValueError, unchanged --
a profile that declares no presets therefore decodes no span at all.
parse_selected_freq_response(frame)
¶
Parse a 0x25 selected/unselected frequency response.
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
Tuple of (receiver_byte, frequency_hz). |
parse_selected_mode_response(frame)
¶
Parse a 0x26 selected/unselected mode response.
Returns:
| Type | Description |
|---|---|
tuple[int, Mode, int | None, int | None]
|
Tuple of (receiver_byte, mode, data_mode_or_None, filter_or_None). |
parse_system_date_response(frame, *, prefix=_CTL_MEM_SYSTEM_DATE)
¶
Parse a system-date reply.
prefix is the map-derived extended-address bytes the caller's
request used (runtime/radio.py: CoreRadio._expect_shape); it defaults
to the shared IC-7610-shaped constant only so tests built before this
migration, which never passed one, keep working unchanged.
parse_system_time_response(frame, *, prefix=_CTL_MEM_SYSTEM_TIME)
¶
Parse a system-time reply. See parse_system_date_response for prefix.
parse_tone_freq_response(frame, *, ctcss_tones_centihz)
¶
Parse tone frequency response (0x1B 0x00).
parse_tsql_freq_response(frame, *, ctcss_tones_centihz)
¶
Parse TSQL frequency response (0x1B 0x01).
parse_tx_band_count_response(data)
¶
Parse 0x1E 0x00 response data into band count (BCD decoded).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Response payload (single BCD byte, or empty). |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of TX bands. |
parse_tx_band_edge_response(data)
¶
Parse 0x1E 0x01 response data into (start_hz, end_hz).
Data format: 5-byte BCD start frequency + 5-byte BCD end frequency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
10 bytes of BCD-encoded frequency pair. |
required |
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
Tuple of (start_hz, end_hz). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If data is shorter than 10 bytes. |
parse_utc_offset_response(frame, *, prefix=_CTL_MEM_UTC_OFFSET)
¶
Parse a UTC-offset reply. See parse_system_date_response for prefix.
power_off(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to power off the radio.
power_on(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to power on the radio.
ptt_off(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a PTT-off CI-V command. See ptt_on.
ptt_on(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a PTT-on CI-V command.
The payload byte (0x01) is constant, so under the tuple contract
(Q7, docs/plans/2026-08-29-profile-driven-command-bytes.md §8.1)
every profile's ptt_on tuple already carries it; this builder
passes no data of its own.
scan_set_df_span(df_span, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to set DeltaF scan span (0x0E 0xA1-0xA7).
scan_set_resume(resume_mode, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to set scan resume mode (0x0E sub).
Which sub-bytes are legal is a per-radio domain (MOR-2007 ruling 4):
every documented CI-V guide (IC-7300/IC-7610/IC-9700/IC-705) lists only
0xD0 (resume OFF) and 0xD3 ("Close&Delay") -- not the 0xD1/0xD2
5s/10s states the deleted code-level VALID_SCAN_RESUME frozenset
accepted on every radio regardless. This builder only encodes the byte
the caller supplies; the profile-aware caller
(runtime/radio.py: CoreRadio.scan_set_resume) validates it against
RadioProfile.scan_resume_values first, same shape as
scan_start_type above.
scan_start(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to start scanning (0x0E 0x01).
scan_start_type(scan_type, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to start scan with specific type (0x0E sub).
Which sub-bytes are legal is a per-radio domain (MOR-2007 ruling 4):
the deleted code-level VALID_SCAN_TYPES frozenset omitted 0x13
(fine ΔF scan, documented on IC-7300/IC-7610/IC-9700) and IC-705's
0x24 (mode-select scan). This builder only encodes the byte the
caller supplies; the profile-aware caller
(runtime/radio.py: CoreRadio.scan_start) validates it against
RadioProfile.scan_type_values first -- the same shape
commands/dsp.py: set_agc uses for AGC-mode domain validation
(MOR-1522).
scan_stop(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to stop scanning (0x0E 0x00).
scope_set_center_type(center_type, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'set scope center type' CI-V command (0x27 0x1C).
Takes no receiver argument (MOR-2007, the latent setter-side twin
of MOR-1981/#2821 -- see the module docstring): 0x27 0x1C takes
exactly one data byte, no selector, so a receiver byte here would
build a genuinely different, wrong frame rather than address a
Main/Sub choice.
scope_set_span(span, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map, presets, receiver=None)
¶
Build the 0x27 0x15 SET frame for span-preset index span.
presets is the radio's declared span table
(profiles.RadioProfile.scope_span_presets_hz, from rigs/*.toml
[scope].span_presets_hz), supplied by the caller because
commands/ may not import profiles/ (.importlinter). It is
the only source of both the legal index range and the Hz value put on
the wire, so a profile that declares no presets rejects every index
through the same _validate_scope_range error every other
out-of-range span raises.
send_cw(text, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frames to send CW text.
CW text is sent in chunks of up to 30 characters per frame. Each character is sent as ASCII byte in the data field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
CW text to send (A-Z, 0-9, and common prosigns). |
required |
to_addr
|
int
|
Radio CI-V address. |
required |
from_addr
|
int
|
Controller CI-V address. |
CONTROLLER_ADDR
|
Returns:
| Type | Description |
|---|---|
list[bytes]
|
List of CI-V frame bytes (one per chunk). |
set_af_level(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'set AF output level' CI-V command.
set_af_mute(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set AF Mute command.
set_agc(mode, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set AGC mode command.
Encodes the raw single-BCD-byte AGC mode value. Which mode values are legal for a given radio (IC-7300's FAST/MID/SLOW vs. the X6200's OFF/FAST/SLOW/AUTO) is a per-profile domain, not a universal one — this builder only enforces the wire-format's single-BCD-byte range and leaves domain validation to the profile-aware caller (MOR-1522).
set_agc_time_constant(value, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set AGC time constant command.
set_antenna_1(enabled, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build ANT1 select command (0x12 0x00 <00|01>).
set_antenna_2(enabled, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build ANT2 select command (0x12 0x01 <00|01>).
set_anti_vox_gain(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Anti-Vox Gain command.
set_apf_type_level(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set APF Type Level command.
set_attenuator_level(db, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Set attenuator level in dB (IC-7610 supports 0..45 in 3 dB steps).
set_audio_peak_filter(mode, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set audio peak filter mode command.
set_auto_notch(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set auto-notch status command.
set_break_in(mode, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set break-in mode command.
Encodes the raw single-BCD-byte break-in value. Which values are legal
for a given radio (the documented OFF/SEMI/FULL domain on IC-705/
IC-7300/IC-9700/IC-7610 vs. the X6100/X6200, which have no confirmed
domain at all) is a per-profile question, not a universal one — this
builder only enforces the wire-format's single-BCD-byte range and
leaves domain validation to the profile-aware caller (MOR-1534, mirrors
MOR-1522's set_agc fix).
set_break_in_delay(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Break-In Delay command.
set_bsr(bsr, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to set band stacking register (0x1A 0x01).
set_compressor_level(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Compressor Level command.
set_cw_pitch(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set CW Pitch command.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
int
|
Raw sidetone level 0-255. Hz-to-level conversion is the caller's profile domain (profiles/control_domain.py: encode_legacy_control). |
required |
set_dash_ratio(value, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Dash Ratio command.
set_data_mode(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, cmd_map)
¶
Build a 'set DATA mode' CI-V command (0x1A 0x06 <0x00-0x03>).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
on
|
int | bool
|
False/0 to disable, True/1 to enable DATA1, or an explicit DATA mode 0-3. |
required |
set_digisel(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Set DIGI-SEL status (Command29-aware).
set_digisel_shift(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set DIGI-SEL Shift command.
set_drive_gain(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Drive Gain command.
set_dual_watch(on, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to enable or disable dual watch.
Dispatches to set_dual_watch_on/set_dual_watch_off (MOR-2007
ruling 1's split keys) rather than resolving a key of its own --
tests/test_profile_command_coverage.py resolves this delegate by
walking both branches by name; it deliberately carries no
@expose_command_key (its own key is a function of on, not of
cmd_map alone).
set_dual_watch_off(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to turn off dual watch.
Resolves the split key set_dual_watch_off (MOR-2007 ruling 1), not
the bare set_dual_watch the hardcoded fallback used to resolve --
see the module docstring.
set_dual_watch_on(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to turn on dual watch. See set_dual_watch_off.
set_filter_shape(shape, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set DSP IF filter shape command.
Encodes the raw single-BCD-byte filter-shape value. Which values are
legal is a per-profile [filter_shape] values domain, not a universal
enum -- this builder only enforces the wire-format's single-BCD-byte
range and leaves domain validation to the profile-aware caller
(MOR-1534, mirrors MOR-1522's set_agc fix).
set_filter_width(filter_index, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, cmd_map)
¶
Build a 'set DSP IF filter width' CI-V command (0x1A 0x03, cmd29).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filter_index
|
int
|
Filter width index encoded by the active radio profile. |
required |
receiver
|
int
|
RECEIVER_MAIN (0x00) or RECEIVER_SUB (0x01). |
RECEIVER_MAIN
|
set_freq(freq_hz, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, cmd_map)
¶
Build a 'set frequency' CI-V command.
Note
BCD encoding uses 5 bytes (10 decimal digits), so the maximum
representable frequency is 9,999,999,999 Hz (~10 GHz). Frequencies
outside this range will raise ValueError from :func:bcd_encode.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
freq_hz
|
int
|
Frequency in Hz (0 - 9,999,999,999). |
required |
to_addr
|
int
|
Radio CI-V address. |
required |
from_addr
|
int
|
Controller CI-V address. |
CONTROLLER_ADDR
|
receiver
|
int
|
RECEIVER_MAIN (0x00) or RECEIVER_SUB (0x01). |
RECEIVER_MAIN
|
Returns:
| Type | Description |
|---|---|
bytes
|
CI-V frame bytes. |
set_ip_plus(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Set IP+ on/off.
set_key_speed(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Key Speed command.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
int
|
Raw key-speed level 0-255. WPM-to-level conversion is the caller's profile domain (profiles/control_domain.py: encode_legacy_control). |
required |
set_main_sub_tracking(on, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Main/Sub Tracking status command (0x16 0x5E).
set_manual_notch_width(width, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'set manual notch width' CI-V command (0x16 0x57).
Encodes the raw single-BCD-byte notch-width value. Which values are
legal is a per-profile [notch] width_values domain, not a fixed
0/1/2 (WIDE/MID/NAR) enum on every radio — this builder only enforces
the wire-format's single-BCD-byte range and leaves domain validation
to the profile-aware caller (MOR-1542, mirrors set_break_in/
set_filter_shape/set_ssb_tx_bandwidth's MOR-1534 fix; CoreRadio keeps
the domain-legality seat).
set_mic_gain(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Mic Gain command.
set_mode(mode, filter_width=None, *, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, cmd_map)
¶
Build a 'set mode' CI-V command.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
Mode
|
Operating mode. |
required |
filter_width
|
int | None
|
Optional filter number (1-3). |
None
|
to_addr
|
int
|
Radio CI-V address. |
required |
from_addr
|
int
|
Controller CI-V address. |
CONTROLLER_ADDR
|
receiver
|
int
|
RECEIVER_MAIN (0x00) or RECEIVER_SUB (0x01). |
RECEIVER_MAIN
|
Returns:
| Type | Description |
|---|---|
bytes
|
CI-V frame bytes. |
set_monitor_gain(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Monitor Gain command.
set_nb(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Set Noise Blanker on/off.
set_nb_depth(value, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set NB Depth command.
set_nb_level(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set NB Level command.
set_nb_width(value, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set NB Width command.
set_notch_filter(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set Notch Filter level command.
set_nr(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Set Noise Reduction on/off.
set_nr_level(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set NR Level command.
set_pbt_inner(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set PBT Inner command.
set_pbt_outer(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a set PBT Outer command.
set_preamp(level=1, *, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, command29=True, cmd_map)
¶
Set preamp level (0=off, 1=PREAMP1, 2=PREAMP2).
set_quick_dual_watch(enabled, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Write the persistent Quick Dual Watch menu toggle.
See get_quick_split.
set_quick_split(enabled, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Write the persistent Quick Split menu toggle. See get_quick_split.
set_ref_adjust(value, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set REF Adjust command.
set_repeater_tone(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to set repeater tone (0x16 0x42).
set_repeater_tsql(on, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build CI-V command to set repeater TSQL (0x16 0x43).
set_rf_gain(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'set RF gain' CI-V command.
set_rf_power(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a 'set RF power' CI-V command.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
int
|
Power level 0-255 (radio maps to actual watts). |
required |
set_rit_frequency(offset_hz, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set RIT frequency offset command (0x21 0x00).
set_rx_antenna_ant1(enabled, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build set RX ANT state for ANT1 (0x12 0x00 <00|01>). Warning: also selects ANT1.
set_rx_antenna_ant2(enabled, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build set RX ANT state for ANT2 (0x12 0x01 <00|01>). Warning: also selects ANT2.
set_selected_mode(mode, data_mode, filter_index, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a "set selected receiver mode" CI-V command (0x26 0x00).
Frame layout: FE FE <to> <from> 26 00 <mode> <data_mode> <filter> FD.
The leading 0x00 data byte selects the active receiver (mirroring
:func:get_selected_mode); mode / data_mode / filter set the
full tuple so a mode-only change preserves the radio's current data-mode
and filter.
set_split(on, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Enable or disable split mode.
set_squelch(level, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map)
¶
Build a 'set squelch level' CI-V command.
set_ssb_tx_bandwidth(bandwidth, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set SSB TX bandwidth preset command.
Encodes the raw single-BCD-byte bandwidth value. Which values are legal
is a per-profile [ssb_tx_bw] values domain, not a universal enum --
this builder only enforces the wire-format's single-BCD-byte range and
leaves domain validation to the profile-aware caller (MOR-1534, mirrors
MOR-1522's set_agc fix).
set_tone_freq(freq_centihz, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map, ctcss_tones_centihz)
¶
Build CI-V command to set tone frequency (0x1B 0x00).
set_tsql_freq(freq_centihz, to_addr, from_addr=CONTROLLER_ADDR, receiver=RECEIVER_MAIN, *, command29=True, cmd_map, ctcss_tones_centihz)
¶
Build CI-V command to set TSQL frequency (0x1B 0x01).
set_tuner_status(value, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set tuner/ATU status command (0x1C 0x01). 0=off, 1=on, 2=tune.
set_tuning_step(step, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V command to set tuning step (0x10).
step (0-8, the BCD-encoded index) is a wire-format bound uniform
across every profile that declares tuning steps, not a per-radio
domain -- unlike scan type/resume below, this check stays here
(unaffected by MOR-2007 ruling 4).
set_vfo(code, *, to_addr, from_addr=CONTROLLER_ADDR, cmd_map)
¶
Select a VFO or receiver by its wire code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
int
|
The selector byte to send, taken from the caller's profile. |
required |
Which byte names which VFO is a property of the radio, declared per
profile as [vfo] main_select / sub_select. commands may not
import profiles, so the resolution belongs one layer up --
runtime/radio.py: CoreRadio._set_vfo_wire does it.
set_vox_delay(value, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set VOX Delay command (0x1A 0x05 0x02 0x92).
set_vox_gain(level, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set Vox Gain command.
set_xfc_status(on, to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build a set XFC status command (0x1C 0x02).
stop_cw(to_addr, from_addr=CONTROLLER_ADDR, *, cmd_map)
¶
Build CI-V frame to stop CW sending.
table_index_to_hz(index, *, table)
¶
Convert a table-based filter-width index to Hz.
Used by rigs like FTX-1 where a 2-digit code maps directly to a position in a mode-dependent lookup table.
CI-V Frame Format¶
FE FE— preamble (2 bytes)<to>— destination CI-V address (1 byte)<from>— source CI-V address (1 byte)<cmd>— command byte (1 byte)<sub>— optional sub-command (1 byte)<data>— optional payload (variable length)FD— terminator (1 byte)
Constants¶
from rigplane import IC_7610_ADDR, CONTROLLER_ADDR
IC_7610_ADDR # 0x98 — IC-7610's default CI-V address
CONTROLLER_ADDR # 0xE0 — Controller address (us)
Frame Building¶
build_civ_frame()¶
def build_civ_frame(
to_addr: int,
from_addr: int,
command: int,
sub: int | None = None,
data: bytes | None = None,
) -> bytes
Build a raw CI-V frame.
parse_civ_frame()¶
Parse raw bytes into a CivFrame dataclass.
Command Builders¶
Each function returns raw CI-V frame bytes ready to send. cmd_map is required and
keyword-only on every one of these; omitted here for brevity — see the sections above for the
full contract.
Frequency¶
get_frequency(to_addr=0x98, cmd_map=cmd_map) -> bytes
set_frequency(freq_hz: int, to_addr=0x98, cmd_map=cmd_map) -> bytes
Mode¶
get_mode(to_addr=0x98, cmd_map=cmd_map) -> bytes
set_mode(mode: Mode, filter_width: int | None = None, *, to_addr=0x98, cmd_map=cmd_map) -> bytes
RF Power¶
get_rf_power(to_addr=0x98, cmd_map=cmd_map) -> bytes
set_rf_power(level: int, to_addr=0x98, cmd_map=cmd_map) -> bytes
Meters¶
get_s_meter(to_addr=0x98, cmd_map=cmd_map) -> bytes
get_swr(to_addr=0x98, cmd_map=cmd_map) -> bytes
get_alc(to_addr=0x98, cmd_map=cmd_map) -> bytes
PTT¶
VFO¶
# ``code`` is the rig's selector byte, from the profile's
# ``[vfo] main_select`` / ``sub_select`` — this builder holds no
# name-to-byte table. ``radio.py: CoreRadio._set_vfo_wire`` resolves it.
select_vfo(code: int, *, to_addr=0x98, cmd_map=cmd_map) -> bytes
set_split(on: bool, to_addr=0x98, cmd_map=cmd_map) -> bytes
RF Controls (Command29-aware)¶
All RF control commands use build_cmd29_frame() for dual-receiver compatibility.
# Frame builder for Command29-wrapped commands
build_cmd29_frame(to_addr, from_addr, command, sub=None, data=None, receiver=RECEIVER_MAIN) -> bytes
# Attenuator
get_attenuator(to_addr=0x98, receiver=RECEIVER_MAIN, cmd_map=cmd_map) -> bytes
set_attenuator_level(db: int, to_addr=0x98, receiver=RECEIVER_MAIN, cmd_map=cmd_map) -> bytes
# No set_attenuator(bool) builder at this layer (MOR-2086): a command
# builder cannot see the profile, so it cannot resolve on/off to a valid
# dB value. Use runtime/radio.py: CoreRadio.set_attenuator instead, which
# resolves against the connected profile's declared values.
# Preamp
get_preamp(to_addr=0x98, receiver=RECEIVER_MAIN, cmd_map=cmd_map) -> bytes
set_preamp(level: int = 1, *, to_addr=0x98, receiver=RECEIVER_MAIN, cmd_map=cmd_map) -> bytes
# DIGI-SEL
get_digisel(to_addr=0x98, receiver=RECEIVER_MAIN, cmd_map=cmd_map) -> bytes
set_digisel(on: bool, to_addr=0x98, receiver=RECEIVER_MAIN, cmd_map=cmd_map) -> bytes
Constants: RECEIVER_MAIN = 0x00, RECEIVER_SUB = 0x01
CW¶
send_cw(text: str, to_addr=0x98, cmd_map=cmd_map) -> list[bytes] # Returns multiple frames
stop_cw(to_addr=0x98, cmd_map=cmd_map) -> bytes
Power Control¶
Response Parsers¶
parse_frequency_response()¶
Parse a frequency response to Hz. Raises ValueError if not a frequency response.
parse_mode_response()¶
Parse a mode response. Returns (mode, filter_width).
parse_meter_response()¶
Parse a meter response to 0–255 int.
parse_ack_nak()¶
Check if frame is ACK (True), NAK (False), or neither (None).
CI-V Command Codes¶
Values below are confirmed either as surviving constants in commands/_frame.py (frequency,
mode, levels, meters, PTT, attenuator, preamp, power, scope, ACK/NAK) or, for the three now
resolved entirely from a profile's CommandMap (VFO select, split, CW keying), as the value
rigs/ic7300.toml declares — a profile is free to declare a different byte for its own radio.
| Code | Command |
|---|---|
0x03 |
Read frequency |
0x04 |
Read mode |
0x05 |
Set frequency |
0x06 |
Set mode |
0x07 |
VFO select / equalize / swap |
0x0F |
Split on/off |
0x11 |
Attenuator |
0x14 |
Levels (RF power, etc.) |
0x15 |
Meter readings |
0x16 |
Preamp |
0x17 |
CW keying |
0x18 |
Power on/off |
0x27 |
Scope/waterfall |
0x1C |
PTT / transceiver status |
0xFB |
ACK (command accepted) |
0xFA |
NAK (command rejected) |