Skip to content

fix(radio): correct swapped SBUS Trainer / SBUS Trn Inv. labels - #7616

Closed
BelixRogner wants to merge 1 commit into
EdgeTX:mainfrom
BelixRogner:fix/sbus-trainer-mode-labels
Closed

fix(radio): correct swapped SBUS Trainer / SBUS Trn Inv. labels#7616
BelixRogner wants to merge 1 commit into
EdgeTX:mainfrom
BelixRogner:fix/sbus-trainer-mode-labels

Conversation

@BelixRogner

Copy link
Copy Markdown

Summary of changes:

The SBUS Trainer and SBUS Trn Inv. entries in SYS → Hardware → Serial Port are swapped:
picking "SBUS Trainer" actually selects UART_MODE_SBUS_TRAINER_INV (inverted polarity), and
picking "SBUS Trn Inv." selects UART_MODE_SBUS_TRAINER (normal polarity).

Why

The mode enum (radio/src/dataconstants.h) is:

UART_MODE_TELEMETRY,          // 2
UART_MODE_SBUS_TRAINER,       // 3  -> normal polarity
UART_MODE_SBUS_TRAINER_INV,   // 4  -> ETX_Pol_Inverted

The polarity semantics are unambiguous in serial.cpp: UART_MODE_SBUS_TRAINER leaves
params.polarity at the default, and UART_MODE_SBUS_TRAINER_INV sets
params.polarity = ETX_Pol_Inverted.

The label array is built with SA11(s)s##_1, s##_2, … s##_11
(radio/src/translations/translation_def.h), so array index 0 is TR_AUX_SERIAL_MODES_1 and:

array index label macro current label actual mode
3 TR_AUX_SERIAL_MODES_4 "SBUS Trn Inv." UART_MODE_SBUS_TRAINER (normal)
4 TR_AUX_SERIAL_MODES_5 "SBUS Trainer" UART_MODE_SBUS_TRAINER_INV (inverted)

