Skip to content

tx: programmatic runtime TX-mode API; drop DEVOURER_TX_HT_MCS gate#111

Merged
josephnef merged 1 commit into
masterfrom
feat/tx-mode-api
Jun 27, 2026
Merged

tx: programmatic runtime TX-mode API; drop DEVOURER_TX_HT_MCS gate#111
josephnef merged 1 commit into
masterfrom
feat/tx-mode-api

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

Problem

RtlJaguarDevice::send_packet only wired a radiotap HT-MCS index into the on-air rate when DEVOURER_TX_HT_MCS was set in the environment. Without it, a correctly-formed HT radiotap silently fell back to the MGN_1M default (1 Mbps CCK, clamped to 6 Mbps legacy at 5 GHz). Two things wrong: a library deciding TX behaviour from a CLI env var, and a valid radiotap being ignored by default. The demo compounded it by hand-patching radiotap bytes through a swarm of per-knob env vars.

Change

  • Radiotap is authoritative per-packet — the HT-MCS index is honoured unconditionally (the DEVOURER_TX_HT_MCS gate is removed).
  • New runtime APIdevourer::TxMode (src/TxMode.h) + RtlJaguarDevice::SetTxMode() / ClearTxMode(). The mode is a configurable default, applied only when a frame's radiotap carries no rate (replacing the hardcoded MGN_1M); per-packet radiotap always wins. Mirrors the existing SetTxPowerOverride pattern (pure state, no USB I/O).
  • Consolidated CLI — the per-knob DEVOURER_TX_MCS/_VHT/_VHT_MCS/_VHT_NSS/_LDPC/_STBC/_BW env vars collapse into one string:
    DEVOURER_TX_RATE=<rate>[/<bw>][/SGI][/LDPC][/STBC]
      <rate> = 6M..54M | MCS0..MCS31 | VHT1SS_MCS0..VHT4SS_MCS9
      <bw>   = 20|40|80|160        (default 20)
    
    parsed by parse_tx_mode_env() into a TxMode. e.g. MCS7/40/SGI, VHT2SS_MCS3/80/LDPC, 6M.
  • StreamRateCfgdevourer::TxMode; WiFiDriverTxDemo sends a rate-less beacon and drives the mode via SetTxMode. Stream demos migrated.
  • tests/regress.py, tests/bench_onair.py, tests/thermal_gain_sweep.py and the docs migrated to DEVOURER_TX_RATE; corrected the precoder note that claimed send_packet never reads the HT MCS index.

DEVOURER_TX_PAYLOAD_BYTES and DEVOURER_TX_PWR_* are unchanged (size / power, not mode).

Verification

  • cmake --build build -j clean across all targets; ctest passes (stream_stdin_binary).
  • On air (8812 TX → 8814 monitor, ch6, no DEVOURER_TX_HT_MCS):
    • DEVOURER_TX_RATE=MCS7 → witness decodes 11n … 65.0 Mb/s MCS 7 20 MHz.
    • unset → witness decodes 6.0 Mb/s … 11g (the TxMode default, not 1M CCK).

🤖 Generated with Claude Code

send_packet only honoured a radiotap HT-MCS index when DEVOURER_TX_HT_MCS was
set in the environment, so a valid HT radiotap silently fell back to the
MGN_1M (1M CCK / 6M-legacy-at-5G) default. A library deciding TX behaviour from
a CLI env var, and an ignored-by-default radiotap, were both wrong.

- Radiotap is now authoritative per-packet: the HT-MCS index is honoured
  unconditionally (gate removed).
- New devourer::TxMode struct (src/TxMode.h) + RtlJaguarDevice::SetTxMode /
  ClearTxMode: a runtime default applied when a frame's radiotap carries no
  rate, replacing the hardcoded MGN_1M. Mirrors the SetTxPowerOverride pattern.
- Consolidate the per-knob DEVOURER_TX_MCS/_VHT/_VHT_MCS/_VHT_NSS/_LDPC/_STBC/_BW
  env vars into one DEVOURER_TX_RATE string (<rate>[/<bw>][/SGI][/LDPC][/STBC]),
  parsed by RadiotapBuilder::parse_tx_mode_env into a TxMode. StreamRateCfg ->
  TxMode; the txdemo sends a rate-less beacon and drives the mode via SetTxMode.
- Migrate regress.py / bench_onair.py / thermal_gain_sweep.py and the docs to
  DEVOURER_TX_RATE; correct the precoder note about send_packet ignoring HT MCS.

Verified: build + ctest green; on air (8812 -> 8814 monitor, ch6) MCS7 decodes
as 11n 65 Mb/s MCS 7 and an unset rate as 6 Mb/s 11g — both with no
DEVOURER_TX_HT_MCS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef josephnef merged commit 5f099ee into master Jun 27, 2026
6 checks passed
@josephnef josephnef deleted the feat/tx-mode-api branch June 27, 2026 07:11
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.

1 participant