Skip to content

CLI Reference

Fombriti edited this page May 7, 2026 · 1 revision

CLI Reference

Every GUI feature is also available headless via python -m quansheng_toolkit. The CLI is useful for:

  • Scripting — bulk-update a fleet of radios from a CSV repository
  • CI / automated tests — integration with pytest and unittest
  • Headless servers / Raspberry Pi without a Qt environment
  • Reproducible setups — declarative shell scripts you can commit to git

Tip

The CLI works fully offline, like the GUI. Bundled firmware images and the manifest live inside the package — no network access ever.

Conventions

  • All commands accept --port <PATH> to target a specific serial device (/dev/ttyUSB0, COM3, /dev/cu.usbserial-XXX). If omitted, the toolkit auto-detects.
  • Destructive commands require --yes-i-understand.
  • All commands accept --help for inline documentation.

info

Open a connection, do the protocol handshake, print firmware version. The lightweight liveness check.

python -m quansheng_toolkit info

Output:

Connected: /dev/ttyUSB0
Firmware: F4HWN_5.4.0
Bootloader: 7.00.07

read

Dump the entire EEPROM to a binary file.

python -m quansheng_toolkit read -o eeprom.bin

Use this before any destructive operation. The output is a raw byte image; the toolkit can re-import it via make-bin -i and apply-full --eeprom.

list

Decode and print the channel grid.

# From a live radio
python -m quansheng_toolkit list

# From a saved EEPROM image
python -m quansheng_toolkit list --from-file eeprom.bin

Output is a Rich-formatted table with channel name, RX/TX freq, mode, tones, scan list.

show-settings

Print every named setting with its current value.

python -m quansheng_toolkit show-settings

Output groups settings by section (audio, display, power, etc.).

list-settings

Print every setting key the toolkit knows how to read or write, with type and value range.

python -m quansheng_toolkit list-settings

Useful for discovering what --set k=v accepts in make-bin. Output:

audio.beep                bool
audio.eot                 enum: off, sound, visual, all
audio.set_eot             enum: off, sound, visual, all
display.contrast          int(0..15)
display.invert            bool
display.bl_time           enum: off, 5s, 10s, 20s, 1m, 2m, 4m, on
...

make-bin

Build an EEPROM image by patching a starting image with CSV channels and/or --set k=v settings.

python -m quansheng_toolkit make-bin \
    -i eeprom.bin \
    --csv channels.csv \
    --set "audio.beep=on" \
    --set "display.contrast=10" \
    -o patched.bin \
    --show

Flags:

  • -i / --input — starting EEPROM image (required, usually a fresh read dump)
  • --csv — channels in 21-column CHIRP format (optional)
  • --derive-from-comment — read scan-list assignments from the Comment column (recommended)
  • --set k=v — override a setting; can be repeated
  • -o / --output — output image path (required)
  • --show — print a summary of changes after building

The output .bin is the same shape as a read dump, so it can be applied with apply-full.

apply-full

Upload a full EEPROM image to the radio with byte-for-byte readback verification.

python -m quansheng_toolkit apply-full --eeprom patched.bin

The toolkit:

  1. Writes the image in 64-byte blocks.
  2. Reads back each block as it goes, verifying the write.
  3. Retries any block that didn't persist (logs the retry).
  4. At the end, performs a final full re-read and compares against the source image.

Important

apply-full is verified per-block but not per-image. Every block is ACKed and read back individually, but the toolkit does not re-read the entire image at the end (would double the wall-clock time). On rare occasions a block can be silently lost between ACKs. Run read -o postwrite.bin after a critical apply and diff it against your intended image if you need certainty.

dfu-info

Detect a radio in DFU bootloader mode (PTT + Side Key 2 boot).

python -m quansheng_toolkit dfu-info

Output:

Bootloader: 7.00.07
Identified: UV-K5 V3 / UV-K1(8) v3 Mini Kong (PY32F071)
Compatible bundled firmwares (in firmwares/):
  - f4hwn_fusion_5.4.0_k1_k5v3.bin  (F4HWN Fusion 5.4.0)
  - f4hwn_fusion_5.3.1_k1_k5v3.bin  (F4HWN Fusion 5.3.1)
  - f4hwn_fusion_4.3.2_k5v3.bin     (F4HWN Fusion 4.3.2)
  - stock_k5v3_7.00.11.bin          (Quansheng stock 7.00.11)

dfu-flash

Flash a firmware image while the radio is in DFU mode.

python -m quansheng_toolkit dfu-flash \
    --eeprom firmwares/f4hwn_fusion_5.4.0_k1_k5v3.bin \
    --target k5_v3 \
    --yes-i-understand

Flags:

  • --eeprom — path to the .bin firmware (required)
  • --target — canonical target identifier (required; must match dfu-info output)
  • --yes-i-understand — mandatory acknowledgement (required)
  • --force — bypass the bootloader allowlist (developer use only)

Caution

Read Flashing Firmware before using this command for the first time. The CLI bypasses the GUI's three-stage confirmation, so all the safety responsibility is on you.

dump-calibration

Save the per-unit calibration region to a file.

python -m quansheng_toolkit dump-calibration -o calibration_K5V3_SN12345.bin

See Calibration and Backup for why and when to use this.

restore-calibration

Restore a previously-dumped calibration. Per-unit only — never restore another radio's calibration.

python -m quansheng_toolkit restore-calibration \
    --file calibration_K5V3_SN12345.bin \
    --yes-i-understand

diff-calibration

Byte-by-byte compare two calibration dumps.

python -m quansheng_toolkit diff-calibration --a cal_before.bin --b cal_after.bin

Output highlights only the regions where bytes differ.

Scripting recipes

Snapshot a radio (full state)

SN=$(python -m quansheng_toolkit info | grep 'Serial' | awk '{print $2}')
DATE=$(date +%Y%m%d_%H%M%S)
python -m quansheng_toolkit read              -o snapshot_${SN}_${DATE}_eeprom.bin
python -m quansheng_toolkit dump-calibration  -o snapshot_${SN}_${DATE}_calibration.bin

Apply a CSV to many radios

for port in /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2; do
    python -m quansheng_toolkit --port $port read -o /tmp/cur_${port##*/}.bin
    python -m quansheng_toolkit make-bin \
        -i /tmp/cur_${port##*/}.bin \
        --csv fleet_channels.csv \
        --derive-from-comment \
        -o /tmp/patched_${port##*/}.bin
    python -m quansheng_toolkit --port $port apply-full --eeprom /tmp/patched_${port##*/}.bin
done

Validate a CSV without writing to a radio

make-bin runs the full encoder pipeline. If the CSV has bad syntax or out-of-range values, you'll see the error here, before any write:

python -m quansheng_toolkit make-bin -i /dev/null --csv channels.csv -o /tmp/test.bin --show

(Pass /dev/null as the input — make-bin will fail because /dev/null isn't a valid EEPROM image, but only after parsing the CSV. So syntax errors surface first.)

For a real validation, point -i at any saved read dump.


Next: Troubleshooting & FAQ for common pain points.

Clone this wiki locally