Bench results (real FT-991A)

Summary (as of version 1.1.9, 2026-10-05)

Everything below was tried on a real FT-991A with a Raspberry Pi 4 (Raspberry Pi OS Trixie, Python 3.13).

Area Result
CAT link, auto-detection of the port, reconnect after unplug / power cycle works
Frequency, mode, bands, VFO B (frequency and mode), split, A=B / B=A / swap works
RIT / XIT, filters and DSP (width, IF shift, contour, notches, DNR, NB), IPO / ATT / AGC works
Memory channels: list and recall works (the radio answers every MT read with channel 001: handled; see below)
Meters: S, power, SWR (warning limit), ALC and COMP work; ALC calibrated from one point, SWR ratio is an estimate from the raw value
PTT, TUNE, REAR / MIC switch, transmit switch in Admin, Lock PTT work
Remote audio both ways, Bluetooth headset, background listening on a phone works
Power off and power on over USB from standby works
Installer pack, ready-made image, Imager's own customisation screens, in-app update (self_update.sh), Tailscale (tailscale_setup.sh) work
Settings backup and restore, update notice work
C4FM RX/TX DG-ID not reachable over CAT (no menu value changes)
Quick split (QS;) implemented, not yet tried
Automatic rollback of a failed update, restore.sh, uninstall.sh scripts exist; a full real-Pi run of each is not recorded yet

Radio behaviour that differs from the CAT manual (all handled in the code): - PR (speech processor): the radio uses 0 = off, 1 = on, not 1 / 2 as printed. - FT (TX VFO): set 2 / 3 (TX on A / B), read 0 / 1. - MT (memory read with tag): the answer to MT005; carries the data of channel 5 but always says channel 001; empty channels answer ?;. The server matches the answer on MT alone and takes the channel number from its own request. A channel that stays silent is retried and then read with MR (no tag). - EX153 (WIRES DG-ID): the radio answers with three digits (EX153000;), the manual shows two. - The radio answers a read taken immediately after a VFO command with the old value: reads after VFO operations wait 0.35 s and repeat. - The radio does not announce VFO B changes: VFO B is polled every second.

The sections below are the log of the tests in the order they were done (some notes at the time said "to be tested": the summary above is current).

Bench 1 - read-only: PASSED

Date: 2026-10-01. Hardware: Raspberry Pi (hostname FT991A), FT-991A over USB, app v0.1.0. Method: bench1_readonly.py (sends read commands only).

Command Reply Meaning / status
ID; ID0670; FT-991A identified. Confirmed on hardware
AI; AI1; auto-information was already on (the service enabled it). Confirmed
IF; IF001014220000+000000200000; 25-character body matches the manual's layout (mem 001, 14.220000 MHz, clarifier +0000, RIT/XIT off, mode 2 = USB, VFO). Confirmed
FA; / FB; FA014220000; / FB007000000; 9-digit frequencies. Confirmed
MD0; MD02; USB. Confirmed
TX; TX0; receiving. Confirmed
AG0; RG0; MG; PC; AG0040 RG0255 MG041 PC005 levels read as 3 digits; TX power was 5 W. Confirmed
SM0; SM0032; S-meter raw 32 at idle (first calibration point; antenna state unknown)
RM3..RM6; RM3000 RM4000 RM5000 RM6000 COMP/ALC/PO/SWR are 0 while receiving. Confirmed

Link statistics: tx 16, rx 28, timeouts 0, rejected (?;) 0, unsolicited 12.

Findings: - The CAT port is /dev/ttyUSB0 (the FT-991A exposes two ports; detection picked the right one at 38400 baud). - No read command was answered with ?;. - The service user needs read access to /opt/radio-remote/..., not /home/<user>/... (home directories are private). - The service must be stopped while running the bench script: it holds the port.

Bench 2 - app against the real radio, receive only, PTT disabled: PASSED (operator report)

Antenna tuner on/off (AC) and split (FT): replies from the real radio

Sent Radio replied Meaning
AC; AC000; tuner off
AC001; / AC; AC001; / AC001; tuner on, reads back on
AC000; / AC; AC000; / AC000; tuner off again. The command layer is correct; the app's TUNER chip lights teal (operator report)
FT; FT0; transmit on VFO A (normal)
TS; TS0; TXW off
FT3; FT1; + RI50; RI61; transmit now on VFO B = split. The radio also announces RI5x/RI6x (A/B transmit flags)
FT2; FT0; + RI51; RI60; back to VFO A

So FT behaves as the manual says: set 2 / 3 (TX on A / B), read 0 / 1. Split in the app = FT3;, normal = FT2;; the state follows the radio's own FT announcements. QS; (quick split) and the TUNE button (AC002;) are implemented but NOT yet verified. Auto-information also streams RM0nnn; (front-panel meter) continuously; currently ignored.

VFO operations, tuner, DG-ID: operator report after the first VFO B build

