Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ if(DEVOURER_MT7612U)
src/mt7612u/usb.cpp
src/mt7612u/Mt7612uRadio.cpp src/mt7612u/Mt7612uRadio.h
src/mt7612u/Mt7612uMapping.h
src/mt7612u/Mt7612uRxQueue.h
src/mt7612u/internal.h
src/mt7612u/regs.h
src/mt7612u/initvals.h
Expand Down Expand Up @@ -893,6 +894,25 @@ target_include_directories(Mt7612uMappingSelftest PRIVATE

add_test(NAME mt7612u_mapping COMMAND Mt7612uMappingSelftest)

# Headless guard for the RX hand-off queue, the one piece of backend BEHAVIOUR
# (as opposed to descriptor lookups) that can be exercised without a radio. Its
# two load-bearing properties - a full ring drops the newest frame and counts
# it, and a popped slot outlives the lock so user code can run unlocked - are
# both invisible on a healthy bench and both turn into a wedge, a reorder or a
# use-after-free when broken. Like the mapping cell it compiles regardless of
# DEVOURER_MT7612U: it is header-only and needs no libusb.
add_executable(Mt7612uRxQueueSelftest
tests/mt7612u_rx_queue_selftest.cpp
)
# The first selftest in the tree to use <thread> directly. It links today
# without this because libdevourer already pulls the thread runtime in, and on
# glibc >= 2.34 pthread is part of libc anyway — but that is two accidents, not
# a dependency, and this costs nothing.
find_package(Threads REQUIRED)
target_link_libraries(Mt7612uRxQueueSelftest PRIVATE devourer Threads::Threads)

add_test(NAME mt7612u_rx_queue COMMAND Mt7612uRxQueueSelftest)

# Headless guard for the TX quiesce seam (ITransport::quiesce_tx via
# RtlAdapter): the explicit "stop TX and wait it out" call every device makes
# before anything is released. UsbTransport's cancel/drain is validated on
Expand Down Expand Up @@ -1382,6 +1402,28 @@ if(Python3_Interpreter_FOUND)
COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tests/nitroqam_waterfall.py --self-test
)

# The two MediaTek artifacts that are transcriptions of reference/mt76 —
# the USB-id gate table and the generated MAC initvals. Both were
# hand-checked once and then trusted; the id table was wrong the first time
# (11 of 16 entries, from the host kernel tree rather than the pinned one)
# and nothing caught it. Both SKIP (77) when the submodule is absent, which
# is the case in CI: `actions/checkout` here does not fetch submodules, so
# these are bench cells, not CI cells. Anyone who can regenerate initvals.h
# can run them.
add_test(
NAME mt7612u_usb_ids_vs_mt76
COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tests/mt7612u_usb_ids_vs_mt76.py
)
set_tests_properties(mt7612u_usb_ids_vs_mt76 PROPERTIES SKIP_RETURN_CODE 77)

add_test(
NAME mt7612u_initvals_generated
COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/extract_mt7612u_tables.py --check
)
set_tests_properties(mt7612u_initvals_generated PROPERTIES SKIP_RETURN_CODE 77)
endif()

# --- selftest aggregate ----------------------------------------------------
Expand Down
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,19 @@ Bandwidth cells are devourer's measured on-air TX throughput (Mbps, HT MCS7,
| **RTL8832BU** (11ax) | 2T2R | — | — | — | — | Wi-Fi-only SKU of the 8852B die; rides the 8852BU code path. Not benchmarked. 5/10 MHz capable; HE ER SU + DCM extended range |
| **RTL8832CU** (11ax) | 2T2R + BT | 40 | 33 | 32 | 32 | TP-Link Archer TX50UH (`35bc:0101`); Wi-Fi 6E tri-band (2.4/5/6 GHz). 5/10 and 160 MHz capable; HE ER SU + DCM extended range. Host-push injection over USB 2.0 (~50% duty ceiling); [6G TX+RX validated](tests/kestrel_8832cu_6g_txrx.sh) |
| **RTL8852CU** (11ax) | 2T2R + BT | — | — | — | — | "8852" branding of the same 8852C die; rides the 8832CU code path. Not benchmarked. 5/10 and 160 MHz capable; HE ER SU + DCM extended range |
| **MT7612U** (MediaTek) | 2T2R | ‖ | ‖ | — | — | Alfa AWUS036ACM / Aukey USBAC1200 (`0e8d:7612`) and 15 OEM ids; the one non-Realtek backend, opt-in with `-DDEVOURER_MT7612U=ON`. 20/40/80 MHz; no 5/10 MHz, no fast retune. [Measured record](docs/mt7612u.md) |

