feat: native Kenwood CAT backend

A sixth CAT backend, talking to a TS-590/890/990/2000 over its serial port with
no OmniRig in between — frequency, mode, VFO, split and PTT. Elecraft K3/K4 and
the "Kenwood" setting on other radios speak the same dialect.

The protocol was not researched from scratch: internal/catemu already ANSWERS
these commands, pretending to be a TS-2000 so an ACOM amplifier follows OpsLog.
The IF frame layout here is read from the same format string catemu emits, so
the two halves of the repository agree by construction — and the test caught my
own fixture being one character short, which is exactly the error that layout
invites.

Design notes worth keeping:

  - IF; is the poll. One frame carries frequency, TX state, mode, VFO and split,
    so simplex operation costs a single round trip; the other VFO is only asked
    for when split is actually on.
  - FA/FB take ELEVEN digits here where Yaesu uses nine. That is the likeliest
    place to copy the Yaesu backend and be wrong by a factor of a hundred, so it
    has its own test.
  - Every lesson the Yaesu backend learned the hard way is built in from the
    start: replies matched to the command that asked, "?;" remembered so a poll
    stops paying a timeout for an unsupported command, the serial handle closed
    before reopening, and a rig that answers nothing reported as absent rather
    than "connected".

Untested on hardware — I have no Kenwood here. The frame parsing is covered by
tests against catemu's own format.
This commit is contained in:
2026-07-30 11:56:41 +02:00
parent da886de189
commit b16cb973f2
7 changed files with 606 additions and 6 deletions
+4
View File
@@ -1906,6 +1906,8 @@ export namespace main {
xiegu_addr: number;
yaesu_port: string;
yaesu_baud: number;
kenwood_port: string;
kenwood_baud: number;
icom_port: string;
icom_baud: number;
icom_addr: number;
@@ -1942,6 +1944,8 @@ export namespace main {
this.xiegu_addr = source["xiegu_addr"];
this.yaesu_port = source["yaesu_port"];
this.yaesu_baud = source["yaesu_baud"];
this.kenwood_port = source["kenwood_port"];
this.kenwood_baud = source["kenwood_baud"];
this.icom_port = source["icom_port"];
this.icom_baud = source["icom_baud"];
this.icom_addr = source["icom_addr"];