Skip to content

Fix SWR protection on Lab599 Discovery TX-500 (#599)#626

Merged
patrickrb merged 2 commits into
devfrom
optio/task-e15c1ef5-94d3-43b4-bfd3-c8e2b22eb6a9
Jul 22, 2026
Merged

Fix SWR protection on Lab599 Discovery TX-500 (#599)#626
patrickrb merged 2 commits into
devfrom
optio/task-e15c1ef5-94d3-43b4-bfd3-c8e2b22eb6a9

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Problem

SWR protection never fired on the Lab599 Discovery TX-500 (issue #599). The rig is handled by DiscoveryTX500Rig, which extended KenwoodTS2000Rig and inherited its meter read + parse unchanged. Two things there are incompatible with the TX-500's CAT interface, so swr stayed 0 and MeterProtectionController was never tripped:

  1. The read command never selected the SWR meter. readMeters() only ever sent RM;. Per the TX-500 CAT protocol the rig first needs RM1; to switch the meter to SWR, then RM; returns the reading.
  2. The response parse expected the TS-590/2000 layout. The TX-500 replies RM10023; → after stripping RM, data = "10023": the selector digit is at index 0 ('1' = SWR), not index 2, and the value is substring(1,5) (a raw 00000030 field). is590MeterSWR() checks charAt(2), so it never matched and the reading was dropped.
  3. Scaling was off. The 00000030 field is a different curve from the TS-590's, so it needed a TX-500-specific mapping before reaching the halt threshold.

Fix

Give DiscoveryTX500Rig its own meter handling rather than inheriting the TS-2000 path:

  • sendMeterReadCommand() override sends RM1; (select SWR) before RM;.
  • handleMeterReply() override parses the RM1vvvv layout (selector at index 0, value at substring(1,5)) via new pure-logic helpers Yaesu3Command.isTX500MeterSWR() / getTX500MeterValue().
  • Value → SWR mapping. Lab599's published value→SWR chart is linear (cat = 3·(swr−1), i.e. swr = 1 + cat/3; cat 6 → 3.0:1, cat 27 → 10:1). The mapped ratio is then normalized through the existing MeterProtectionController.swrRatioToNormalized() — the same scale the user-configured halt threshold is stored on — so the halt decision is meaningful for this rig.

KenwoodTS2000Rig gains two protected seams (sendMeterReadCommand(), handleMeterReply()) so the override is a clean hook rather than a copy of the RX/parse path; the inherited TS-2000/TS-590 behavior is unchanged.

Scope / assumptions

  • SWR only. ALC protection was raised as a non-blocking open question in the issue; the TX-500 reports no ALC meter here, so ALC is passed as -1 ("not reported"). This can be a follow-up if the ALC meter id + select command are confirmed.
  • Went with the direct DiscoveryTX500Rig override rather than routing through hamlib (which currently has no rig_get_level/meter binding), per the reporter's own build-vs-hamlib analysis in the issue.

Tests

Per CLAUDE.md, all new logic is covered by pure-logic unit tests:

  • Yaesu3CommandTest — TX-500 RM10023 → SWR selector true + value 23, zero value, non-'1' selector rejected (distinct from the TS-590 index-2 layout), and short-data defaults.
  • DiscoveryTX500RigTest — cat→ratio chart anchor points, monotonicity, unity floor, normalization alignment with the default halt threshold (cat 6 == 120 == 3.0:1), and end-to-end shouldHaltForSwr decisions (cat 23 halts, cat 3 does not).

./gradlew :app:testDebugUnitTest passes (full suite, no regressions).

🤖 Generated with Claude Code

The TX-500 inherited its meter read+parse from KenwoodTS2000Rig, which is
incompatible with the TX-500's CAT interface, so SWR always stayed 0 and
MeterProtectionController never tripped:

- readMeters() only ever sent RM;. The TX-500 needs RM1; to switch the meter
  to SWR first, then RM; returns the reading.
- The RM reply RM1vvvv puts the SWR selector at index 0 (not index 2 like the
  TS-590) and the value at substring(1,5), so is590MeterSWR() never matched.
- The raw 0000-0030 field needed a TX-500-specific curve to normalize into the
  0-255 scale MeterProtectionController's halt threshold uses.

Give DiscoveryTX500Rig its own meter handling: send RM1; before RM;, parse the
RM1vvvv layout, and map the 0-30 field to an SWR ratio (linear per Lab599's
published chart: swr = 1 + cat/3) normalized on the same scale the halt
threshold is stored on. ALC is reported as -1 (not present on this rig).

KenwoodTS2000Rig gains protected sendMeterReadCommand()/handleMeterReply()
hooks so the override is a clean seam rather than a copy of the RX path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes SWR protection for the Lab599 Discovery TX-500 by adding TX-500-specific meter selection, parsing, and scaling so SWR readings correctly reach MeterProtectionController and can trigger TX halt/lockout.

Changes:

  • Added overridable meter seams to KenwoodTS2000Rig (sendMeterReadCommand(), handleMeterReply()) and routed RM parsing through them.
  • Implemented TX-500 meter selection (RM1; then RM;), TX-500 RM reply parsing helpers, and TX-500 cat-value → SWR-ratio → normalized mapping.
  • Added unit tests covering TX-500 RM parsing and the cat-value mapping / protection decisions.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ft8af/app/src/test/java/com/k1af/ft8af/rigs/Yaesu3CommandTest.java Adds unit coverage for TX-500 RM reply selector/value parsing.
ft8af/app/src/test/java/com/k1af/ft8af/rigs/DiscoveryTX500RigTest.java Adds pure-logic tests for TX-500 cat-value → SWR mapping and halt decisions.
ft8af/app/src/main/java/com/k1af/ft8af/rigs/Yaesu3Command.java Adds TX-500 RM parsing helpers (isTX500MeterSWR, getTX500MeterValue).
ft8af/app/src/main/java/com/k1af/ft8af/rigs/KenwoodTS2000Rig.java Introduces protected hooks for meter polling/parsing so subclasses can override cleanly.
ft8af/app/src/main/java/com/k1af/ft8af/rigs/KenwoodTK90RigConstant.java Adds TX-500 SWR meter select CAT command constant and accessor.
ft8af/app/src/main/java/com/k1af/ft8af/rigs/DiscoveryTX500Rig.java Overrides meter read/parse to support TX-500 SWR selection, parsing, normalization, and alerting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ft8af/app/src/test/java/com/k1af/ft8af/rigs/DiscoveryTX500RigTest.java Outdated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@patrickrb
patrickrb merged commit 5dbff0c into dev Jul 22, 2026
15 checks passed
@patrickrb
patrickrb deleted the optio/task-e15c1ef5-94d3-43b4-bfd3-c8e2b22eb6a9 branch July 22, 2026 22:24
patrickrb added a commit that referenced this pull request Jul 24, 2026
…ramed but split on '\r') (#685)

The Kenwood-family rigs (KenwoodTS570Rig, KenwoodTS590Rig, KenwoodTS2000Rig, and
DiscoveryTX500Rig which inherits from TS2000) send every CAT command and reply
terminated with ';' (FA;, RM;, FR0; -- see KenwoodTK90RigConstant), yet their
onReceiveData split incoming bytes on '\r', which these rigs never send. So
s.contains("\r") was never true: every reply was appended to the buffer until it
passed 1000 chars and got wiped, and no reply was ever parsed.

Consequences:
- Frequency read-back was dead (FA replies never applied).
- SWR/ALC over-power protection was dead -- the safety feature that halts TX on
  high SWR never received a reading. This is why the TX-500's SWR fix (#599/PR
  #626) never actually worked: PR #626 corrected the meter *layout* but the reply
  reached parsing through the inherited '\r' split and was dropped first. The
  reporter's own evidence in #599 (reply "RM10023;") and #589 ("control works
  normally except swr protection is not working at all", CAT chip goes red within
  seconds -- the signature of reads never parsing) confirm the ';' framing.

This was a half-migration: the command constants were switched to ';'-terminated
but onReceiveData was left splitting on '\r'. The same-repo Kenwood-family rigs
TrUSDXRig (TS-480 emulation) and Flex6000Rig already split on ';'.

Fix: add a multi-terminator overload CatLineSplitter.split(buffered, incoming,
String terminators) -- any character in the set ends a command (the existing char
overload delegates to it). The three Kenwood rigs adopt split(buffer, s, ";\r")
and extract processCommand(String), draining every complete command in a read.
Accepting both ';' and '\r' fixes the confirmed-broken ';' stream while being
unable to regress any transport that might interleave a '\r' (Kenwood data never
contains ';'; an empty span between ';' and '\r' becomes an empty frame that
Yaesu3Command.getCommand treats as a no-op). Draining all frames per read also
fixes the coalesced RM SWR+ALC reply drop, matching the CatLineSplitter adoption
already done for the Yaesu/Elecraft rigs. DiscoveryTX500Rig is fixed via
inheritance.

Tests: 6 new CatLineSplitterTest cases covering the ';'-framed Kenwood reply, the
coalesced SWR+ALC meter poll, freq+meter coalescing, cross-read reassembly, the
stray-'\r' tolerance, and char/String overload agreement (19 total, all green).
Full rig unit-test package green; main sources compile.

Refs #599, #589.

Co-authored-by: Optio Agent <optio-agent@noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants