Repository navigation
fix: stop moduleData antennaMode aliasing subType on boards without an external antenna - #7735
Merged
Merged
Conversation
…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
marked this pull request as ready for review
September 1, 2026 02:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7733.
Fixes three defects introduced by #7113, which made the
ModuleDatabit layout conditional onEXTERNAL_ANTENNAwhile the generated YAML descriptor tables are shared between boards that differ on that flag.1. Phantom
antennaModealiasingsubTypetx16s,t16,t18,v16include the x10 table;t8,t12,tlite,lr3pro,commando8include the xlite one. Those boards describe anantennaModefield they do not compile, overlaying the top two bits of their livesubType.yaml_bits.cppis LSB-first, soantennaMode == subType >> 2.A reported TX16S file shows it exactly:
subType: 6,3→3 = 0b0011→ top two bits0→ emitted asantennaMode: MODE_PER_MODEL.Companion hides the UI but round-trips the value, and writes
antennaModeaftersubType, so the radio applies it second and overwritessubType. Changing an MPM sub-protocol in Companion could silently change it again on load.2.
subTypenarrowed 4 → 2 bitsOn
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
antennaModebecomes unconditional, so every board compiles the layout its table describes. The bits come fromtype(18 of 64 values used) becausecheck_yaml_funcs()pins the header to 4 bytes viaoffsetof(ModuleData, ppm) == 4andcheck_size<ModuleData, 29>(), and it must precedeCUST_ATTR(subType)so that node stays at bit offset 8 wherer_/w_modSubtyperesolve the struct base.subTypereturns to 4 bits.All 25 generated tables now share an identical
struct_ModuleData; the entire diff across them is thetypewidth 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-radio126/126 on x10 (EXTERNAL_ANTENNAon) and tx16s (off)gtests-companion14/14, including two new tests, each confirmed to fail when its fix is revertedTypedBadConversion<int>,bad conversion, column 20struct_ModuleDataThis also explains why the issue only shows on models modified under 2.12.3: an untouched 2.12.2 file has no
antennaModekey, and the radio only writes the phantom one when it re-saves the model.