Read split from the radio, and read two of them

Split. RadioState carries a transmit frequency, zero meaning the radio
transmits where it listens, so split is not a second flag that can disagree
with it. The contact stores it in N1MM's QSX column, the entry window shows
14008.00 followed by the transmit frequency, and the bandmap draws a red bar
there. SetSplitAsync sets the frequency before turning split on, or a radio
last split somewhere else transmits there.

Every command now goes out with a + in front, asking rigctld for its extended
answer: named fields ended by an RPRT line. The raw answer is bare values with
no terminator, so the client had to know how many lines each command returns —
there was a `command == "m"` special case for the one that returns two. Add a
third such command and get the count wrong once, and every later answer is read
against the wrong command for the rest of the session. RigctldReply parses the
extended form and is tested on its own.

A radio that cannot do split answers RPRT -11. That is an answer, not a broken
connection, so the frequency and mode it did report still count.

Two radios. Settings hold a list rather than one host and port, with the single
radio an older settings file holds carried into it. Both radios are read and
both show on the bandmap, the active one green and the other orange, but only
the active one drives the entry window: the second radio moving must not drag
the operator off the station being worked. Ctrl+Tab swaps, and a contact
records which radio made it.

This is not a full two-radio operating position — no second entry window, no
alternating CQ, no audio switching. It is two radios read and logged correctly.

Tested against a stand-in for rigctld over a real socket, and looked at under
Xvfb with two fake radios, one of them split.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 16:40:42 +00:00
parent da9884ebf5
commit 43be3816c3
19 changed files with 706 additions and 98 deletions

View File

@@ -46,7 +46,7 @@ scorer: red for a dupe, green for a new multiplier, blue for points.
| While typing | dupe check, multiplier check, points, country and zone from the country file |
| Windows | entry, log, check, bandmap, score summary, packet |
| Editing | double-click a cell in the log, or open the whole contact with Ctrl+Y; Delete removes it. All of it goes out to the other stations |
| Radio | hamlib `rigctld`, reconnecting on its own |
| Radio | one or two radios over hamlib `rigctld`, split, reconnecting on its own |
| Cluster | DX cluster over telnet, spots feeding the bandmap, Alt+P to spot a station |
| Bandmap | drawn like N1MM's: a frequency scale with the receiver on it and callsigns beside it, joined by leader lines |
| Network | contacts shared with the other stations of a multi-operator entry, in N1MM's own contact message |
@@ -120,6 +120,36 @@ Correcting the country prefix by hand changes the score. The country file is a
best guess for calls it has no rule for, so what the contact says now wins over
what the file says.
### Radios
**Config → Radios** takes a `rigctld` address per radio. Each radio needs its
own `rigctld`, started for whichever rig is on that port:
rigctld -m 2028 -r /dev/ttyUSB0 -t 4532
rigctld -m 1035 -r /dev/ttyUSB1 -t 4533
Commands go out with a `+` in front, which asks `rigctld` for its extended
answer: named fields ended by an `RPRT` line. The raw answer is bare values with
no terminator, so the client has to know how many lines each command returns,
and one wrong count leaves the connection reading every later answer against
the wrong command.
Split is read from the radio and recorded: the contact stores where we
transmitted in N1MM's QSX column, the entry window shows `14008.00 ▸ 14020.0`,
and the bandmap draws a red bar at the transmit frequency. A radio that cannot
do split answers `RPRT -11`; that is an answer, not a broken connection, and
everything else it reported still counts.
A second radio makes the station SO2R. Both are read and both show on the
bandmap — the one you are on in green, the other in orange — but only the one
you are on drives the entry window, so the second radio moving cannot drag you
off the station you are working. Ctrl+Tab moves you to the other radio; contacts
record which one made them.
Not there yet: a second entry window, alternating CQ, and audio switching. What
is here is two radios read and logged correctly, not a full two-radio operating
position.
### The bandmap
A frequency scale down the left with the stations written out beside it. Each
@@ -134,10 +164,9 @@ Callsigns are coloured by the same scorer as the entry window, so a dupe reads
as a dupe here too. Clicking a callsign puts the radio there with the call
already in the entry window; clicking anywhere else just moves the radio.
The green bar on the scale is the receiver, as wide as the mode it is in.
`VfoRole` has transmit and second-radio bars ready, but nothing feeds them yet:
the radio does not report a transmit VFO or a second radio, so those bars stay
out rather than showing a guess.
The bars on the scale are as wide as the mode passes: green where you are
listening, red where the radio transmits when working split, orange for the
other radio of a two-radio station.
Band-plan colouring of the scale is not there. The segments differ by ITU region
and the program has no band-plan table, so it would be guesswork.
@@ -210,7 +239,9 @@ beyond logging them, and the check window's Call History and Exchange columns,
which are left out rather than shown empty.
The radio, network and keyer clients are tested against fakes that speak the
documented protocols. None has been run against a real radio or keyer. The
documented protocols — the radio one over a real socket, against a stand-in for
`rigctld` that answers in the extended form. None has been run against a real
radio or keyer. The
cluster client is tested over a real socket against a node fake that sends the
telnet negotiation, the login prompt and spot lines, but not against a live
node.