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
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ add_library(WiFiDriver
src/HalModule.h
src/Iqk8812a.cpp
src/Iqk8812a.h
src/Iqk8814a.cpp
src/Iqk8814a.h
src/PhydmWatchdog.cpp
src/PhydmWatchdog.h
src/ParsedRadioPacket.cpp
src/PhyTableLoader.cpp
src/PhyTableLoader.h
Expand Down
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ The Realtek 11ac driver that simply devours its competitors.

Devourer is a userspace re-implementation of Realtek's RTL88xxAU Wi-Fi
driver (Jaguar family: RTL8812AU and RTL8821AU shipping on every band,
RTL8811AU supported via the 8812 code path, RTL8814AU RX-only),
speaking to the chip directly through libusb. No kernel
module, no `rtl8812au` DKMS tree — just a C++20 static library
(`WiFiDriver`) plus two demo executables for RX and TX. It is the
OpenIPC project's driver of choice for long-range video links built on
top of cheap Realtek 11ac USB radios.
RTL8811AU supported via the 8812 code path, RTL8814AU with band-
specific gaps — see table below), speaking to the chip directly
through libusb. No kernel module, no `rtl8812au` DKMS tree — just a
C++20 static library (`WiFiDriver`) plus two demo executables for RX
and TX. It is the OpenIPC project's driver of choice for long-range
video links built on top of cheap Realtek 11ac USB radios.

## Hardware landscape

Expand All @@ -25,7 +25,7 @@ layered on top.
| -------------- | --------------- | ------------- | ---------------------- | ---------------------- | ------------------------------------------- |
| **RTL8812AU** | 2T2R | TX + RX | TX + RX | TX + RX | VID/PID `0bda:8812`; reference part — works on every channel/band combo |
| **RTL8811AU** | 1T1R | TX + RX | TX + RX | TX + RX | 1T1R cut of 8812 silicon; rides 8812 code path with `RFType=RF_TYPE_1T1R` selected from `REG_SYS_CFG` bit 27. Status mirrored from 8812 — not separately exercised |
| **RTL8814AU** | 4T4R, 3-SS max | RX only | RX only | RX only | VID/PID `0bda:8813`; 2-SS effective on USB-2. TX submits succeed on the bulk pipe but nothing reaches the air at any band |
| **RTL8814AU** | 4T4R, 3-SS max | RX only | RX only | TX + RX | VID/PID `0bda:8813`; 2-SS effective on USB-2. 5 GHz UNII-2/3 TX produces on-air frames after the 8814A-specific band-switch + channel-set chain. 2.4 GHz TX still doesn't reach receivers |
| **RTL8821AU** | 1T1R AC + BT | TX + RX | TX + RX | TX + RX | OEM-rebadged as TP-Link Archer T2U Plus (`2357:0120`) etc. UNII-2/3 TX has cross-receiver asymmetry against 8812AU peers |

