Skip to content

CI-V Commands

The library supports a comprehensive set of CI-V commands for controlling your Icom transceiver.

Frequency

# Get current frequency (returns Hz as int)
freq = await radio.get_frequency()
print(f"{freq / 1e6:.3f} MHz")  # 14.074 MHz

# Set frequency
await radio.set_frequency(14_074_000)   # 20m FT8
await radio.set_frequency(7_074_000)    # 40m FT8
await radio.set_frequency(3_573_000)    # 80m FT8
await radio.set_frequency(144_300_000)  # 2m SSB

Frequency is always in Hz (integer). The radio internally uses BCD encoding (5 bytes, little-endian).

Mode

from icom_lan import Mode

# Get current mode
mode = await radio.get_mode()
print(mode.name)  # "USB"

# Get mode + filter number (if reported)
mode, filt = await radio.get_mode_info()

# Set mode (string or enum)
await radio.set_mode("USB")
await radio.set_mode("CW")
await radio.set_mode(Mode.LSB)

# Set/read filter number
await radio.set_filter(2)
f = await radio.get_filter()

Available modes:

Mode Value Description
LSB 0x00 Lower Sideband
USB 0x01 Upper Sideband
AM 0x02 Amplitude Modulation
CW 0x03 Continuous Wave
RTTY 0x04 Radio Teletype
FM 0x05 Frequency Modulation
WFM 0x06 Wide FM
CW_R 0x07 CW Reverse
RTTY_R 0x08 RTTY Reverse
DV 0x17 D-Star Digital Voice

RF Power

# Get RF power level (0–255)
power = await radio.get_power()

# Set RF power level
await radio.set_power(128)  # ~50% power
await radio.set_power(255)  # Maximum power
await radio.set_power(0)    # Minimum power

Power Mapping

The 0–255 value is the radio's internal setting. The actual wattage depends on the radio model and operating mode. For IC-7610: 255 ≈ 100W on HF.

Meters

# S-meter (0–255, receive signal strength)
s = await radio.get_s_meter()

# SWR meter (0–255, during TX only)
swr = await radio.get_swr()

# ALC meter (0–255, during TX only)
alc = await radio.get_alc()

TX-Only Meters

get_swr() and get_alc() will timeout if the radio is not transmitting. Wrap them in try/except:

from icom_lan.exceptions import TimeoutError

try:
    swr = await radio.get_swr()
except TimeoutError:
    swr = None  # Not transmitting

PTT (Push-To-Talk)

# Start transmitting
await radio.set_ptt(True)

# Stop transmitting
await radio.set_ptt(False)

Transmit Safety

Always ensure:

  • Your antenna is connected
  • You are authorized to transmit on the current frequency
  • PTT is released when done (use try/finally)
try:
    await radio.set_ptt(True)
    # ... do TX work ...
finally:
    await radio.set_ptt(False)

VFO Control

# Select VFO
await radio.select_vfo("A")     # VFO A (simpler radios)
await radio.select_vfo("B")     # VFO B
await radio.select_vfo("MAIN")  # Main receiver (IC-7610)
await radio.select_vfo("SUB")   # Sub receiver (IC-7610)

# A=B command (semantics can vary on MAIN/SUB radios; use with care)
await radio.vfo_equalize()

# Swap VFO A and B
await radio.vfo_exchange()

# Split mode
await radio.set_split_mode(True)   # TX on VFO B, RX on VFO A
await radio.set_split_mode(False)

Attenuator & Preamp

These commands use Command29 framing for dual-receiver radios (IC-7610). By default, they target the MAIN receiver.

from icom_lan import RECEIVER_MAIN, RECEIVER_SUB

# --- Attenuator ---
# Get attenuation level in dB
db = await radio.get_attenuator_level()  # Returns 0, 3, 6, ..., 45
print(f"ATT: {db} dB")

# Set attenuation level (0–45 in 3 dB steps)
await radio.set_attenuator_level(18)  # 18 dB
await radio.set_attenuator_level(0)   # Off

# Simple toggle (compat — maps on=18dB, off=0dB)
await radio.set_attenuator(True)
await radio.set_attenuator(False)

# Boolean check
is_on = await radio.get_attenuator()  # True/False

# --- Preamp ---
# Get preamp level
level = await radio.get_preamp()  # Returns 0, 1, or 2
print(f"Preamp: {level}")

# Set preamp level
await radio.set_preamp(0)  # Off
await radio.set_preamp(1)  # PREAMP 1
await radio.set_preamp(2)  # PREAMP 2

# --- Target SUB receiver (IC-7610) ---
await radio.set_preamp(1, receiver=RECEIVER_SUB)
db = await radio.get_attenuator_level(receiver=RECEIVER_SUB)

Command29 — Dual-Receiver Radios

The IC-7610 has two independent receivers (MAIN and SUB). Commands like attenuator and preamp are per-receiver. The library automatically wraps them with the 0x29 <receiver> CI-V prefix that tells the radio which receiver to target, without changing the selected VFO.

Single-receiver radios (IC-7300) don't use Command29 — the receiver parameter is ignored.

CW Keying

Send CW text using the radio's built-in keyer:

# Send CW text (auto-chunked to 30 chars)
await radio.send_cw_text("CQ CQ DE KN4KYD K")

# Stop CW in progress
await radio.stop_cw_text()

CW text supports A–Z, 0–9, and standard prosigns. Long messages are automatically split into 30-character chunks.

Power Control

# Remote power on
await radio.power_control(True)

# Remote power off
await radio.power_control(False)

Note

Power-on requires the radio to maintain network connectivity in standby mode. This is model-dependent.

Raw CI-V Commands

For commands not covered by the high-level API, use send_civ() directly:

# Send any CI-V command
response = await radio.send_civ(
    command=0x1A,     # CI-V command byte
    sub=0x05,         # Sub-command (optional)
    data=b"\x01\x23", # Payload (optional)
)

print(f"Command: 0x{response.command:02X}")
print(f"Data: {response.data.hex()}")

This gives you access to the full CI-V command set — refer to your radio's CI-V reference manual for available commands.