Skip to content

fix: stop moduleData antennaMode aliasing subType on boards without an external antenna - #7735

Merged
pfeerick merged 3 commits into
mainfrom
fix/moduledata-antennamode-layout
Sep 1, 2026
Merged

pfeerick merged 3 commits into
mainfrom
fix/moduledata-antennamode-layout

Conversation

@pfeerick

@pfeerick pfeerick commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

Fixes #7733.

Fixes three defects introduced by #7113, which made the ModuleData bit layout conditional on EXTERNAL_ANTENNA while the generated YAML descriptor tables are shared between boards that differ on that flag.

1. Phantom antennaMode aliasing subType

tx16s, t16, t18, v16 include the x10 table; t8, t12, tlite, lr3pro, commando8 include the xlite one. Those boards describe an antennaMode field they do not compile, overlaying the top two bits of their live subType. yaml_bits.cpp is LSB-first, so antennaMode == subType >> 2.

A reported TX16S file shows it exactly: subType: 6,3 → 3 = 0b0011 → top two bits 0 → emitted as antennaMode: MODE_PER_MODEL.

Companion hides the UI but round-trips the value, and writes antennaMode after subType, so the radio applies it second and overwrites subType. Changing an MPM sub-protocol in Companion could silently change it again on load.

2. subType narrowed 4 → 2 bits

On x10, x10express, x12s, xlite, xlites, v12. MPM sub-protocols reach 7 (DSM2, AFHDS2A, CABELL, FRSKY_R9, MT99XX) and up to 14 via telemetry, so anything above 3 truncated.

3. Companion could not open affected files

Already fixed on main by #7114; the 2.12.x fix is in #7736.

Approach

antennaMode becomes unconditional, so every board compiles the layout its table describes. The bits come from type (18 of 64 values used) because check_yaml_funcs() pins the header to 4 bytes via offsetof(ModuleData, ppm) == 4 and check_size<ModuleData, 29>(), and it must precede CUST_ATTR(subType) so that node stays at bit offset 8 where r_/w_modSubtype resolve the struct base. subType returns to 4 bits.

All 25 generated tables now share an identical struct_ModuleData; the entire diff across them is the type width plus the moved field.

Companion additionally gates encode, decode and the legacy pxx migration on HasExternalAntenna, which handles files already written by 2.12.3.

Verification

  • gtests-radio 126/126 on x10 (EXTERNAL_ANTENNA on) and tx16s (off)
  • gtests-companion 14/14, including two new tests, each confirmed to fail when its fix is reverted
  • Pre-fix reproduction gave the reported error verbatim: TypedBadConversion<int>, bad conversion, column 20
  • Regenerated tables verified free of drift outside struct_ModuleData

This also explains why the issue only shows on models modified under 2.12.3: an untouched 2.12.2 file has no antennaMode key, and the radio only writes the phantom one when it re-saves the model.

pfeerick and others added 3 commits August 31, 2026 11:15
…ternal antenna

#7113 made the ModuleData bit layout conditional on EXTERNAL_ANTENNA, taking
antennaMode's two bits out of subType. The generated YAML descriptors are shared
between boards that differ on that flag - tx16s, t16, t18, v16 include the x10
table, and t8, t12, tlite, lr3pro, commando8 include the xlite one - so those
boards describe an antennaMode field they do not compile, overlaying the top two
bits of their live subType. They emit a phantom antennaMode derived from subType,
and writing one back corrupts it.

The same change also narrowed subType from 4 bits to 2 on x10, x10express, x12s,
xlite, xlites and v12, where MPM sub-protocols above 3 then truncate.

Make antennaMode unconditional so every board compiles the layout its table
describes, borrowing the bits from type (18 of 64 values used) since
check_yaml_funcs() pins the header to 4 bytes, and restore subType to 4 bits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ut one

Firmware released before antennaMode was made unconditional emitted the field on
boards with no external antenna, where it aliased the top two bits of subType.
Companion hides the UI for those boards but still round-tripped the value, and
writes antennaMode after subType, so firmware applied it second and it overwrote
subType's high bits - changing an MPM sub-protocol in Companion could silently
change it again on load.

Gate encode, decode and the legacy pxx migration on HasExternalAntenna, matching
the predicate the model setup panel already uses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Guards the two Companion-side failures: a module carrying a string antennaMode
must decode at all, and the key must not be written back for a board with no
external antenna, where the radio parses it over subType's top bits.

The fixture already selects tx16s, which is one of the affected boards. The
decode case works on a ModuleData node rather than a whole model - a throw out
of the ModelData decode is not catchable here and aborts the binary instead of
failing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pfeerick pfeerick added this to the 3.0 milestone Aug 31, 2026
@pfeerick pfeerick added companion (cpn) Related to the companion software bug/regression ↩️ A new version of EdgeTX broke something firmware (fw) General radio firmware issue, not colorlcd or B&W specific labels Aug 31, 2026
@pfeerick
pfeerick marked this pull request as ready for review September 1, 2026 02:05
@pfeerick
pfeerick merged commit 73390c7 into main Sep 1, 2026
64 checks passed
@pfeerick
pfeerick deleted the fix/moduledata-antennamode-layout branch September 1, 2026 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug/regression ↩️ A new version of EdgeTX broke something companion (cpn) Related to the companion software firmware (fw) General radio firmware issue, not colorlcd or B&W specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Existing models from firmware 2.12.2 that are modified in radio firmware 2.12.3 cannot be imported into Companion 2.12.3

1 participant