`†` = works on-air but the reading varies run-to-run (bracketed = best clean
reading).

`‖` = **measured, but not by this column's method**, so not comparable with the
rows above. These cells are USRP duty cycle × PHY rate; the MT7612U bench has
no USRP, and its HT MCS7 / 20 MHz figures — 34.03 Mbit/s single-frame, 44.55
with A-MPDU — are receiver frame counts instead, which is the instrument this
project deliberately does not judge TX by. Both directions are validated
against the kernel `mt76x2u` driver on 2.4 GHz and UNII-1:
[the regression matrix](docs/mt7612u.md#on-air-against-the-kernel-driver).

These cells are single-frame injection (the default TX path), measured as
channel occupancy × PHY rate. A-MPDU (`SetAmpduMode`) does **not** move them on
a chip already near the PHY ceiling — it raises *goodput* (delivered payload)
Expand All @@ -137,6 +146,21 @@ long preamble only). It intentionally does not advertise VHT, LDPC, SGI, STBC,
or experimental 5/10 MHz operation; see
[the validation record](docs/rtl8733b.md) for the tested and deferred matrix.

The **MT7612U** backend (`src/mt7612u/`) is the one non-Realtek family, behind
the same `IRadio` contract and sharing none of the Realtek HAL — this is 32-bit
registers over EP0 plus an in-band MCU on EP8/EP5, with firmware uploaded at
bring-up. It is OFF by default; build it with `-DDEVOURER_MT7612U=ON`, and note
that the firmware is *not* embedded the way every Realtek blob is: `mt7662.bin`
and `mt7662_rom_patch.bin` ship zstd-compressed in linux-firmware under their
own licence, so they are searched for at runtime
(`DeviceConfig.mt7612u.firmware_dir`). Monitor RX with per-chain RSSI, raw
injection at any rate the TXWI can express, hardware ACK, A-MPDU and 20/40/80
MHz tuning all work; there is no fast retune (≈50 ms fast / ≈530 ms full), no
5/10 MHz, no HE, no 160 MHz, no beacons, and unicast injection is a 40× cliff.
`SetTxMode` is refused — the C library has no session-default rate, so the rate
goes in each frame's radiotap header instead, where it always wins. [Every
number and its counterpart](docs/mt7612u.md).

> Heads up — some Realtek sticks ship in "ZeroCD" mode and first enumerate as
> a USB flash drive holding a Windows installer (`0bda:1a2b` is the canonical
> offender). If the device won't open, check `lsusb`; `usb_modeswitch` flips
Expand Down Expand Up @@ -371,7 +395,9 @@ per-chip quirks notes at the bottom.
Headless selftests run with `ctest`. Hardware regression is
`tests/regress.py`: a TX/RX matrix between devourer and the kernel driver
across plugged-in adapters, with optional full-pair, encoding-sweep, and
third-adapter-sniffer modes — see [`tests/README.md`](tests/README.md).
third-adapter-sniffer modes — see [`tests/README.md`](tests/README.md). It
covers the MediaTek backend too (`--mt7612u-fw-dir`, and `--tx-pid`/`--rx-pid`
accept a sysfs id so two adapters of one model can be told apart).

## License

Expand Down
Loading
Loading