From e65f59dab583283a1ff6ca64f5e7d95a3d7cb963 Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Thu, 25 Jun 2026 17:36:23 +0300 Subject: [PATCH 1/2] demo: env-gated 40 MHz RX (DEVOURER_BW) + PHY flags on corrupt-any dump DEVOURER_BW=40 selects a 40 MHz monitor channel (CHANNEL_WIDTH_40, with DEVOURER_CHOFFSET for the secondary half) so the RX can receive HT40 frames; needed to validate the gr-ieee802-11 fork's HT40 transmit over the air. Also surface bw/stbc/ldpc/sgi on the DUMP_ALL line (matching ) so a frame the chip decodes-but-fails-CRC can be inspected for its decoded PHY params. Co-Authored-By: Claude Opus 4.8 --- demo/main.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/demo/main.cpp b/demo/main.cpp index c381034..6caa345 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -166,11 +166,13 @@ static void packetProcessor(const Packet &packet) { static const bool dump_all = std::getenv("DEVOURER_RX_DUMP_ALL") != nullptr; if (dump_all) { printf("len=%zu crc_err=%u icv_err=%u " - "rate=%u rssi=%d,%d evm=%d,%d snr=%d,%d\n", + "rate=%u bw=%u stbc=%u ldpc=%u sgi=%u rssi=%d,%d evm=%d,%d snr=%d,%d\n", packet.Data.size(), packet.RxAtrib.crc_err ? 1u : 0u, packet.RxAtrib.icv_err ? 1u : 0u, packet.RxAtrib.data_rate, + packet.RxAtrib.bw, packet.RxAtrib.stbc, + packet.RxAtrib.ldpc, packet.RxAtrib.sgi, packet.RxAtrib.rssi[0], packet.RxAtrib.rssi[1], packet.RxAtrib.evm[0], packet.RxAtrib.evm[1], packet.RxAtrib.snr[0], packet.RxAtrib.snr[1]); @@ -444,10 +446,24 @@ int main() { channel = std::atoi(ch_env); logger->info("DEVOURER_CHANNEL set — tuning to channel {}", channel); } + /* RX bandwidth: 20 MHz by default. DEVOURER_BW=40 selects a 40 MHz monitor + * channel (for receiving HT40 frames); DEVOURER_CHOFFSET picks the secondary + * half (1 = secondary above the primary, 2 = secondary below). */ + ChannelWidth_t width = CHANNEL_WIDTH_20; + uint8_t ch_offset = 0; + if (const char *bw_env = std::getenv("DEVOURER_BW")) { + if (std::atoi(bw_env) == 40) { + width = CHANNEL_WIDTH_40; + ch_offset = 1; // default: secondary channel above the primary + if (const char *off_env = std::getenv("DEVOURER_CHOFFSET")) + ch_offset = static_cast(std::atoi(off_env)); + logger->info("DEVOURER_BW=40 — 40 MHz RX, channel-offset {}", ch_offset); + } + } rtlDevice->Init(packetProcessor, SelectedChannel{ .Channel = static_cast(channel), - .ChannelOffset = 0, - .ChannelWidth = CHANNEL_WIDTH_20, + .ChannelOffset = ch_offset, + .ChannelWidth = width, }); rc = libusb_release_interface(dev_handle, 0); From 4c84908dd0b42fe9d978c12dc887f3a286f21e7a Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Thu, 25 Jun 2026 18:33:37 +0300 Subject: [PATCH 2/2] send_packet: honour STBC + FEC=LDPC on the HT radiotap path The HT-MCS radiotap branch read bandwidth and short-GI but never STBC or FEC, so an HT frame tagged STBC/LDPC in radiotap silently transmitted as BCC SISO -- only the VHT branch honoured them. Read STBC (MCS known bit5 / flags bits5-6) and LDPC (known bit4 / flags bit4) here too, so WiFiDriverTxDemo with DEVOURER_TX_HT_MCS=1 + DEVOURER_TX_STBC=1 emits a real HT STBC / HT LDPC frame. Verified at the TX descriptor: fixed rate:128 (MGN_MCS0) stbc:1. Intended as a chip reference for the gr-ieee802-11 fork's modern TX. Co-Authored-By: Claude Opus 4.8 --- src/RtlJaguarDevice.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/RtlJaguarDevice.cpp b/src/RtlJaguarDevice.cpp index 9f729d8..f2bb803 100644 --- a/src/RtlJaguarDevice.cpp +++ b/src/RtlJaguarDevice.cpp @@ -97,6 +97,19 @@ bool RtlJaguarDevice::send_packet(const uint8_t *packet, size_t length) { sgi = 0; } + /* STBC (radiotap MCS known bit5 / flags bits5-6) and FEC=LDPC (known bit4 / + * flags bit4). The HT branch previously read neither, so an HT frame tagged + * STBC/LDPC in radiotap silently transmitted as BCC SISO -- only the VHT + * branch honoured them. Reading them here lets WiFiDriverTxDemo emit a real + * HT STBC / HT LDPC frame (needed as a chip reference for the gr-ieee802-11 + * fork's modern-format TX). */ + if (mcs_known & 0x20) { + stbc = (mcs_flags >> 5) & 0x3; + } + if ((mcs_known & 0x10) && (mcs_flags & 0x10)) { + ldpc = 1; + } + /* DEVOURER_TX_HT_MCS=1: honour the HT MCS index from radiotap byte 2 * and set fixed_rate accordingly. Without this knob the historic * behaviour kicks in — fixed_rate stays at the MGN_1M default and the