Installer and updater on a real Pi: PASSED

Bench finding: manual vs radio, speech processor (PR)

The service logged bad frame from radio: bad PR every slow-poll cycle. Raw capture from the real radio:

Sent Radio replied
PR0; PR00; (processor off)
PR1; PR10; (parametric mic EQ off)

The manual says the on/off digit is 1 = OFF, 2 = ON; the radio uses 0 = OFF, 1 = ON. Set test on the real radio:

Sent Radio
PR01; accepted; PR0; then reads PR01; (processor ON)
PR02; ?; (rejected)
PR00; accepted; reads PR00; (OFF)

Fixed in both directions (parser and encoder): the processor toggle now sends PR01; / PR00;. Before the fix the UI would have turned the processor on when asked to turn it off. Lesson: the CAT manual can be wrong on value tables; every set command in the controls panel should be checked on the real radio (Bench 2b), not trusted from the manual. Side note: with auto-information on, the radio streams RM0nnn; (front-panel meter) frames continuously; they are currently ignored.

All other polled controls (NA, SH, IS, CO, BP, BC, NR, RL, NB, NL, PA, RA, RT, XT, PL, ML, AC) produced no warnings on the real radio, i.e. their reply formats parsed. Rejections (?;) are not logged at warning level, so a command refused in the current mode would not show up in that log.

Receive audio: PASSED (operator report)

Listen in the browser: receive audio is heard and the RX meter moves. Observation: with IPO selected nothing useful is heard, with AMP1/AMP2 it receives. Expected radio behaviour (IPO = no preamp gain) but needs confirming against the radio's own display (open question: do app labels IPO/AMP1/AMP2 match the radio's front panel?).

Audio: device detection and CPU

arecord -l / aplay -l (Pi 4, radio on): the radio appears as card 1: CODEC [USB Audio CODEC], device 0 for both capture and playback; the other playback cards are the Pi's headphones and two HDMI outputs. Exactly one USB audio CODEC, so auto-detection selects plughw:CARD=CODEC,DEV=0 for both directions.

audio_spike.py on a Raspberry Pi 4 Model B (aarch64, 4 cores, Python 3.13.5):

Test Result
Opus encode 96 / 32 / 24 kbps 599 / 851 / 849 us per 20 ms frame (3.0 / 4.3 / 4.2 % of one core)
Opus decode 124-156 us per frame (about 0.7 %)
measured bitrate for the 32 kbps target 31.7 kbps (the bitrate patch works)
WebRTC loopback, 1 listener 20.8 % of one core (server encode + client decode + SRTP, both ends in one process)
WebRTC loopback, 3 listeners 55.6 % of one core
frame delivery 50 frames/s per listener in both cases

Reading: real server-side cost is below these figures because the loopback also runs the client. A Pi 4 has ample headroom for the default audio.max_peers = 3; a separate audio process is not needed there. A Pi 3B+ is expected (estimate, not measured) to be 2-3x slower per core: use max_peers 1-2.

At that point still unverified (all of it was verified later, see the summary at the top): every set command, the controls panel, PTT, audio, NA/GT quirks, PS0;/PS1;. Meter calibration against real signals is still open.

FTDX101D (real radio, 2026-10-05)

Hardware: Raspberry Pi 4 (hostname FT991A), FTDX101D over USB, app v1.1.9 plus the local FTDX101D work. The radio first stayed silent until its menu CAT RTS was set to OFF (with RTS high it answered ID0681;), CAT rate 38400, Enhanced port /dev/ttyUSB0. Read-only first contact: 36 commands answered, 0 timeouts, 0 rejected.

Check Result
Frequency, band, mode (MAIN) and the SUB receiver (FB, OI) work, both directions
FR (which receivers listen), FT (transmit MAIN / SUB), VS (operated receiver) work; the radio's own keys are followed
USB audio carries one receiver SSB OUT SELECT 0 / 1 switches it; the other mode families answer the same way
Audio out level, audio in level (EX0101 09, EX010113 and the AM / FM / DATA / RTTY / CW versions) work
Filter, noise, receiver controls for MAIN and for SUB (P1 = 0 / 1) work
Speech processor PR0 is 0 = OFF / 1 = ON, the manual says 1 / 2 and PR02; gets ?;; the radio's PROC light follows
PROC / PITCH knob sets the AMC output level (AO) while the menu PROC LEVEL is not COMP; sets PL when it is COMP
CW keyer (KS, KP, KR, BI) the values apply; the radio's main screen does not show them outside CW mode. SD answers 2 digits, not 4: not offered
TUNE (AC002;), antenna tuner on / off work
Memories (MT read, MC recall, VM; = V/M key) work; the radio has only channel 001 stored. MT answers have the FT-991A layout
PTT and meters PTT keyed several times by the operator; SUB on the air not tried

Not tried: transmitting on the SUB receiver, and the FTDX101MP.