Skip to content

radiotap TX: honour HT LDPC/STBC known bits on Jaguar2/3#291

Merged
josephnef merged 2 commits into
OpenIPC:masterfrom
gilankpam:radiotap-tx-ht-ldpc-stbc
Jul 15, 2026
Merged

radiotap TX: honour HT LDPC/STBC known bits on Jaguar2/3#291
josephnef merged 2 commits into
OpenIPC:masterfrom
gilankpam:radiotap-tx-ht-ldpc-stbc

Conversation

@gilankpam

Copy link
Copy Markdown
Contributor

Summary

build_tx_block on Jaguar2/3 read only bw/sgi/mcs from the HT MCS radiotap field and dropped the FEC/STBC known bits, so an HT frame requesting LDPC or STBC aired as plain BCC / no-STBC — only VHT frames were honoured. This adds a shared decode helper and wires it into both the Jaguar2 and Jaguar3 HT paths so HT injects apply LDPC/STBC too.

The descriptor fill and STBC-cap guard were already correct: DATA_LDPC dword5[7], DATA_STBC dword5[9:8] & 0x3 — byte-identical to the vendor driver (rtl88x2eu-20230815 hal/rtl8822e/usb/rtl8822eu_xmit.c, SET_TX_DESC_DATA_STBC_8822E(.., pattrib->stbc & 3)).

Changes

  • src/RadiotapTxFlags.hdecode_radiotap_mcs_field(): one shared reading of the HT MCS known/flag/index bytes (bw/sgi/mcs + LDPC/STBC).
  • Jaguar2 + Jaguar3 build_tx_block IEEE80211_RADIOTAP_MCS cases now use it; the STBC-cap guard below still clamps to what the chip can do.

Testing

  • New host selftest tests/radiotap_txflags_selftest.cpp covers the decode. ctest 21/21 green.
  • Bench-verified on 8822E hardware via rxdemo: HT MCS0 injects decoded stbc=0 ldpc=0 before this change and stbc=1 ldpc=1 after; live video stayed clean at MCS5 with STBC+LDPC active.

🤖 Generated with Claude Code

J2/J3 send_packet ignored the MCS field's FEC/STBC known bits, so HT frames
tagged LDPC/STBC (e.g. mabur's MAX_RANGE robustness flags) silently flew as
plain BCC SISO; only the VHT case honoured them. J1 already carried the fix.
Shared decode in RadiotapTxFlags.h + headless builder/parser contract test.

@josephnef josephnef left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving — the fix is correct and I verified it end-to-end.

Correctness: the shared decode is bit-exact against the radiotap spec and behaviorally identical to Jaguar1's proven copy; ldpc/stbc init to 0, the SetTxMode default still applies only to rate-less frames after the walk, both STBC-cap guards sit downstream, and MCS+VHT dual-field frames stay correct (VHT iterates after MCS and only ever sets). The old J2/J3 behavior of not gating sgi/bw on their known bits is preserved, so no semantic regressions.

Impact check: the encoding matrix missed this because txdemo's rate-less beacon rides the SetTxMode default path (already correct). The real victims are streamtx/svctx/tdma/timesync/duplex, which embed the mode into per-frame radiotap via build_stream_radiotap — every HT /LDPC stream link on Jaguar2/3 silently aired BCC.

On-air A/B (streamtx MCS1/LDPC/STBC → 8812AU rx.txhit decode, master vs PR build):

arm frames decoded
8812EU (J3), master 12 ldpc=0 stbc=0 all
8812EU (J3), PR 10 ldpc=1 stbc=1 all
8812BU (J2), master 99 ldpc=0 stbc=0 all
8812BU (J2), PR 82 ldpc=1 stbc=1 all

Unanimous truth table on both generations; rate stays MCS1 throughout. ctest 21/21.

Nits (will handle as follow-ups on master, no action needed here): RadiotapTxFlags.h is included twice in RtlJaguar3Device.cpp; the decoder could use the named IEEE80211_RADIOTAP_MCS_* constants; and Jaguar1 can adopt the shared decoder so the copies truly can't diverge.

@josephnef josephnef merged commit c25b599 into OpenIPC:master Jul 15, 2026
15 checks passed
josephnef added a commit that referenced this pull request Jul 15, 2026
…#292)

## Summary

Follow-ups from the #291 review, in one pass:

- **Jaguar1 adopts `decode_radiotap_mcs_field()`** — the last private
copy of the HT MCS known/flag reading is gone, so the three generations'
`send_packet` parsers genuinely can't diverge. Behavior-identical:
`bwidth` starts at 20 MHz, so J1's explicit BW_20/20L/20U branch was a
no-op, and its ldpc/stbc/sgi semantics already matched the shared
decode.
- **Named constants** — the decoder spells its bit tests with
`IEEE80211_RADIOTAP_MCS_HAVE_FEC`/`FEC_LDPC`/`HAVE_STBC`/`STBC_MASK`/`STBC_SHIFT`/`SGI`
instead of raw masks and shifts.
- **Duplicate include dropped** — `RadiotapTxFlags.h` was included twice
in `RtlJaguar3Device.cpp`.
- **Selftest**: new raw 3-byte MCS field case (BW code 20U, STBC stream
count 2, LDPC, no SGI) pinning the decoder's bit positions independently
of what `build_stream_radiotap` can emit — a direct guard on the
constants refactor.

## Testing

- `ctest` 21/21 green.
- Bench-verified on air (streamtx `MCS1/LDPC/STBC` → `rx.txhit` decode):
- 8812AU (J1 — the swapped path) → 8822B RX, ch6: **107/107** frames
`ldpc=1 stbc=1`, rate MCS1.
- 8812EU (J3 regression on the refactored decoder) → 8812AU RX, ch36:
**19/19** `ldpc=1 stbc=1`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <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