Choice(box, rect_t{}, STR_AUX_SERIAL_MODES, 0, UART_MODE_MAX, …) in
gui/colorlcd/radio/hw_serial.cpp indexes the array directly by enum value, so the mislabelling
reaches the screen. The same ordering is present in all 19 i18n/*.h files, so this is systematic
rather than one bad translation.

Corroboration: Companion maps the mode to its label by enum name rather than by array position
(companion/src/firmwares/generalsettings.cpp), and returns "SBUS Trainer" for
AUX_SERIAL_SBUS_TRAINER — i.e. Companion and the radio currently disagree about what mode 3 is
called.

Impact

Anyone configuring an SBUS trainer input picks the opposite polarity to the one they intended,
which presents as "trainer just doesn't work" with no diagnostic. It may be a contributing factor
in the confusion in #6384, where the discussion turned on which polarity AUX1 actually needs.

Note also that on STM32F4 targets UART_MODE_SBUS_TRAINER_INV is hidden
(gui_common.cpp), so F4 users are currently offered a single SBUS option labelled
"SBUS Trn Inv." which is in fact the normal-polarity mode.

The fix

Swap the two label values in all 19 i18n/*.h files. Deliberately not reordering the enum:
g_eeGeneral.serialPort persists these as raw 4-bit values, so changing the enum would silently
repoint existing radio configurations at a different mode.

No string is made longer by the swap, so there is no new truncation risk on small screens; the
existing TR() short/long variants travel with their strings.

Testing

  • tools/commit-tests.sh for tx15 (colour) and t12max (monochrome) — builds clean, tests pass.
  • Verified on a RadioMaster TX15 Max: the entry that configures normal-polarity SBUS trainer now
    reads "SBUS Trainer" rather than "SBUS Trainer Inv.".

Out of scope

Companion's AuxSerialMode enum has no SBUS_TRAINER_INV entry at all, so its values diverge
from the radio's from index 4 onward. YAML round-trips are name-based (uartModeLut) and so are
not corrupted by this, but Companion cannot represent the inverted mode. Left for a separate PR.

The two SBUS trainer entries in SYS -> Hardware -> Serial Port are
swapped: selecting "SBUS Trainer" configures UART_MODE_SBUS_TRAINER_INV
(inverted polarity) and selecting "SBUS Trn Inv." configures
UART_MODE_SBUS_TRAINER (normal polarity).

SA11() expands to s##_1 ... s##_11, so array index 0 is
TR_AUX_SERIAL_MODES_1. That puts "SBUS Trn Inv." at index 3, which is
UART_MODE_SBUS_TRAINER, and "SBUS Trainer" at index 4, which is
UART_MODE_SBUS_TRAINER_INV. The Choice widget indexes the array
directly by enum value, so the mislabelling reaches the screen. All 19
language files share the same ordering.

Swap the two label values rather than reordering the enum:
g_eeGeneral.serialPort persists the mode as a raw 4-bit value, so
changing the enum would silently repoint existing configurations at a
different mode. No string grows, so there is no new truncation risk on
small screens.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011yNWsmBtBtjmHtNSJjuUeA
@pfeerick

pfeerick commented Aug 4, 2026

Copy link
Copy Markdown
Member

Note also that on STM32F4 targets UART_MODE_SBUS_TRAINER_INV is hidden
(gui_common.cpp), so F4 users are currently offered a single SBUS option labelled
"SBUS Trn Inv." which is in fact the normal-polarity mode.

I'm not sure this is actually correct, as IIRC SBUS is a "inverted" signal by default on the handset electronics... thus the weird NORMAL to INV semantics...

Regardless, @3djc is more conversant with this... if radio and companion disagree on the same setting, this needs to be fixed regardless, but which side is correct as far as the end user is concerned?

@BelixRogner

Copy link
Copy Markdown
Author

Good question — I went back through the history, and it turns out not to be a polarity-semantics issue at all. It's an off-by-one introduced when the second mode was added.

Before #7133 the labels were correct:

#define TR_AUX_SERIAL_MODES_4          "SBUS Trainer"   // index 3 = UART_MODE_SBUS_TRAINER
#define TR_AUX_SERIAL_MODES_5          "Lua"            // index 4 = UART_MODE_LUA

b3d36eb (#7133, "non inverted SBUS trainer support on serial inputs on H5/H7") then inserted the new entry at different positions in the two lists:

  • enumUART_MODE_SBUS_TRAINER_INV was added after UART_MODE_SBUS_TRAINER, so the new mode is index 4:
   UART_MODE_SBUS_TRAINER,
+  UART_MODE_SBUS_TRAINER_INV,
   UART_MODE_LUA,
  • labels"SBUS Trn Inv." was inserted at _4, so the new label landed at index 3:
-#define TR_AUX_SERIAL_MODES_4          "SBUS Trainer"
-#define TR_AUX_SERIAL_MODES_5          "Lua"
+#define TR_AUX_SERIAL_MODES_4          TR("SBUS Trn Inv.",TR("SBUS Trn Inv.","SBUS Trainer Inv."))
+#define TR_AUX_SERIAL_MODES_5          "SBUS Trainer"
+#define TR_AUX_SERIAL_MODES_6          "LUA"

Everything from LUA onward shifted consistently in both lists, which is why only these two entries ended up mismatched and nothing else broke.

SA11() expands _1 … _11 in order so array index 0 is _1, and Choice(box, rect_t{}, STR_AUX_SERIAL_MODES, 0, UART_MODE_MAX, …) in hw_serial.cpp indexes the array directly by enum value. So index 3 currently renders as "SBUS Trn Inv." while actually configuring the non-inverted mode — serialSetupPort() only sets params.polarity = ETX_Pol_Inverted for UART_MODE_SBUS_TRAINER_INV.

That also explains the disagreement with Companion: Companion wasn't touched by #7133, so it still reflects the original mapping (AUX_SERIAL_SBUS_TRAINER"SBUS Trainer"). To your question of which side is right for the end user — the radio is the one that regressed, and this PR restores what the labels said before #7133.

Verified on a TX15 Max.

Happy to defer to @3djc if the intent in #7133 was actually to relabel the pre-existing mode as well as add the new one — in that case the fix would instead be to swap the enum, though that would need a storage conversion since g_eeGeneral.serialPort persists the raw value.

@3djc

3djc commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

I will do my best to have a look before the end of the week

@pfeerick

pfeerick commented Aug 5, 2026

Copy link
Copy Markdown
Member

Possibly the 3.0 version of #7142 wasn't done?

@3djc

3djc commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

The analysis is wrong. Tested a TX15 max with those settings:

Capture d’écran 2026-08-06 à 11 19 10 Capture d’écran 2026-08-06 à 11 19 17 Capture d’écran 2026-08-06 à 11 19 24

And it works perfectly. My guess is there has been confusion in the understanding of:
UART_MODE_SBUS_TRAINER_INV, // 4 -> ETX_Pol_Inverted

In H7 terms, this means:

  • for end users: normal SBUS
  • the INV is for MCU side inversion vs a standard uart signal, since normal SBUS is inverted serial

So for H7 radio, all is fine. But investigating the issue, two side issues appeared:

  • F4 is essentially inverted, since there are static inverters fitted
  • H5 should work with that logic, but don't because the serial port driver only handles inversion for H7 and H7RS

For radio side, I think this PR is not correct, I will issue one fixing the issues above. @pfeerick could you test the Companion side ?

@BelixRogner

Copy link
Copy Markdown
Author

You're right, thanks for testing it properly.

I was reasoning from internal consistency between the enum name and the label array, and never accounted for the physical layer — that normal SBUS is inverted serial, so MCU-side inversion is exactly what an end user with a standard receiver needs on H7. Under that reading the labels are describing the signal the user supplies rather than the polarity register, and they're correct.

The #7133 relabel was deliberate, not an off-by-one. My history argument showed the enum and label insertions landed at different positions, which is true, but that doesn't establish the pre-#7133 labelling was still correct once a second mode existed — and it isn't.

@pfeerick called this in the first reply and I talked past it. Apologies for the noise.

Closing. Glad it at least surfaced the F4 static-inverter labelling and the H5 driver inversion gap — happy to test whatever you put up for those.

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.

3 participants