Successor families (`Jaguar2` / `Jaguar+` — 8812BU, 8822BU/BE, etc., and
Expand Down Expand Up @@ -105,6 +105,24 @@ Common to both demos:
channel switch. Skipped by default in 8814 monitor mode: the loop issues
~300 vendor control transfers and the resulting per-rate indices are
unused for RX-only operation.
- `DEVOURER_SKIP_TXPWR=1` — skip the per-rate TX-power loop entirely on
every chip. Useful for fast iteration during BB/RF debugging when the
per-rate indices aren't relevant to what you're measuring.
- `DEVOURER_FORCE_IQK=1` — run phydm I/Q calibration on every channel-set,
not just band transitions. For 8814, IQK is otherwise off by default —
the kernel doesn't run it on `iw set channel` either, and devourer
matches that behaviour.
- `DEVOURER_DISABLE_IQK=1` — never run IQK, even when armed by a band
transition. Diagnostic — IQK-output BB regs stay at their BB-init seeds.
- `DEVOURER_PHYDM_WATCHDOG=1` — start the periodic phydm DM watchdog
thread (FA-counter statistics + DIG IGI walk every ~2 s). Off by
default because the watchdog's BB reads/writes share libusb's
transfer queue with the TX bulk path and measurably drop sustained
TX throughput on Jaguar chips. Use for canary-diff workflows and
RX-only DIG tuning.
- `DEVOURER_DUMP_CANARY=1` — emit a canonical post-channel-set dump of
BB/MAC/RF anchor registers. Feeds the `tests/canary_diff.py`
cross-validation tool against `tools/canary_kernel_dump.sh` output.
- `DEVOURER_USB_QUIET=1` — downgrade libusb log level from DEBUG to
WARNING (DEBUG produces ~7 MB per 15 s and can fill `/tmp` mid-capture).

Expand Down Expand Up @@ -180,7 +198,9 @@ src/ Driver implementation
FirmwareManager chip-specific firmware download
PhyTableLoader applies chip-cut-conditional BB/AGC tables
PowerTracking8812a phydm thermal-meter TX BB-swing compensation
Iqk8812a phydm I/Q calibration
Iqk8812a phydm I/Q calibration for 8812 / 8821
Iqk8814a phydm I/Q calibration for 8814 (4-path)
PhydmWatchdog opt-in periodic DM thread (FA stats + DIG)
RtlUsbAdapter libusb wrapper (vendor + bulk transfers)
FrameParser RX parsing, TX descriptor layout
Radiotap.c radiotap header iterator
Expand Down
32 changes: 32 additions & 0 deletions src/HalModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,29 @@ bool HalModule::rtw_hal_init(SelectedChannel selectedChannel) {
if (status) {
_radioManagementModule->init_hw_mlme_ext(selectedChannel);
_radioManagementModule->SetMonitorMode();

/* Construct + start the phydm DM watchdog after chip init is
* complete. Tick once synchronously so the first canary capture
* sees post-watchdog state (mirrors kernel where phydm runs
* before any read-back). Then spawn the periodic thread for
* subsequent 2s ticks. */
/* Phydm DM watchdog is opt-in (`DEVOURER_PHYDM_WATCHDOG=1`). The
* watchdog thread's periodic BB reads/writes share libusb's
* transfer queue with the TX bulk path — measured 4500→1000 TX
* submits in 10s on 8821 ch100, and 2300→0 RX hits on the 8814
* ch100 dev-dev cell — when the watchdog runs concurrently with
* sustained TX. The scaffold + DIG port are kept available for
* targeted experiments (canary diff vs kernel reference, future
* RX-only DIG tuning), but normal monitor-mode RX/TX runs the
* faster, watchdog-less path that matches kernel cold-init
* behaviour anyway (kernel doesn't run phydm before the first
* `iw set channel` either). */
if (std::getenv("DEVOURER_PHYDM_WATCHDOG")) {
_phydmWatchdog = std::make_unique<PhydmWatchdog>(
_device, _eepromManager, _radioManagementModule.get(), _logger);
_phydmWatchdog->TickOnce();
_phydmWatchdog->Start();
}
} else {
_logger->error("rtw_hal_init: fail");
}
Expand Down Expand Up @@ -310,6 +333,15 @@ bool HalModule::rtl8812au_hal_init(uint8_t init_channel) {
if (_eepromManager->version_id.ICType == CHIP_8812) {
_radioManagementModule->ArmIQKOnNextChannelSet();
}
/* Note: 8814 IQK is NOT auto-armed on cold init. The kernel does
* not arm it either — the standard `iw set channel` path goes
* through `set_channel_bwmode` → `rtw_hal_set_chnl_bw` without
* firing `HW_VAR_DO_IQK`. Only AP-mode / DFS / silent-reset paths
* fire IQK kernel-side. Auto-arming on devourer caused BB 0xc60
* to land at the AFE-normal value (0x07808003) at end of IQK
* restore, instead of the BB-init final value (0x0e808003) that
* the kernel canary observes. The `Iqk8814a` port is still wired
* up via `DEVOURER_FORCE_IQK=1` for explicit testing. */

if (_eepromManager->version_id.RFType == RF_TYPE_1T1R) {
PHY_BB8812_Config_1T();
Expand Down
4 changes: 4 additions & 0 deletions src/HalModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern "C"{
#include "Hal8814PwrSeq.h"
#include "Hal8821APwrSeq.h"
}
#include "PhydmWatchdog.h"
#include "RadioManagementModule.h"
#include "RtlUsbAdapter.h"
#include "SelectedChannel.h"
Expand Down Expand Up @@ -51,6 +52,9 @@ class HalModule {
uint8_t _rxAggDmaSize =
16; /* uint: 128b, 0x0A = 10 =
MAX_RX_DMA_BUFFER_SIZE/2/pHalData.UsbBulkOutSize */
/* Phydm DM watchdog. Lazily constructed in `rtw_hal_init` after
* `RadioManagementModule` is fully wired up. */
std::unique_ptr<PhydmWatchdog> _phydmWatchdog;

public:
HalModule(RtlUsbAdapter device, std::shared_ptr<EepromManager> eepromManager,
Expand Down
Loading
Loading