From bad18fbbb0b2c7260248293b095dd6de0269e359 Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:41:39 +0300 Subject: [PATCH 1/4] core: rename IRtlDevice to IRadio and IRtlTransport to ITransport The radio contract and the bus seam are vendor-neutral; only RtlAdapter and the five backends are Realtek-specific and keep their names. IRtlDevice -> IRadio (src/IRadio.h) WiFiDriver::CreateRtlDevice -> CreateRadio CreateRtlDevicePcie -> CreateRadioPcie devourer::IRtlTransport -> ITransport (src/Transport.h) Hard rename, no aliases. Mechanical pass, applicable unchanged to a downstream tree: git grep -I -l -z -E 'IRtlDevice|RtlTransport\.h|IRTL_DEVICE_H|CreateRtlDevice|IRtlTransport' \ -- . ':!reference' ':!hal' \ | xargs -0 sed -i -E \ -e 's/\bIRtlDevice\.h\b/IRadio.h/g' \ -e 's/\bRtlTransport\.h\b/Transport.h/g' \ -e 's/\bIRTL_DEVICE_H\b/IRADIO_H/g' \ -e 's/\bCreateRtlDevicePcie\b/CreateRadioPcie/g' \ -e 's/\bCreateRtlDevice\b/CreateRadio/g' \ -e 's/\bIRtlTransport\b/ITransport/g' \ -e 's/\bIRtlDevice\b/IRadio/g' Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_015VtdB2ZryKELUwREjPBH3v --- CLAUDE.md | 32 ++++++++++++------------- CMakeLists.txt | 10 ++++---- README.md | 6 ++--- docs/adapter-doctor.md | 4 ++-- docs/aggregation.md | 6 ++--- docs/beamforming-self-sounding.md | 2 +- docs/driver-primer.md | 4 ++-- docs/fhss.md | 2 +- docs/frequency-hopping.md | 4 ++-- docs/he-trigger-ul.md | 4 ++-- docs/mt7612u.md | 4 ++-- docs/narrowband.md | 6 ++--- docs/rtl8733b.md | 4 ++-- docs/rx-spectrum-sensing.md | 4 ++-- docs/scheduled-mac.md | 2 +- docs/time-distribution.md | 4 ++-- examples/chanmig/main.cpp | 6 ++--- examples/chanscout/main.cpp | 6 ++--- examples/chipstate/main.cpp | 10 ++++---- examples/common/DeviceSession.h | 10 ++++---- examples/common/caps_event.h | 8 +++---- examples/common/env_config.h | 2 +- examples/doctor/main.cpp | 8 +++---- examples/duplex/main.cpp | 6 ++--- examples/dwelltx/main.cpp | 4 ++-- examples/precoder/main.cpp | 4 ++-- examples/rx/main.cpp | 32 ++++++++++++------------- examples/sense/main.cpp | 4 ++-- examples/streamtx/main.cpp | 8 +++---- examples/svctx/main.cpp | 4 ++-- examples/tdma/main.cpp | 8 +++---- examples/tdma/tdma.h | 2 +- examples/timesync/main.cpp | 16 ++++++------- examples/tx/main.cpp | 18 +++++++-------- examples/txpower/main.cpp | 10 ++++---- src/AdapterCaps.h | 2 +- src/AdapterHealth.h | 4 ++-- src/CfoTracker.h | 2 +- src/DeviceConfig.h | 6 ++--- src/{IRtlDevice.h => IRadio.h} | 14 +++++------ src/PcieTransport.h | 8 +++---- src/RtlAdapter.cpp | 2 +- src/RtlAdapter.h | 12 +++++----- src/RtlUsbAdapter.h | 4 ++-- src/RxPacket.h | 2 +- src/RxSense.h | 2 +- src/Sounding.h | 2 +- src/ThermalStatus.h | 2 +- src/{RtlTransport.h => Transport.h} | 6 ++--- src/TxPower.h | 4 ++-- src/UsbDeviceLock.h | 2 +- src/UsbOpen.h | 2 +- src/UsbTransport.cpp | 4 ++-- src/UsbTransport.h | 6 ++--- src/WiFiDriver.cpp | 8 +++---- src/WiFiDriver.h | 14 +++++------ src/jaguar1/RadioManagementModule.h | 6 ++--- src/jaguar1/RtlJaguarDevice.cpp | 4 ++-- src/jaguar1/RtlJaguarDevice.h | 36 ++++++++++++++--------------- src/jaguar2/ChipVariant.h | 2 +- src/jaguar2/HalJaguar2.h | 6 ++--- src/jaguar2/RtlJaguar2Device.cpp | 2 +- src/jaguar2/RtlJaguar2Device.h | 26 ++++++++++----------- src/jaguar3/ChipVariant.h | 2 +- src/jaguar3/HalJaguar3.h | 2 +- src/jaguar3/Jaguar3Calibration.h | 2 +- src/jaguar3/RtlJaguar3Device.cpp | 6 ++--- src/jaguar3/RtlJaguar3Device.h | 26 ++++++++++----------- src/kestrel/ChipVariant.h | 2 +- src/kestrel/RtlKestrelDevice.h | 8 +++---- src/mt7612u/README.md | 2 +- src/mt7612u/tools/bringup.c | 2 +- src/mt7612u/usb.c | 2 +- src/rtl8733b/CLAUDE.md | 6 ++--- src/rtl8733b/Phy8733b.h | 4 ++-- src/rtl8733b/Rtl8733bDevice.cpp | 6 ++--- src/rtl8733b/Rtl8733bDevice.h | 12 +++++----- tests/ack_responder_selftest.cpp | 2 +- tests/adapter_caps_probe.sh | 2 +- tests/ap_responder.cpp | 4 ++-- tests/ap_wpa2.cpp | 4 ++-- tests/beacon_fullbody.cpp | 2 +- tests/beacon_interval_shift.sh | 6 ++--- tests/beacon_steer_check.cpp | 6 ++--- tests/beacon_steer_survival.sh | 2 +- tests/beacon_tbtt.cpp | 4 ++-- tests/beacon_ts_check.cpp | 2 +- tests/beacon_update_probe.cpp | 2 +- tests/beacon_wire_check.cpp | 2 +- tests/dl_departure_tx.cpp | 2 +- tests/fast_bw_rxcheck.cpp | 2 +- tests/in_process_hotplug_wrap.cpp | 4 ++-- tests/pcie_ptp_beacon.cpp | 2 +- tests/pcie_txegress_tx.cpp | 4 ++-- tests/probe_responder.cpp | 4 ++-- tests/retune_bench.cpp | 2 +- tests/rtl8733b_txpwr_regcheck.sh | 2 +- tests/rx_quality_selftest.cpp | 2 +- tests/tsf_probe.cpp | 2 +- tests/tsf_tdoa_probe.cpp | 6 ++--- tests/tx_quiesce_selftest.cpp | 6 ++--- tests/txegress_witness.cpp | 2 +- tests/txpwr_offset_regcheck.sh | 2 +- tests/txpwr_rate_diffs_regcheck.sh | 2 +- tests/ue_rx_probe.cpp | 2 +- tests/ul_trigger_ap.cpp | 4 ++-- 106 files changed, 312 insertions(+), 312 deletions(-) rename src/{IRtlDevice.h => IRadio.h} (99%) rename src/{RtlTransport.h => Transport.h} (97%) diff --git a/CLAUDE.md b/CLAUDE.md index ca6a63c1..8ab6cc1c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -60,7 +60,7 @@ construction from the `SYS_CFG2` chip-id (Kestrel: PID-first): 20/40 MHz on 2.4/5 GHz, plus long-preamble CCK on 2.4 GHz at 20 MHz, plus 10 MHz narrowband (5 MHz refused — `src/rtl8733b/CLAUDE.md`). Everything the backend has not ported (TSF/beacons, A-MPDU, CCX/`tx.report`, - the flat-index and per-rate TX-power knobs) falls through to `IRtlDevice`'s + the flat-index and per-rate TX-power knobs) falls through to `IRadio`'s not-ported defaults rather than being faked, so read the base class before assuming a cross-generation feature below applies here. `FastRetune` IS ported (intra-band, TSSI kept live — `src/rtl8733b/CLAUDE.md`). SGI, LDPC, STBC, VHT @@ -79,12 +79,12 @@ PCIe sibling of the 8821CU — rides the same Jaguar2 HAL through a vfio-pci transport (`src/PcieTransport.{h,cpp}`: BAR2 MMIO registers over the same 0x0000..0xFFFF space the USB vendor-control path addresses, 88xx buffer-descriptor DMA rings for TX/RX). USB and PCIe are independent -transports behind `devourer::IRtlTransport` (`src/RtlTransport.h`); the +transports behind `devourer::ITransport` (`src/Transport.h`); the bus-neutral `RtlAdapter` the HALs hold forwards to whichever it was built with. The few genuinely bus-specific bring-up steps gate on `is_usb()` (PCIe power-seq rows, PQ map, no USB RX-agg, no DLFW 512-pad) or ride `hci_setup()` (pre-power TRX ring programming, no-op on USB). Factory: -`WiFiDriver::CreateRtlDevicePcie(PcieTransport::Open(bdf, logger))` — the +`WiFiDriver::CreateRadioPcie(PcieTransport::Open(bdf, logger))` — the caller owns vfio like it owns libusb. Demos: `DEVOURER_PCIE_BDF=0000:01:00.0` on rxdemo and txdemo; `pcieprobe ` validates the layers bottom-up. Bind/restore: `tests/pcie_vfio_bind.sh` — driver_override, **not** new_id, @@ -207,11 +207,11 @@ dumps (kernel cross-validation format). **The library reads no environment.** Construction-time knobs live in `devourer::DeviceConfig` (`src/DeviceConfig.h` — rx / tx / bf / tuning / debug / usb sections, every field doc-tagged with its env-var spelling and value -grammar), passed as `CreateRtlDevice`'s defaulted fourth argument. Mid-session -knobs are runtime setters on `IRtlDevice` (`SetTxMode`, `SetTxPowerOffsetQdb`, +grammar), passed as `CreateRadio`'s defaulted fourth argument. Mid-session +knobs are runtime setters on `IRadio` (`SetTxMode`, `SetTxPowerOffsetQdb`, `SetTxPowerIndexOverride`, `SetRxPathMask`, `SetCcaMode`, `FastRetune`, ...). -**Adapter capabilities**: `IRtlDevice::GetAdapterCaps()` (`src/AdapterCaps.h`) +**Adapter capabilities**: `IRadio::GetAdapterCaps()` (`src/AdapterCaps.h`) aggregates chip identity, chain counts, the composed `GetTxCaps` + `GetTxPowerCaps`, channel widths, per-band tunable + characterized frequency spans, and feature flags — resolved at construction, thread-safe, callable @@ -270,7 +270,7 @@ those are the ones listed below. - `DEVOURER_USB_DEBUG=1` — libusb DEBUG log level (~7 MB / 15 s, has filled `/tmp` mid-capture; adds 0.5–0.8 s to init). - `DEVOURER_THERMAL_POLL_MS=N` — emit `thermal` events from the RF 0x42 meter, - on every generation (the poller rides `IRtlDevice::GetThermalStatus`). + on every generation (the poller rides `IRadio::GetThermalStatus`). `raw` is 0..63 thermal units (~1.5–2 °C each, **not** absolute °C); `delta` = raw − EFUSE baseline. **Telemetry only**: the poller emits and warns (`DEVOURER_THERMAL_WARN_DELTA`, default 15) and never stops RX; no HAL gates @@ -388,7 +388,7 @@ temporal layer and injects each at its ladder's rate ## Frequency hopping -`IRtlDevice::FastRetune(channel)` — lean intra-band, same-bandwidth retune on +`IRadio::FastRetune(channel)` — lean intra-band, same-bandwidth retune on all five generations (RF channel switch only, write-only from a compose cache); falls back to full `SetMonitorChannel` on a band change. FHSS-grade on the Jaguar/Kestrel dies: ~0.5–2.5 ms per hop depending on chip. @@ -418,7 +418,7 @@ reference, policy thresholds, measured sensing constants and the on-air harnesses: `src/hopset/CLAUDE.md`. Article + results: `docs/fhss.md`, `docs/jammer-resilience.md`. -`IRtlDevice::FastSetBandwidth(bw)` is the bandwidth analogue — a lean +`IRadio::FastSetBandwidth(bw)` is the bandwidth analogue — a lean same-channel toggle between 20 MHz and 5/10 MHz narrowband (baseband re-clock only; ~0.18 ms on the 8812AU vs ~90 ms for the full `SetMonitorChannel`); falls back to the full path for a 40/80 MHz endpoint. Validation: @@ -498,16 +498,16 @@ sensor; C2H rides the RX path, so J1/J2 TX-only sessions see none (run ## Architecture -**The caller owns libusb.** `WiFiDriver::CreateRtlDevice` is intentionally +**The caller owns libusb.** `WiFiDriver::CreateRadio` is intentionally thin — `libusb_init`, device open, kernel-driver detach, and `libusb_claim_interface(handle, 0)` must happen **before** handing the handle to the factory. `examples/rx/main.cpp` is the canonical boilerplate; `devourer::claim_interface_then_reset` (src/UsbOpen.h) is the recommended open path (advisory per-adapter lock before reset). -Owning libusb means owning the **teardown order**: destroy the `IRtlDevice` +Owning libusb means owning the **teardown order**: destroy the `IRadio` first, then release the interface, close the handle, and only then -`libusb_exit`. The device is what quiesces TX (`IRtlDevice::Stop`, and the +`libusb_exit`. The device is what quiesces TX (`IRadio::Stop`, and the destructor as a backstop: Jaguar1's async bulk-OUT URBs must be cancelled and reaped while the context still exists), so tearing libusb down first is a crash, not a leak — and only under enough TX load to keep URBs outstanding at @@ -516,7 +516,7 @@ that order; the transport logs a diagnostic naming this if it is destroyed with TX still in flight. **Chip identity is resolved at construction** from the `SYS_CFG2` chip-id + -USB PID. `CreateRtlDevice` returns an `IRtlDevice` (`Init` = bring-up + RX +USB PID. `CreateRadio` returns an `IRadio` (`Init` = bring-up + RX loop; `InitWrite` = TX bring-up; `StartRxLoop` = blocking RX worker on an already-up chip, enabling TX+RX on one handle; `send_packet`) and constructs `RtlJaguarDevice` / `RtlJaguar2Device` / `RtlJaguar3Device` / `RtlKestrelDevice` @@ -528,11 +528,11 @@ the backend's header before believing a cross-generation claim. Generation-agnostic core in `src/` (always compiled; depends on no HAL): -- `WiFiDriver` — the factory (`CreateRtlDevice`). +- `WiFiDriver` — the factory (`CreateRadio`). - `DeviceConfig.h` — construction-time configuration struct; every component copies the sub-struct it consumes at construction. - `RtlAdapter` — the bus-neutral register/frame accessor; a copyable value - type shared by every component, forwarding to the `IRtlTransport` it was + type shared by every component, forwarding to the `ITransport` it was built with (`UsbTransport` = libusb vendor control + bulk; `PcieTransport` = BAR2 MMIO + DMA rings). `RtlUsbAdapter` is a deprecated alias. - `Radiotap.c` — radiotap iterator. TX buffers passed to `send_packet` **must** @@ -616,7 +616,7 @@ byte-for-byte; prefer that shape when adding one. ```cpp auto logger = std::make_shared(); WiFiDriver driver(logger); -auto dev = driver.CreateRtlDevice(handle); // handle is already claimed +auto dev = driver.CreateRadio(handle); // handle is already claimed dev->InitWrite(SelectedChannel{ .Channel = 36, .ChannelOffset = 0, .ChannelWidth = CHANNEL_WIDTH_20 }); dev->send_packet(buffer, len); // buffer[0..] = radiotap header, then 802.11 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1aa0534d..be36a29e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,7 +173,7 @@ add_library(devourer src/Radiotap.c src/RadiotapBuilder.cpp src/RadiotapBuilder.h - src/RtlTransport.h + src/Transport.h src/RtlAdapter.cpp src/RtlAdapter.h src/RtlUsbAdapter.h # compat alias shim (RtlUsbAdapter = RtlAdapter) @@ -224,7 +224,7 @@ add_library(devourer src/hopset/HopsetSense.h src/hopset/HopsetFusion.h src/hopset/HopsetEvents.h - src/IRtlDevice.h + src/IRadio.h src/SignalStop.cpp src/SignalStop.h src/WiFiDriver.cpp @@ -567,7 +567,7 @@ endif() # rtl8733bprobe — staged USB bring-up prober for the RTL8733B (HALMAC 87xx), # the pcieprobe/kestrelprobe sibling: identity -> power-on + EFUSE -> firmware # -> MAC/PHY -> TSSI audit stages, used alongside normal factory dispatch. It -# never substitutes for the production IRtlDevice path. +# never substitutes for the production IRadio path. if(DEVOURER_8733B) add_executable(rtl8733bprobe examples/rtl8733bprobe/main.cpp @@ -676,7 +676,7 @@ target_link_libraries(duplex PUBLIC devourer PRIVATE PkgConfig::libusb) target_include_directories(duplex PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/examples/common) # txpower — reference consumer of the runtime TX-power API -# (IRtlDevice::SetTxPowerOffsetQdb / SetTxPowerIndexOverride / GetTxPowerState / +# (IRadio::SetTxPowerOffsetQdb / SetTxPowerIndexOverride / GetTxPowerState / # GetThermalStatus): opens one adapter, steps the knobs from CLI args (no env # vars), and prints machine-readable state markers. The register-level # validation driver for tests/txpwr_offset_regcheck.sh and the shape of an @@ -775,7 +775,7 @@ target_link_libraries(ToneMaskSelftest PRIVATE devourer) add_test(NAME tone_mask_math COMMAND ToneMaskSelftest) -# Headless guard for the TX quiesce seam (IRtlTransport::quiesce_tx via +# 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 # hardware under ASan — the test header says what it does and does not cover. diff --git a/README.md b/README.md index 22b56514..8d38347c 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ the full boilerplate; the minimal RX path is: ```cpp auto logger = std::make_shared(); WiFiDriver driver(logger); -auto dev = driver.CreateRtlDevice(handle); // handle is already claimed +auto dev = driver.CreateRadio(handle); // handle is already claimed dev->Init(packetProcessor, SelectedChannel{ .Channel = 36, .ChannelOffset = 0, @@ -229,13 +229,13 @@ Construction-time options travel in a `devourer::DeviceConfig` ```cpp devourer::DeviceConfig cfg; cfg.rx.keep_corrupted = true; // deliver CRC-failed frames too -auto dev = driver.CreateRtlDevice(handle, ctx, lock, cfg); +auto dev = driver.CreateRadio(handle, ctx, lock, cfg); ``` Anything that changes mid-session is a runtime setter on the device: `SetTxMode`, `SetTxPowerOffsetQdb`, `SetRxPathMask`, `FastRetune`, ... The device class is chosen automatically from the chip behind the handle; -one `IRtlDevice` interface covers all five hardware backends. +one `IRadio` interface covers all five hardware backends. ## Going deeper diff --git a/docs/adapter-doctor.md b/docs/adapter-doctor.md index a1c233bb..4f4dcb2b 100644 --- a/docs/adapter-doctor.md +++ b/docs/adapter-doctor.md @@ -28,13 +28,13 @@ build/doctor --bus 3 --port 2.3.3 # topology select (two same-PID adapters) 1. **Bring-up** — `InitWrite`; an abort is an immediate FAILING. 2. **EFUSE stability** — N fresh *physical* map reads - (`IRtlDevice::ProbeEfuseStability`), cross-compared byte-for-byte + + (`IRadio::ProbeEfuseStability`), cross-compared byte-for-byte + EEPROM-ID (0x8129) validated. Any read-to-read mismatch is conclusive by itself. Not probed on the 8822E — its OTP is not reliably readable after bring-up by design, so probing would flag healthy units. 3. **FW boot** — checksum + MCU-ready outcome of the bring-up's - download (`IRtlDevice::GetFwBootStatus`). + download (`IRadio::GetFwBootStatus`). 4. **RX smoke** — FCS-clean frame count over `--listen-secs`. Ambient traffic counts. Hearing *nothing* is only SUSPECT unless `--expect-traffic` vouches for a source on the channel — an diff --git a/docs/aggregation.md b/docs/aggregation.md index ab0e0747..391e6718 100644 --- a/docs/aggregation.md +++ b/docs/aggregation.md @@ -18,7 +18,7 @@ and A-MPDU unicast into reliable (hardware-ARQ) links. ## USB TX aggregation (`send_packets`) -`IRtlDevice::send_packets(TxPacketView*, n)` + `DeviceConfig tx.usb_agg_max` +`IRadio::send_packets(TxPacketView*, n)` + `DeviceConfig tx.usb_agg_max` (env `DEVOURER_TX_USB_AGG`, default 0 = off → per-frame loop, byte-identical descriptors). Packing rules live in `src/TxAggPlan.h` (pure math, ctest'd): blocks 8-byte aligned, the FIRST descriptor carries the block count @@ -90,7 +90,7 @@ coverage a reliability layer can count on — is in ## A-MPDU (`SetAmpduMode`) -`IRtlDevice::SetAmpduMode(AmpduMode)` / `ClearAmpduMode()` / `GetAmpduMode()` +`IRadio::SetAmpduMode(AmpduMode)` / `ClearAmpduMode()` / `GetAmpduMode()` (env `DEVOURER_TX_AMPDU_MODE="tid/maxnum[/density[/noack[/maxtime_hex]]]"`, `src/AmpduMode.h`, all generations) configure A-MPDU TX in one call: it marks every data frame aggregatable (data QSEL + AGG_EN + MAX_AGG_NUM + @@ -187,7 +187,7 @@ numbers above came from. ## Hardware ACK/BlockAck responder — reliable unicast -`IRtlDevice::SetAckResponder(mac)` / `ClearAckResponder()` (env +`IRadio::SetAckResponder(mac)` / `ClearAckResponder()` (env `DEVOURER_ACK_RESPONDER=`, all generations; `src/AckResponder.h`) arms the MAC's autonomous ACK engine while monitor RX/injection continue unchanged: port identity (MACID/BSSID 0x610/0x618 = `mac`) + net_type (0x102 diff --git a/docs/beamforming-self-sounding.md b/docs/beamforming-self-sounding.md index 3c1e856d..236d5440 100644 --- a/docs/beamforming-self-sounding.md +++ b/docs/beamforming-self-sounding.md @@ -74,7 +74,7 @@ DEVOURER_PID=0x8813 DEVOURER_CHANNEL=100 DEVOURER_BF_DETECT_REPORT=4 \ # single-radio beamformer: the report is addressed TO the sounder, so one # adapter can sound and capture its own reports — DEVOURER_TX_WITH_RX=thread # runs the RX worker loop on a thread next to the TX loop (one bring-up, one -# claimed handle; see StartRxLoop in IRtlDevice). Hardware-validated on the +# claimed handle; see StartRxLoop in IRadio). Hardware-validated on the # 8814AU (Jaguar-1), the 8822BU (Jaguar-2) and both Jaguar-3 variants # (8822CU / 8822EU) — 50k+ self-captured reports per 20 s at full sounding # rate. On Jaguar-2/3, DEVOURER_BF_ARM_SOUNDER takes the sounder MAC diff --git a/docs/driver-primer.md b/docs/driver-primer.md index a9f480d6..7ff42609 100644 --- a/docs/driver-primer.md +++ b/docs/driver-primer.md @@ -50,7 +50,7 @@ access is a vendor **control transfer**: the host submits a **URB** (USB request block) to the kernel's USB stack, the request crosses the wire with the register address packed into its setup fields, and the chip answers with the data. That's the whole trick — `lsusb`-level plumbing, no kernel driver magic. devourer's -`RtlAdapter` (`src/RtlTransport.h`) is nothing but this, and the vendor equivalent +`RtlAdapter` (`src/Transport.h`) is nothing but this, and the vendor equivalent is `usb_ops_linux.c` in each tree. The address space is a map you'll internalize fast: the MAC's registers occupy the @@ -442,7 +442,7 @@ find each in the vendor trees and in devourer. | PA / LNA | power amp (TX) / low-noise amp (RX) front end | 1 | board-level; selected by RFE type | | WCPU | the MAC's embedded CPU running firmware | 1,5 | booted by FWDL | | A-die / D-die | analog / digital silicon dies in one package | 1,9 | reached via DAV / DDV | -| URB | USB request block — one queued USB transfer | 2 | `usb_ops_linux.c` / `src/RtlTransport.h` | +| URB | USB request block — one queued USB transfer | 2 | `usb_ops_linux.c` / `src/Transport.h` | | chip id | which die design; drives HAL dispatch | 3 | `SYS_CFG` / `WiFiDriver` factory | | cut | silicon revision (A/B/C…) | 3 | gates tables + firmware images | | RFE (type) | board's RF front-end wiring variant, from efuse | 3 | gates PHY table blocks | diff --git a/docs/fhss.md b/docs/fhss.md index 9ec682c0..5d39d8c0 100644 --- a/docs/fhss.md +++ b/docs/fhss.md @@ -33,7 +33,7 @@ without stalling the data stream is the engineering problem. ## The hop engine: a lean retune -`IRtlDevice::FastRetune(channel, cache_rf)` is the generation-agnostic entry +`IRadio::FastRetune(channel, cache_rf)` is the generation-agnostic entry point. The default implementation is the full `SetMonitorChannel`; every chip family overrides it with a stripped-down path. The vendor's channel-set routine does a great deal that does not change between two channels of the same band and diff --git a/docs/frequency-hopping.md b/docs/frequency-hopping.md index b29819ec..3a0d2bc5 100644 --- a/docs/frequency-hopping.md +++ b/docs/frequency-hopping.md @@ -325,7 +325,7 @@ constants once); every subsequent same-band hop is ~1.5 ms. ## The ports: all three generations -`IRtlDevice::FastRetune(channel, cache_rf)` is the generation-agnostic entry +`IRadio::FastRetune(channel, cache_rf)` is the generation-agnostic entry point (default = the full `SetMonitorChannel` at the current width/offset), and every generation overrides it with a lean path built from the tricks above: @@ -481,7 +481,7 @@ implies. ## The bandwidth analogue: FastSetBandwidth -The same method applies to a *bandwidth* switch. `IRtlDevice::FastSetBandwidth(bw)` +The same method applies to a *bandwidth* switch. `IRadio::FastSetBandwidth(bw)` is a lean same-channel toggle between 20 MHz and 5/10 MHz narrowband — and it collapses even harder than a hop, because narrowband keeps the RF in 20 MHz mode (so the RF bandwidth register, MAC BW, sub-channel, TX power, and IQK are all diff --git a/docs/he-trigger-ul.md b/docs/he-trigger-ul.md index d91d9998..b156d5e9 100644 --- a/docs/he-trigger-ul.md +++ b/docs/he-trigger-ul.md @@ -63,7 +63,7 @@ responses and data frames: `TriggerConfig`: frame-control `0x24`, duration, RA/TA, the HE Common Info field, and one User Info field per granted user (AID, RU allocation, MCS, spatial streams, target RSSI). -2. `IRtlDevice::SendTrigger()` prepends a radiotap header (legacy OFDM, so any +2. `IRadio::SendTrigger()` prepends a radiotap header (legacy OFDM, so any monitor decodes it) and calls the normal `send_packet()` transmit path. The firmware's trigger scheduler is bypassed entirely. @@ -91,7 +91,7 @@ client firmware does not air. In short: ## Device API -The surface is on `IRtlDevice`; each call returns `false` on pre-AX generations. +The surface is on `IRadio`; each call returns `false` on pre-AX generations. - `SendTrigger(const TriggerConfig&)` — air one Basic Trigger. Default path is host-injection; set `DeviceConfig.debug.kestrel_trigger_f2p` (env diff --git a/docs/mt7612u.md b/docs/mt7612u.md index 0d0ff2a6..4c59053d 100644 --- a/docs/mt7612u.md +++ b/docs/mt7612u.md @@ -6,7 +6,7 @@ running this project's own `rxdemo`/`txdemo`. Read `## Offline tests` and `## Counterparts` before quoting any number here. **This code is not wired into the build.** `CMakeLists.txt` is untouched, there -is no `IRtlDevice` implementation and no `WiFiDriver` dispatch. It is a +is no `IRadio` implementation and no `WiFiDriver` dispatch. It is a standalone C library plus a per-gate bringup harness, offered for the scope question in the PR rather than for merge. @@ -351,7 +351,7 @@ Stated because the numbers above are uniformly favourable. Ordered, and honest about which are unknowns rather than typing: -1. `IRtlDevice` implementation, `WiFiDriver` dispatch, `DeviceConfig` plumbing, +1. `IRadio` implementation, `WiFiDriver` dispatch, `DeviceConfig` plumbing, `CMakeLists.txt`, `ctest` cells. None of this exists. 2. `mt76x2_phy_tssi_compensate()` — periodic temperature correction. Without it output power drifts with die temperature. diff --git a/docs/narrowband.md b/docs/narrowband.md index 1aab70cc..f9767949 100644 --- a/docs/narrowband.md +++ b/docs/narrowband.md @@ -150,7 +150,7 @@ chip-specific traps. The ones this port paid for, current-state: power-up and is deaf on the next — while a closer-crystal peer decodes the same transmitter and the same pair is stable at 2.4 GHz. This is physics, not a driver bug — and it drifts, so a fixed trim is not enough (below). The - manual lever is `IRtlDevice::SetXtalCap` (env `DEVOURER_XTAL_CAP`): + manual lever is `IRadio::SetXtalCap` (env `DEVOURER_XTAL_CAP`): the AFE crystal load-capacitance trim pulls the chip's reference oscillator a few ppm, so trimming one end of a marginal pair moves the offset off the sync boundary. The trim range is per generation (`GetAdapterCaps().xtal_cap_max`: @@ -239,7 +239,7 @@ keeps the RF in 20 MHz mode (RF18[11:10] unchanged) and the MAC at 20 MHz, so the RF bandwidth register, the MAC BW bits, the sub-channel, the RX DFIR/CCA tail, TX power (narrowband folds to the 20 MHz column), and IQK are all invariant. The only thing that actually changes is the baseband ADC/DAC -re-clock register. `IRtlDevice::FastSetBandwidth(bw)` — the bandwidth analogue +re-clock register. `IRadio::FastSetBandwidth(bw)` — the bandwidth analogue of `FastRetune` (`docs/frequency-hopping.md`) — writes just that delta from a cached channel state, and falls back to the full `SetMonitorChannel` for a 40/80 MHz endpoint: @@ -345,7 +345,7 @@ band's bursts). `DEVOURER_NB_BW=5` or `=10` on the demos selects narrowband; the library exposes it as `CHANNEL_WIDTH_5` / `CHANNEL_WIDTH_10` on `SelectedChannel`, and -`IRtlDevice::GetAdapterCaps().narrowband_ok` reports whether the running chip +`IRadio::GetAdapterCaps().narrowband_ok` reports whether the running chip supports it. Support today: **Jaguar2 (8822B/8821C) and Jaguar3 (8822C/8822E)** fully, and **Jaguar1 on the 8812AU/8811AU and the 8814AU** — every generation. The 8821A is the one exclusion (its DAC-clock divide starves TX; see the walls). diff --git a/docs/rtl8733b.md b/docs/rtl8733b.md index 533e0124..cc5a0661 100644 --- a/docs/rtl8733b.md +++ b/docs/rtl8733b.md @@ -77,7 +77,7 @@ everywhere it was pointed: scope — the Wi-Fi function is interface 2, and the demos' claim helpers select it (`find_wifi_interface`). -The following was exercised through the normal `WiFiDriver` / `IRtlDevice` +The following was exercised through the normal `WiFiDriver` / `IRadio` factory path: - USB discovery and endpoint selection; card enable and disable; firmware @@ -216,7 +216,7 @@ calibration has nothing to drive the loop and takes the flat path. ### The runtime lever Because the loop is the power control, the runtime knob is the loop's target. -`IRtlDevice::SetTxPowerOffsetQdb` shifts every per-rate target that survives +`IRadio::SetTxPowerOffsetQdb` shifts every per-rate target that survives the safe ceiling — cap first, then shift, so the calibrated per-rate spread comes through the move intact — and writes it as the five packed dwords at `0x3a00..0x3a10`, **in place, with tracking left enabled**. That is the same diff --git a/docs/rx-spectrum-sensing.md b/docs/rx-spectrum-sensing.md index f55cf77a..082bc9ad 100644 --- a/docs/rx-spectrum-sensing.md +++ b/docs/rx-spectrum-sensing.md @@ -87,7 +87,7 @@ event every `N` ms: "igi":..,"frames":N,"rssi_mean":..,"rssi_max":..,"snr_mean":..,"snr_min":..} ``` -`cca_*`/`fa_*`/`igi` are frame-free (`IRtlDevice::GetRxEnergy`, `null` on a chip +`cca_*`/`fa_*`/`igi` are frame-free (`IRadio::GetRxEnergy`, `null` on a chip that doesn't expose them); the FA/CCA counts are the delta since the previous event (each read resets the hardware counters). `rssi_*`/`snr_*`/`frames` are the rolling per-frame aggregate over the interval. @@ -151,7 +151,7 @@ stays in the moderate regime where `cca_ofdm` rises without saturating. The energy sensor reads one channel at a time; to localise an interferer in frequency, sweep. With `DEVOURER_RX_SWEEP="1,6,11"` the sensor cycles the listed bins — the RX loop runs on a worker thread while the main thread retunes between -reads via `IRtlDevice::FastRetune` (the lean intra-band hop path every +reads via `IRadio::FastRetune` (the lean intra-band hop path every generation implements; `DEVOURER_RX_SWEEP_FULL=1` forces the full `SetMonitorChannel` per dwell for A/B) — and emits one `rx.energy` event (tagged `"ch":N`) per bin. Aggregating those into an energy-vs-frequency bar chart peaks (or, diff --git a/docs/scheduled-mac.md b/docs/scheduled-mac.md index 14591861..f4b15bfe 100644 --- a/docs/scheduled-mac.md +++ b/docs/scheduled-mac.md @@ -80,7 +80,7 @@ which is why scheduled **UL** rides beacon-steered timing, not `send_packet`. A scheduled MAC that carries its DCI-style grant map in the beacon body must be able to **change the airing beacon's content** without missing, duplicating or tearing beacons. The primitive is -`IRtlDevice::UpdateBeaconPayload(beacon, len)` — an in-place content swap for +`IRadio::UpdateBeaconPayload(beacon, len)` — an in-place content swap for an active `StartBeacon` (same buffer contract; interval, TBTT phase and port identity untouched) riding the same reserved-page re-download the TBTT steers use. Its companion `StopBeacon()` silences the beacon function: the chip diff --git a/docs/time-distribution.md b/docs/time-distribution.md index b39f3dab..43f3a6a6 100644 --- a/docs/time-distribution.md +++ b/docs/time-distribution.md @@ -3,7 +3,7 @@ devourer exposes the chip's hardware TSF (the 802.11 MAC's free-running 64-bit microsecond clock) two ways: a per-frame receive stamp (`rx_pkt_attrib::tsfl`, the low 32 bits latched in the MAC at reception, on all three generations) and a -direct `IRtlDevice::ReadTsf()`. Together they are the primitive an LTE eNB uses +direct `IRadio::ReadTsf()`. Together they are the primitive an LTE eNB uses to give its UEs a common timebase — one node holds a reference and distributes it over the air, and every other node slaves to it with no GPS of its own. The `timesync` example (`examples/timesync/`) is a worked demonstration. @@ -79,7 +79,7 @@ Run it with `tests/timesync_demo.sh` (one master + two slaves; joins the two ## Hardware beacon — sub-µs downlink (`DEVOURER_TSYNC_HWBEACON`) The software downlink above is bounded by the master's stamp→air jitter. The -hardware path removes it entirely: `IRtlDevice::StartBeacon` loads a beacon into +hardware path removes it entirely: `IRadio::StartBeacon` loads a beacon into the MAC's beacon reserved-page and lets the chip **auto-transmit it at each TBTT** — hardware-timed, and the MAC inserts the live 64-bit TSF into the beacon's timestamp field at the transmit instant. No `ReadTsf()`, no diff --git a/examples/chanmig/main.cpp b/examples/chanmig/main.cpp index bb74f660..056a1ba2 100644 --- a/examples/chanmig/main.cpp +++ b/examples/chanmig/main.cpp @@ -56,7 +56,7 @@ namespace cm = devourer::chanmig; using devourer::Ev; static devourer::EventSink *g_ev = nullptr; -static IRtlDevice *g_dev = nullptr; +static IRadio *g_dev = nullptr; static std::mutex g_dev_mu; /* serialize send/retune against the RX thread */ /* The pure state machines are single-threaded by design; the demo drives them * from the RX callback, the tick loop, and (ground) the operator thread, so @@ -541,7 +541,7 @@ int main(int argc, char **argv) { #endif WiFiDriver driver(logger); auto owned_device = - driver.CreateRtlDevice(handle, ctx, lock, devourer_config_from_env()); + driver.CreateRadio(handle, ctx, lock, devourer_config_from_env()); if (!owned_device) { logger->error("no driver for this chip"); return 1; @@ -549,7 +549,7 @@ int main(int argc, char **argv) { /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); g_dev = dev; Ev(*g_ev, "migrate.id").t().f("role", role.c_str()) diff --git a/examples/chanscout/main.cpp b/examples/chanscout/main.cpp index c1c05ade..cb7f2251 100644 --- a/examples/chanscout/main.cpp +++ b/examples/chanscout/main.cpp @@ -273,7 +273,7 @@ int main() { session.adopt_lock(usb_lock); WiFiDriver driver(logger); - auto owned_device = driver.CreateRtlDevice(handle, ctx, usb_lock, + auto owned_device = driver.CreateRadio(handle, ctx, usb_lock, devourer_config_from_env()); if (!owned_device) { logger->error("No driver for this chip in this build — exiting"); @@ -282,7 +282,7 @@ int main() { /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); devourer::emit_adapter_caps(*g_ev, dev); const devourer::AdapterCaps caps = dev->GetAdapterCaps(); @@ -360,7 +360,7 @@ int main() { cm::ScanScheduler sched(cfg); /* --- RX loop on a worker thread (rxdemo sweep pattern) --- */ - IRtlDevice *devp = dev; + IRadio *devp = dev; const cm::ScanScheduler::DwellPlan first = sched.next(steady_ms()); std::thread rx([devp, first, &logger]() { try { diff --git a/examples/chipstate/main.cpp b/examples/chipstate/main.cpp index 8753eb5b..9e4e631e 100644 --- a/examples/chipstate/main.cpp +++ b/examples/chipstate/main.cpp @@ -37,7 +37,7 @@ #include #include "DeviceSession.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "RtlAdapter.h" #include "UsbOpen.h" #include "WiFiDriver.h" @@ -140,7 +140,7 @@ bool parse_poke(const char *s, RegOp &op) { } /* Raw register client over the transport layer — deliberately below - * CreateRtlDevice so it works on any die, configured or not. */ + * CreateRadio so it works on any die, configured or not. */ int run_reg_ops(libusb_device_handle *handle, Logger_t logger, libusb_context *ctx, std::shared_ptr lock, @@ -290,13 +290,13 @@ int main(int argc, char **argv) { * very state it exists to inspect — one look and the evidence is gone. */ cfg.tuning.teardown_power_down = false; WiFiDriver driver(logger); - std::unique_ptr owned = driver.CreateRtlDevice(handle, ctx, lock, cfg); + std::unique_ptr owned = driver.CreateRadio(handle, ctx, lock, cfg); if (!owned) { - logger->error("CreateRtlDevice failed (chip support not built?)"); + logger->error("CreateRadio failed (chip support not built?)"); return 3; } session.adopt_device(std::move(owned)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); if (a.init) { logger->info("chipstate: --init, running a full bring-up before the dump"); diff --git a/examples/common/DeviceSession.h b/examples/common/DeviceSession.h index adb3e92a..a9a9f42c 100644 --- a/examples/common/DeviceSession.h +++ b/examples/common/DeviceSession.h @@ -6,7 +6,7 @@ * The caller owns libusb (see the architecture note in CLAUDE.md), which means * the caller also owns the order things die in. That order is not arbitrary: * - * 1. destroy the IRtlDevice — quiesces TX (cancels and reaps the in-flight + * 1. destroy the IRadio — quiesces TX (cancels and reaps the in-flight * bulk-OUT URBs) and drops the transport, all * while the libusb context is still valid; * 2. libusb_release_interface — the chip is no longer being driven; @@ -30,7 +30,7 @@ #include -#include "IRtlDevice.h" +#include "IRadio.h" #include "UsbDeviceLock.h" #include "UsbOpen.h" /* find_wifi_interface — the interface the claim used */ #include "logger.h" @@ -59,11 +59,11 @@ class DeviceSession { void adopt_lock(std::shared_ptr lock) { _lock = std::move(lock); } - void adopt_device(std::unique_ptr dev) { _dev = std::move(dev); } + void adopt_device(std::unique_ptr dev) { _dev = std::move(dev); } libusb_context *context() const { return _ctx; } libusb_device_handle *handle() const { return _handle; } - IRtlDevice *device() const { return _dev.get(); } + IRadio *device() const { return _dev.get(); } const std::shared_ptr &lock() const { return _lock; } /* Explicit teardown for demos that have work to do after the adapter is @@ -90,7 +90,7 @@ class DeviceSession { private: Logger_t _logger; - std::unique_ptr _dev; + std::unique_ptr _dev; std::shared_ptr _lock; libusb_device_handle *_handle = nullptr; libusb_context *_ctx = nullptr; diff --git a/examples/common/caps_event.h b/examples/common/caps_event.h index f7ed0553..97583ce1 100644 --- a/examples/common/caps_event.h +++ b/examples/common/caps_event.h @@ -1,9 +1,9 @@ /* Shared `adapter.caps` machine-event emitter for the demos. * - * One place that serializes IRtlDevice::GetAdapterCaps() (src/AdapterCaps.h) to + * One place that serializes IRadio::GetAdapterCaps() (src/AdapterCaps.h) to * the JSONL event plane so rxdemo / txdemo / doctor / txpower all emit the same * schema — a dependent app or test script consumes one event instead of calling - * the C++ API. Emit it right after CreateRtlDevice (the caps are static and + * the C++ API. Emit it right after CreateRadio (the caps are static and * resolved at construction — no bring-up needed). Mirrors the txpwr.caps * emission in examples/txpower/main.cpp: booleans as 0/1, chip_id as a hex * string, bandwidths + frequency spans as arrays (absent band -> null). */ @@ -12,11 +12,11 @@ #include "AdapterCaps.h" #include "Event.h" -#include "IRtlDevice.h" +#include "IRadio.h" namespace devourer { -inline void emit_adapter_caps(EventSink &sink, IRtlDevice *dev) { +inline void emit_adapter_caps(EventSink &sink, IRadio *dev) { const AdapterCaps c = dev->GetAdapterCaps(); /* Supported channel widths as an MHz int array (kBw* -> MHz). */ diff --git a/examples/common/env_config.h b/examples/common/env_config.h index cfe7f73e..6d3d7f78 100644 --- a/examples/common/env_config.h +++ b/examples/common/env_config.h @@ -3,7 +3,7 @@ /* DEVOURER_* environment-variable interface of the example binaries. * * The library is configured through devourer::DeviceConfig (see - * src/DeviceConfig.h) and runtime setters on IRtlDevice; it reads no env vars. + * src/DeviceConfig.h) and runtime setters on IRadio; it reads no env vars. * The demos — and the test scripts driving them — speak env vars, and this * translator is where that mapping lives: every library-level DEVOURER_* var * becomes a DeviceConfig field (devourer_config_from_env). Demo-local vars diff --git a/examples/doctor/main.cpp b/examples/doctor/main.cpp index 589b0acb..c28769be 100644 --- a/examples/doctor/main.cpp +++ b/examples/doctor/main.cpp @@ -229,16 +229,16 @@ int main(int argc, char **argv) { cfg.rx.enable_with_tx = true; WiFiDriver driver(logger); - std::unique_ptr owned_device = - driver.CreateRtlDevice(handle, ctx, lock, cfg); + std::unique_ptr owned_device = + driver.CreateRadio(handle, ctx, lock, cfg); if (!owned_device) { - logger->error("CreateRtlDevice failed (chip support not built?)"); + logger->error("CreateRadio failed (chip support not built?)"); return 3; } /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); devourer::emit_adapter_caps(logger->events(), dev); diff --git a/examples/duplex/main.cpp b/examples/duplex/main.cpp index 7c005ff3..23f560fb 100644 --- a/examples/duplex/main.cpp +++ b/examples/duplex/main.cpp @@ -295,7 +295,7 @@ static void packet_processor(const Packet &packet) { } struct TxArgs { - class IRtlDevice *rtl; // unique_ptr lives in main(); raw ptr OK while + class IRadio *rtl; // unique_ptr lives in main(); raw ptr OK while // we join() before that unique_ptr goes away int interval_ms; size_t max_psdu; @@ -483,12 +483,12 @@ int main(int argc, char **argv) { session.adopt_lock(usb_lock); WiFiDriver wifi_driver{logger}; - auto owned_device = wifi_driver.CreateRtlDevice(handle, nullptr, usb_lock, + auto owned_device = wifi_driver.CreateRadio(handle, nullptr, usb_lock, devourer_config_from_env()); /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const rtlDevice = session.device(); + IRadio *const rtlDevice = session.device(); int channel = 6; if (const char *ch_env = std::getenv("DEVOURER_CHANNEL")) { diff --git a/examples/dwelltx/main.cpp b/examples/dwelltx/main.cpp index d65e0625..b286ae08 100644 --- a/examples/dwelltx/main.cpp +++ b/examples/dwelltx/main.cpp @@ -135,13 +135,13 @@ int main() { WiFiDriver driver{logger}; auto cfg = devourer_config_from_env(); // honors DEVOURER_FASTRETUNE_FW - auto owned_device = driver.CreateRtlDevice(handle, nullptr, usb_lock, cfg); + auto owned_device = driver.CreateRadio(handle, nullptr, usb_lock, cfg); if (!owned_device) return 1; // The session owns the device from here: it is what guarantees the device // (and its in-flight TX) dies before libusb does. session.adopt_device(std::move(owned_device)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); // --- schedule + admission parameters --------------------------------------- std::vector chans; diff --git a/examples/precoder/main.cpp b/examples/precoder/main.cpp index 810a0caa..965bcb90 100644 --- a/examples/precoder/main.cpp +++ b/examples/precoder/main.cpp @@ -219,12 +219,12 @@ int main(int argc, char **argv) { session.adopt_lock(usb_lock); WiFiDriver wifi_driver{logger}; - auto owned_device = wifi_driver.CreateRtlDevice(handle, nullptr, usb_lock, + auto owned_device = wifi_driver.CreateRadio(handle, nullptr, usb_lock, devourer_config_from_env()); /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const rtlDevice = session.device(); + IRadio *const rtlDevice = session.device(); // 2.4 GHz channel 6 is the plan's matrix-validated cell for these chips. int channel = 6; diff --git a/examples/rx/main.cpp b/examples/rx/main.cpp index 9216a2f5..19911464 100644 --- a/examples/rx/main.cpp +++ b/examples/rx/main.cpp @@ -135,7 +135,7 @@ static std::atomic g_hopset_now_slot{0}; * this same claimed handle (one bring-up, RX loop + occasional control TX), * which is the reserved low-rate feedback opportunity. */ static std::unique_ptr g_hopset_policy; -static IRtlDevice *g_hopset_dev = nullptr; +static IRadio *g_hopset_dev = nullptr; static bool g_hopset_verbose_events = false; /* Per-dwell frame accounting, written lock-free from the RX worker and read * by the hop loop when the slot closes. */ @@ -455,10 +455,10 @@ static bool parse_la_spec(const char *spec, devourer::LaParams &p) { } /* Dispatch la_capture to whichever generation this device is (research - * helpers are concrete-type methods, not on IRtlDevice). Returns an + * helpers are concrete-type methods, not on IRadio). Returns an * empty function when the generation has no LA support wired yet. */ static std::function -la_runner_for(IRtlDevice *dev) { +la_runner_for(IRadio *dev) { #if defined(DEVOURER_HAVE_JAGUAR1) if (auto *j1 = dynamic_cast(dev)) return [j1](const devourer::LaParams &p) { return j1->la_capture(p); }; @@ -532,7 +532,7 @@ static void run_la_capture( /* DEVOURER_RX_ENERGY_MS=N: periodic frame-free RX energy / channel-busy * telemetry — the read side of DEVOURER_CW_TONE. Each interval emits one * rx.energy event combining the chip's phydm FA/CCA counters + IGI - * (IRtlDevice::GetRxEnergy, frame-free, all three generations) with a rolling + * (IRadio::GetRxEnergy, frame-free, all three generations) with a rolling * per-frame RSSI/SNR aggregate. A second adapter running this detects the first * adapter's CW carrier as a jump in cca_ofdm / fa_ofdm and a rise in igi. * 0 = disabled. */ @@ -694,7 +694,7 @@ static const bool g_rx_pctr = []() { return e != nullptr && std::strcmp(e, "0") != 0; }(); -/* Emit the frame-free NHM power histogram (IRtlDevice::GetRxEnergy fills it) as +/* Emit the frame-free NHM power histogram (IRadio::GetRxEnergy fills it) as * a distinct rx.nhm event so it never disturbs the rx.energy * fields its consumers key on. `peak` = the fullest bucket (0 = quiet * noise floor, higher = energy is landing in a higher power band, e.g. under an @@ -1276,7 +1276,7 @@ int main(int argc, char **argv) { .f("stage", "demo.open_device") .f("ms", ms_since_start()); WiFiDriver wifi_driver(logger); - auto owned_device = wifi_driver.CreateRtlDevicePcie( + auto owned_device = wifi_driver.CreateRadioPcie( std::move(transport), devourer_config_from_env()); if (!owned_device) { logger->error("No driver for this PCIe chip in this build — exiting"); @@ -1285,7 +1285,7 @@ int main(int argc, char **argv) { /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before the transport behind it. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); devourer::Ev(*g_ev, "init.timing") .f("stage", "demo.create_device") .f("ms", ms_since_start()); @@ -1431,7 +1431,7 @@ int main(int argc, char **argv) { session.adopt_lock(usb_lock); WiFiDriver wifi_driver(logger); - auto owned_device = wifi_driver.CreateRtlDevice(dev_handle, ctx, usb_lock, + auto owned_device = wifi_driver.CreateRadio(dev_handle, ctx, usb_lock, devourer_config_from_env()); if (!owned_device) { /* The factory returns null when the plugged chip's generation wasn't @@ -1442,7 +1442,7 @@ int main(int argc, char **argv) { /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const rtlDevice = session.device(); + IRadio *const rtlDevice = session.device(); devourer::Ev(*g_ev, "init.timing") .f("stage", "demo.create_device") .f("ms", ms_since_start()); @@ -1490,7 +1490,7 @@ int main(int argc, char **argv) { } } /* The BB-debug-port / queue-depth research helpers are Jaguar1-only, so - * they live on RtlJaguarDevice rather than the IRtlDevice interface. The + * they live on RtlJaguarDevice rather than the IRadio interface. The * whole block compiles out when Jaguar1 support isn't built; when it is, the * dynamic_cast yields nullptr for a Jaguar3 device, disabling them cleanly. */ #if defined(DEVOURER_HAVE_JAGUAR1) @@ -1524,7 +1524,7 @@ int main(int argc, char **argv) { } #endif /* DEVOURER_HAVE_JAGUAR1 */ - /* Cross-generation thermal telemetry. GetThermalStatus is part of IRtlDevice + /* Cross-generation thermal telemetry. GetThermalStatus is part of IRadio * (Jaguar1/2/3, Kestrel, and RTL8733B); using the base pointer is what makes * DEVOURER_THERMAL_POLL_MS work on RTL8812EU and newer backends instead of * silently becoming Jaguar1-only. Emit + warn only — see the knob's comment @@ -1534,7 +1534,7 @@ int main(int argc, char **argv) { if (g_thermal_poll_ms > 0) { logger->info("DEVOURER_THERMAL_POLL_MS={} warn_delta={} — starting thermal " "poller", g_thermal_poll_ms, g_thermal_warn_delta); - IRtlDevice *dev = rtlDevice; + IRadio *dev = rtlDevice; therm_emitter = std::thread([&therm_emitter_stop, dev, logger]() { bool warned = false; while (!therm_emitter_stop.load()) { @@ -1566,7 +1566,7 @@ int main(int argc, char **argv) { } /* DEVOURER_RX_ENERGY_MS: frame-free RX energy / channel-busy telemetry — the - * read side of DEVOURER_CW_TONE. Cross-generation (IRtlDevice::GetRxEnergy), + * read side of DEVOURER_CW_TONE. Cross-generation (IRadio::GetRxEnergy), * so it runs off the base device pointer, not the Jaguar1 downcast. The thread * sleeps one interval first (so its first read lands after bring-up completes, * not mid-init), then each interval reads GetRxEnergy() + drains the rolling @@ -1578,7 +1578,7 @@ int main(int argc, char **argv) { if (g_rx_energy_ms > 0) { logger->info("DEVOURER_RX_ENERGY_MS={} — starting RX energy telemetry", g_rx_energy_ms); - IRtlDevice *dev = rtlDevice; + IRadio *dev = rtlDevice; energy_emitter = std::thread([&energy_emitter_stop, dev]() { auto nap = [&](uint32_t ms) { for (uint32_t s = 0; s < ms && !energy_emitter_stop.load(); s += 50) @@ -1897,7 +1897,7 @@ int main(int argc, char **argv) { if (acquire_ms < 1) acquire_ms = 1; } - IRtlDevice *dev = rtlDevice; + IRadio *dev = rtlDevice; SelectedChannel first{static_cast(hop_rx_channels[0]), ch_offset, width}; std::thread rx([dev, first, &logger]() { @@ -2066,7 +2066,7 @@ int main(int argc, char **argv) { if (!g_rx_sweep.empty()) { logger->info("DEVOURER_RX_SWEEP: {} bins, dwell {} ms — live spectrum map", g_rx_sweep.size(), g_rx_sweep_dwell_ms); - IRtlDevice *dev = rtlDevice; + IRadio *dev = rtlDevice; SelectedChannel first{static_cast(g_rx_sweep[0]), ch_offset, width}; std::thread rx([dev, first, &logger]() { try { diff --git a/examples/sense/main.cpp b/examples/sense/main.cpp index 983438d4..0f8381b2 100644 --- a/examples/sense/main.cpp +++ b/examples/sense/main.cpp @@ -337,7 +337,7 @@ struct Adapter { devourer::DeviceSession session; libusb_device_handle *handle() const { return session.handle(); } - IRtlDevice *dev() const { return session.device(); } + IRadio *dev() const { return session.device(); } }; /* Open one adapter by VID:PID on its own libusb context, claim + reset, and build @@ -368,7 +368,7 @@ static bool open_adapter(Adapter &a, uint16_t vid, uint16_t pid, a.session.adopt_lock(lock); WiFiDriver driver(logger); auto owned_device = - driver.CreateRtlDevice(handle, ctx, lock, devourer_config_from_env()); + driver.CreateRadio(handle, ctx, lock, devourer_config_from_env()); if (!owned_device) return false; a.session.adopt_device(std::move(owned_device)); diff --git a/examples/streamtx/main.cpp b/examples/streamtx/main.cpp index 06905d98..278ef3c9 100644 --- a/examples/streamtx/main.cpp +++ b/examples/streamtx/main.cpp @@ -226,14 +226,14 @@ int main(int argc, char **argv) { * it. Explicit DEVOURER_DIS_CCA=0 still forces standard carrier-sense back on. */ if (std::getenv("DEVOURER_DIS_CCA") == nullptr) stream_cfg.tuning.disable_cca = true; - auto owned_device = wifi_driver.CreateRtlDevice(handle, nullptr, usb_lock, + auto owned_device = wifi_driver.CreateRadio(handle, nullptr, usb_lock, stream_cfg); /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const rtlDevice = session.device(); + IRadio *const rtlDevice = session.device(); /* Jaguar1-only research features (TXAGC override, fast-retune hopping) aren't - * on the IRtlDevice contract — downcast for them; jag is null on Jaguar3, and + * on the IRadio contract — downcast for them; jag is null on Jaguar3, and * the downcast plus its call sites compile out when Jaguar1 isn't built. */ #if defined(DEVOURER_HAVE_JAGUAR1) RtlJaguarDevice *jag = dynamic_cast(rtlDevice); @@ -265,7 +265,7 @@ int main(int argc, char **argv) { * corrupted-frame salvage path gets exercised (pairs with the B210 interferer * in tests/fused_fec_onair.sh). Applied once and held, unlike * txdemo's DEVOURER_TX_PWR_START ramp. Must follow InitWrite so it - * applies live. Generation-agnostic (IRtlDevice runtime TX-power API). */ + * applies live. Generation-agnostic (IRadio runtime TX-power API). */ if (const char *o = std::getenv("DEVOURER_TX_PWR_OVERRIDE")) { int idx = std::atoi(o); rtlDevice->SetTxPowerIndexOverride(idx); diff --git a/examples/svctx/main.cpp b/examples/svctx/main.cpp index d957aa4a..13fc947d 100644 --- a/examples/svctx/main.cpp +++ b/examples/svctx/main.cpp @@ -172,12 +172,12 @@ int main(int argc, char** argv) { session.adopt_lock(usb_lock); WiFiDriver wifi_driver{logger}; - auto owned_device = wifi_driver.CreateRtlDevice(handle, nullptr, usb_lock, + auto owned_device = wifi_driver.CreateRadio(handle, nullptr, usb_lock, devourer_config_from_env()); /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const rtlDevice = session.device(); + IRadio *const rtlDevice = session.device(); int channel = 6; if (const char* ch = std::getenv("DEVOURER_CHANNEL")) channel = std::atoi(ch); diff --git a/examples/tdma/main.cpp b/examples/tdma/main.cpp index 59531096..9973ef6f 100644 --- a/examples/tdma/main.cpp +++ b/examples/tdma/main.cpp @@ -102,7 +102,7 @@ static libusb_device_handle* open_device( } // --- TX role ---------------------------------------------------------------- -static void run_tx(IRtlDevice* dev, const tdma::Config& c) { +static void run_tx(IRadio* dev, const tdma::Config& c) { dev->InitWrite(SelectedChannel{c.channel, 0, CHANNEL_WIDTH_20}); std::this_thread::sleep_for(std::chrono::seconds(2)); const auto rt_crit = devourer::build_stream_radiotap(c.crit_rate); @@ -225,7 +225,7 @@ static ChannelWidth_t desired_width(const tdma::Config& c) { return pos < c.sched.nb_ms ? c.sched.nb_w : c.sched.wide_w; } -static void run_rx(IRtlDevice* dev, const tdma::Config& c) { +static void run_rx(IRadio* dev, const tdma::Config& c) { // Bring RX up: rx-camp at its band; rx-sync wide (the control loop corrects). ChannelWidth_t start_w = c.role == tdma::Role::RxCamp ? c.camp_w : CHANNEL_WIDTH_20; g_rx_mhz.store(tdma::mhz_of(start_w)); @@ -320,12 +320,12 @@ int main() { WiFiDriver wifi(logger); auto owned_device = - wifi.CreateRtlDevice(handle, ctx, lock, devourer_config_from_env()); + wifi.CreateRadio(handle, ctx, lock, devourer_config_from_env()); if (!owned_device) { logger->error("no driver for this chip"); return 1; } // The session owns the device from here: it is what guarantees the device // (and its in-flight TX) dies before libusb does. session.adopt_device(std::move(owned_device)); - IRtlDevice* const dev = session.device(); + IRadio* const dev = session.device(); if (c.role == tdma::Role::Tx) run_tx(dev, c); else run_rx(dev, c); diff --git a/examples/tdma/tdma.h b/examples/tdma/tdma.h index 583c63f0..eb5b803b 100644 --- a/examples/tdma/tdma.h +++ b/examples/tdma/tdma.h @@ -5,7 +5,7 @@ // The idea (see docs/narrowband.md, "Burst-level bandwidth TDMA"): a transmitter // alternates BURSTS between a robust narrowband width (5/10 MHz — ~6 dB link // budget, for critical frames) and a wide width (20/40 MHz — throughput, for -// bulk frames), flipping bandwidth with the cheap IRtlDevice::FastSetBandwidth. +// bulk frames), flipping bandwidth with the cheap IRadio::FastSetBandwidth. // Narrowband is an ADC-clock-domain state, not a per-packet radiotap field, and // a receiver decodes exactly one width at a time — so the scheme is inherently // burst-level and the hard part is schedule synchronization. diff --git a/examples/timesync/main.cpp b/examples/timesync/main.cpp index 1cdd531b..16bba5c8 100644 --- a/examples/timesync/main.cpp +++ b/examples/timesync/main.cpp @@ -122,7 +122,7 @@ static std::vector build_std_beacon(int interval_tu) { 0x01, 0x01, 0x82}; // supported rates (1M) } -static void run_master(IRtlDevice* dev, const timesync::Config& c) { +static void run_master(IRadio* dev, const timesync::Config& c) { dev->InitWrite(SelectedChannel{c.channel, 0, CHANNEL_WIDTH_20}); sleep_ms(2000); if (c.hwbeacon) { @@ -230,7 +230,7 @@ static void slave_cb(const Packet& p) { g_fit.add(local_us, master_us); } -static void run_slave(IRtlDevice* dev, const timesync::Config& c) { +static void run_slave(IRadio* dev, const timesync::Config& c) { std::thread rx([&] { dev->Init(slave_cb, SelectedChannel{c.channel, 0, CHANNEL_WIDTH_20}); }); @@ -303,7 +303,7 @@ static void master_ta_cb(const Packet& p) { emit(buf); } -static void run_master_ta(IRtlDevice* dev, const timesync::Config& c) { +static void run_master_ta(IRadio* dev, const timesync::Config& c) { g_slot_us = c.slot_ms * 1000.0; g_ta_gain = c.ta_gain; if (const char* f = std::getenv("DEVOURER_TSYNC_TA_FIXED")) { g_ta_fixed = true; g_ta_us.store(std::atof(f)); // authority test: hold TA constant @@ -360,7 +360,7 @@ static void ue_cb(const Packet& p) { } } -static void run_ue(IRtlDevice* dev, const timesync::Config& c) { +static void run_ue(IRadio* dev, const timesync::Config& c) { dev->InitWrite(SelectedChannel{c.channel, 0, CHANNEL_WIDTH_20}); std::thread rx([&] { dev->StartRxLoop(ue_cb); }); sleep_ms(2000); @@ -487,7 +487,7 @@ int main() { g_hwbeacon = c.hwbeacon; // slave reads the standard 802.11 beacon timestamp WiFiDriver wifi(logger); - std::unique_ptr owned_device; + std::unique_ptr owned_device; libusb_context* ctx = nullptr; /* DEVOURER_PCIE_BDF=0000:01:00.0 — drive a PCIe adapter (RTL8821CE) through * the vfio transport instead of libusb (DEVOURER_PCIE builds; mirrors the @@ -499,7 +499,7 @@ int main() { auto transport = devourer::PcieTransport::Open(pcie_bdf, logger); if (!transport) return 1; owned_device = - wifi.CreateRtlDevicePcie(std::move(transport), devourer_config_from_env()); + wifi.CreateRadioPcie(std::move(transport), devourer_config_from_env()); } else #endif { @@ -514,13 +514,13 @@ int main() { session.adopt_handle(handle, devourer::find_wifi_interface(handle)); session.adopt_lock(lock); owned_device = - wifi.CreateRtlDevice(handle, ctx, lock, devourer_config_from_env()); + wifi.CreateRadio(handle, ctx, lock, devourer_config_from_env()); } if (!owned_device) { logger->error("no driver for this chip"); return 1; } // The session owns the device from here: it is what guarantees the device // (and its in-flight TX) dies before libusb does. session.adopt_device(std::move(owned_device)); - IRtlDevice* const dev = session.device(); + IRadio* const dev = session.device(); if (c.role == timesync::Role::Ue) run_ue(dev, c); else if (c.role == timesync::Role::Master && c.uplink) run_master_ta(dev, c); diff --git a/examples/tx/main.cpp b/examples/tx/main.cpp index d027330a..3840fb1f 100644 --- a/examples/tx/main.cpp +++ b/examples/tx/main.cpp @@ -147,7 +147,7 @@ static std::mutex g_hopset_mu; static std::optional g_hopset_keys; static std::optional g_hopset_auth; static std::optional g_hopset_view; -static IRtlDevice *g_hopset_dev = nullptr; +static IRadio *g_hopset_dev = nullptr; static std::atomic g_hopset_tick_slot{0}; /* Quiet-window sensing (DEVOURER_TX_SENSE=1) and the fusion layer that decides * whether this side's own evidence may act on the schedule. */ @@ -221,7 +221,7 @@ static void hopset_route( * * window_us is measured, not nominal — the hardware keeps counting during the * read's own bus round-trips, so excluding that time would inflate the rate. */ -static bool hopset_sense_window(IRtlDevice *dev, uint32_t settle_us, +static bool hopset_sense_window(IRadio *dev, uint32_t settle_us, uint32_t window_us, bool with_nhm, devourer::hopset::SensePhase phase, uint64_t slot, uint64_t round, @@ -762,7 +762,7 @@ int main(int argc, char **argv) { } WiFiDriver wifi_driver{logger}; - std::unique_ptr owned_device; + std::unique_ptr owned_device; #if defined(DEVOURER_HAVE_PCIE) if (pcie_bdf) { auto transport = devourer::PcieTransport::Open(pcie_bdf, logger); @@ -771,7 +771,7 @@ int main(int argc, char **argv) { devourer::Ev(*g_ev, "init.timing") .f("stage", "txdemo.open_device") .f("ms", ms_since_start()); - owned_device = wifi_driver.CreateRtlDevicePcie(std::move(transport), + owned_device = wifi_driver.CreateRadioPcie(std::move(transport), devourer_config_from_env()); } else #endif @@ -780,7 +780,7 @@ int main(int argc, char **argv) { logger->error("DEVOURER_PCIE_BDF set but this build has DEVOURER_PCIE=OFF"); return 1; } - owned_device = wifi_driver.CreateRtlDevice(handle, nullptr, usb_lock, + owned_device = wifi_driver.CreateRadio(handle, nullptr, usb_lock, devourer_config_from_env()); } if (!owned_device) { @@ -792,7 +792,7 @@ int main(int argc, char **argv) { /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const rtlDevice = session.device(); + IRadio *const rtlDevice = session.device(); devourer::Ev(*g_ev, "init.timing") .f("stage", "txdemo.create_device") .f("ms", ms_since_start()); @@ -800,7 +800,7 @@ int main(int argc, char **argv) { /* Jaguar1-only research features (TX-mode default, fast-retune hopping, * thermal telemetry, TXAGC override, BB-reg probe) are not part of the - * IRtlDevice contract — reach them by downcasting. jag is null on Jaguar3, + * IRadio contract — reach them by downcasting. jag is null on Jaguar3, * where those call sites are skipped, and compiled out entirely when Jaguar1 * support isn't built. */ #if defined(DEVOURER_HAVE_JAGUAR1) @@ -1066,7 +1066,7 @@ int main(int argc, char **argv) { * default apply; a frame embedding its own rate radiotap overrides it per * packet. Default (no env) = 6 M legacy. Replaces the former per-knob * DEVOURER_TX_MCS/_VHT/_LDPC/_STBC/_BW env vars + the DEVOURER_TX_HT_MCS gate. */ - /* TX-mode default (DEVOURER_TX_RATE) — now a first-class IRtlDevice feature so + /* TX-mode default (DEVOURER_TX_RATE) — now a first-class IRadio feature so * it applies to Jaguar3 (8822CU/EU) too. The demo's beacon is rate-less, so * without this its Jaguar3 TX fell back to MGN_1M (1 Mbps) regardless of * DEVOURER_TX_RATE. Per-packet radiotap still overrides. */ @@ -1991,7 +1991,7 @@ int main(int argc, char **argv) { mode = "radiotap"; } else if (hop_fast) { - /* IRtlDevice virtual: every generation implements the lean fast path + /* IRadio virtual: every generation implements the lean fast path * (cached RF18 write + on-change constants, with the internal * band-change fallback to the full set). */ rtlDevice->FastRetune(static_cast(ch), diff --git a/examples/txpower/main.cpp b/examples/txpower/main.cpp index dfeb5ff4..d9355238 100644 --- a/examples/txpower/main.cpp +++ b/examples/txpower/main.cpp @@ -209,7 +209,7 @@ ChannelWidth_t bw_enum(int bw) { } } -void print_state(IRtlDevice *dev, bool with_thermal) { +void print_state(IRadio *dev, bool with_thermal) { const devourer::TxPowerState s = dev->GetTxPowerState(); devourer::Ev(*g_ev, "txpwr.state") .f("flat", s.flat_index) @@ -286,16 +286,16 @@ int main(int argc, char **argv) { session.adopt_lock(lock); WiFiDriver driver(logger); - std::unique_ptr owned_device = - driver.CreateRtlDevice(handle, ctx, lock, devourer_config_from_env()); + std::unique_ptr owned_device = + driver.CreateRadio(handle, ctx, lock, devourer_config_from_env()); if (!owned_device) { - logger->error("CreateRtlDevice failed (chip support not built?)"); + logger->error("CreateRadio failed (chip support not built?)"); return 1; } /* The session owns the device from here: it is what guarantees the device * (and its in-flight TX) dies before libusb does. */ session.adopt_device(std::move(owned_device)); - IRtlDevice *const dev = session.device(); + IRadio *const dev = session.device(); devourer::emit_adapter_caps(*g_ev, dev); diff --git a/src/AdapterCaps.h b/src/AdapterCaps.h index 50d8144e..6aea9af9 100644 --- a/src/AdapterCaps.h +++ b/src/AdapterCaps.h @@ -11,7 +11,7 @@ * there is one source of truth per fact. Like those, it is STATIC — resolved at * construction, safe from any thread, callable before Init/InitWrite. The live * "which antennas look connected" question is deliberately NOT here (it needs - * traffic); see IRtlDevice::GetActiveRxPaths / ActiveRxPaths in RxQuality.h. + * traffic); see IRadio::GetActiveRxPaths / ActiveRxPaths in RxQuality.h. * * FREQUENCY COVERAGE. The 5 GHz synthesizer on these parts tunes well past the * regulatory UNII channels (the vendor rtl88x2bu "monitor_chan_override" hack: diff --git a/src/AdapterHealth.h b/src/AdapterHealth.h index f4965e2a..1b22569f 100644 --- a/src/AdapterHealth.h +++ b/src/AdapterHealth.h @@ -16,7 +16,7 @@ * validity, the firmware-boot outcome of the last bring-up, and an RX smoke * count. The classifier maps those to a plain verdict + reason bits. * - * IRtlDevice carries the probe entry points (ProbeEfuseStability, + * IRadio carries the probe entry points (ProbeEfuseStability, * GetFwBootStatus); examples/doctor is the reference consumer. */ #ifndef DEVOURER_ADAPTER_HEALTH_H @@ -46,7 +46,7 @@ struct EfuseStability { uint16_t first_mismatch_off = 0xFFFF; /* first differing offset, if any */ }; -/* Shared probe loop behind IRtlDevice::ProbeEfuseStability — each generation +/* Shared probe loop behind IRadio::ProbeEfuseStability — each generation * supplies its own fresh-physical-map reader as `read_map(uint8_t *buf)` * (return false on transport failure) and this does the cross-compare. */ template diff --git a/src/CfoTracker.h b/src/CfoTracker.h index 3344939a..2ee9872b 100644 --- a/src/CfoTracker.h +++ b/src/CfoTracker.h @@ -9,7 +9,7 @@ namespace devourer { /* Closed-loop carrier-frequency-offset tracker (issue #217). Ported from the * vendor phydm_cfo_tracking control law: accumulate the per-frame path-A CFO * tail from the RX phy-status, and on a periodic tick step the crystal-cap - * trim (IRtlDevice::SetXtalCap) by ±1 to drive the average CFO toward zero. + * trim (IRadio::SetXtalCap) by ±1 to drive the average CFO toward zero. * * A bang-bang integrator with hysteresis: it starts correcting once |CFO| * exceeds an enable threshold and stops inside a deadband, so it doesn't diff --git a/src/DeviceConfig.h b/src/DeviceConfig.h index daa4bfb3..c3d8971d 100644 --- a/src/DeviceConfig.h +++ b/src/DeviceConfig.h @@ -1,9 +1,9 @@ #pragma once /* DeviceConfig — construction-time configuration, passed to - * WiFiDriver::CreateRtlDevice (defaulted: CreateRtlDevice(handle) gives stock + * WiFiDriver::CreateRadio (defaulted: CreateRadio(handle) gives stock * behaviour). Fields are fixed for the device's lifetime; knobs that change - * mid-session are runtime setters on IRtlDevice / the concrete device classes + * mid-session are runtime setters on IRadio / the concrete device classes * (SetTxMode, SetTxPowerOffsetQdb, SetRxPathMask, SetCcaMode, ...). * * The example binaries populate this from DEVOURER_* environment variables via @@ -403,7 +403,7 @@ struct DeviceConfig { * (stub default 0xa/0xb). */ std::optional nb_adc; /* env: DEVOURER_XTAL_CAP — crystal-cap trim code applied at the end of - * bring-up (IRtlDevice::SetXtalCap). The CFO lever for narrowband at the + * bring-up (IRadio::SetXtalCap). The CFO lever for narrowband at the * edge of its budget; unset = efuse/default. Raw code, 0..0x3f (Jaguar1/2) * or 0..0x7f (Jaguar3). */ std::optional xtal_cap; diff --git a/src/IRtlDevice.h b/src/IRadio.h similarity index 99% rename from src/IRtlDevice.h rename to src/IRadio.h index 179affda..61561b88 100644 --- a/src/IRtlDevice.h +++ b/src/IRadio.h @@ -1,5 +1,5 @@ -#ifndef IRTL_DEVICE_H -#define IRTL_DEVICE_H +#ifndef IRADIO_H +#define IRADIO_H #include #include @@ -35,7 +35,7 @@ struct TxPacketView { size_t len; }; -/* IRtlDevice is the chip-family-agnostic device contract used by the demos and +/* IRadio is the chip-family-agnostic device contract used by the demos and * the WiFiDriver factory. The production family implementations are: * - RtlJaguarDevice — Realtek "Jaguar" wave-1 (8812AU/8811AU/8821AU/8814AU) * - RtlJaguar2Device — Realtek "Jaguar2" (8822BU/8812BU) @@ -46,9 +46,9 @@ struct TxPacketView { * Chip-family-specific research helpers (BB-debug-port reads, the 8814 queue * poller, ...) are intentionally NOT part of this interface — callers that need * them dynamic_cast down to the concrete type. */ -class IRtlDevice { +class IRadio { public: - virtual ~IRtlDevice() = default; + virtual ~IRadio() = default; virtual void Init(Action_ParsedRadioPacket packetProcessor, SelectedChannel channel) = 0; @@ -198,7 +198,7 @@ class IRtlDevice { * feature flags (per-packet TX power, narrowband, fast retune, per-chain * RSSI). Resolved at construction — safe from any thread and callable BEFORE * Init/InitWrite (the demos emit it as the `adapter.caps` event right after - * CreateRtlDevice). Default returns supported=false. */ + * CreateRadio). Default returns supported=false. */ virtual devourer::AdapterCaps GetAdapterCaps() { return {}; } /* Best-effort live estimate of which RX chains are actually carrying signal @@ -617,4 +617,4 @@ class IRtlDevice { virtual void DumpChipState() {} }; -#endif /* IRTL_DEVICE_H */ +#endif /* IRADIO_H */ diff --git a/src/PcieTransport.h b/src/PcieTransport.h index 2bae8327..2a3c4966 100644 --- a/src/PcieTransport.h +++ b/src/PcieTransport.h @@ -34,12 +34,12 @@ #include #include -#include "RtlTransport.h" +#include "Transport.h" #include "logger.h" namespace devourer { -class PcieTransport final : public IRtlTransport { +class PcieTransport final : public ITransport { public: /* TX queues, indexing _tx_rings. Order is fixed (ring register map). */ enum Queue : int { @@ -81,7 +81,7 @@ class PcieTransport final : public IRtlTransport { PcieTransport(const PcieTransport &) = delete; PcieTransport &operator=(const PcieTransport &) = delete; - /* ---- IRtlTransport: register plane (BAR2 MMIO) ---- */ + /* ---- ITransport: register plane (BAR2 MMIO) ---- */ bool is_usb() const override { return false; } uint8_t read8(uint16_t reg) override { return guarded_read(reg); } uint16_t read16(uint16_t reg) override { return guarded_read(reg); } @@ -98,7 +98,7 @@ class PcieTransport final : public IRtlTransport { return true; } - /* ---- IRtlTransport: frame plane (88xx BD rings) ---- */ + /* ---- ITransport: frame plane (88xx BD rings) ---- */ /* The ring is chosen from the tx-descriptor QSEL at buf[5] bits [4:0] * (identical position on every 88xx descriptor this library builds); the * `ep` hint is USB addressing and ignored. QSEL_BEACON -> BCN ring is the diff --git a/src/RtlAdapter.cpp b/src/RtlAdapter.cpp index 4640a988..190d9072 100644 --- a/src/RtlAdapter.cpp +++ b/src/RtlAdapter.cpp @@ -28,7 +28,7 @@ RtlAdapter::RtlAdapter(libusb_device_handle *dev_handle, Logger_t logger, init_from_transport(cfg); } -RtlAdapter::RtlAdapter(std::shared_ptr transport, +RtlAdapter::RtlAdapter(std::shared_ptr transport, Logger_t logger, const devourer::DeviceConfig &cfg) : _transport{std::move(transport)}, _logger{std::move(logger)} { init_from_transport(cfg); diff --git a/src/RtlAdapter.h b/src/RtlAdapter.h index ffb87656..74efa7f3 100644 --- a/src/RtlAdapter.h +++ b/src/RtlAdapter.h @@ -6,7 +6,7 @@ * via shared_ptr, so the transport — and with it the USB device lock or the * vfio fds + DMA rings — lives until the last copy dies). * - * The bus specifics live behind IRtlTransport (src/RtlTransport.h): USB = + * The bus specifics live behind ITransport (src/Transport.h): USB = * devourer::UsbTransport (libusb vendor-control registers + bulk endpoints), * PCIe = devourer::PcieTransport (BAR2 MMIO registers + 88xx DMA rings). The * adapter itself carries only bus-neutral chip helpers built on the register @@ -32,7 +32,7 @@ #endif #include "DeviceConfig.h" -#include "RtlTransport.h" +#include "Transport.h" #include "TxStats.h" #include "drv_types.h" #include "hal_com_reg.h" @@ -60,7 +60,7 @@ enum TxSele { }; class RtlAdapter { - std::shared_ptr _transport; + std::shared_ptr _transport; Logger_t _logger; /* USB-descriptor-derived facts (defaults on PCIe), mirrored at construction @@ -81,7 +81,7 @@ class RtlAdapter { std::shared_ptr usb_lock = nullptr, const devourer::DeviceConfig &cfg = {}); /* Any transport (the PCIe factory path; also the seam for future buses). */ - RtlAdapter(std::shared_ptr transport, + RtlAdapter(std::shared_ptr transport, Logger_t logger, const devourer::DeviceConfig &cfg = {}); bool is_usb() const { return _transport->is_usb(); } @@ -141,7 +141,7 @@ class RtlAdapter { } void bulk_clear_halt(uint8_t ep) { _transport->clear_halt(ep); } - /* Stop TX and wait out everything already submitted (IRtlTransport:: + /* Stop TX and wait out everything already submitted (ITransport:: * quiesce_tx). Must run while the caller's bus context is still alive — * the device Stop()/destructor does it, so callers rarely need this. */ void quiesce_tx() { _transport->quiesce_tx(); } @@ -158,7 +158,7 @@ class RtlAdapter { uint8_t efuse_OneByteRead(uint16_t addr, uint8_t *data); void phy_set_bb_reg(uint16_t regAddr, uint32_t bitMask, uint32_t data); - /* 32-bit-address register write (see IRtlTransport::write32_wide) — the + /* 32-bit-address register write (see ITransport::write32_wide) — the * halbb/halrf BB window lives at addr + 0x10000 (wIndex=1 over USB), out of * reach of the 16-bit rtw_write path. */ bool rtw_write32_wide(uint32_t addr, uint32_t value) { diff --git a/src/RtlUsbAdapter.h b/src/RtlUsbAdapter.h index 72273127..4d95284f 100644 --- a/src/RtlUsbAdapter.h +++ b/src/RtlUsbAdapter.h @@ -3,8 +3,8 @@ /* Compatibility shim. The class once named RtlUsbAdapter is now the * bus-neutral RtlAdapter (src/RtlAdapter.h); the USB wire specifics moved to - * devourer::UsbTransport (src/UsbTransport.h) behind the IRtlTransport seam - * (src/RtlTransport.h). Prefer RtlAdapter in new code. */ + * devourer::UsbTransport (src/UsbTransport.h) behind the ITransport seam + * (src/Transport.h). Prefer RtlAdapter in new code. */ #include "RtlAdapter.h" diff --git a/src/RxPacket.h b/src/RxPacket.h index f3d5e884..fcdf0e71 100644 --- a/src/RxPacket.h +++ b/src/RxPacket.h @@ -90,7 +90,7 @@ struct rx_pkt_attrib /* Path-A CFO tail from the OFDM phy-status (signed HW units; kHz = raw * * 2.5, phydm CFO_HW_RPT_2_KHZ). The carrier-frequency offset between this * receiver's crystal and the transmitter's — the closed-loop CFO tracker's - * input (see IRtlDevice::SetXtalCap). 0 when the phy-status carries none. */ + * input (see IRadio::SetXtalCap). 0 when the phy-status carries none. */ int8_t cfo_tail = 0; /* A-MPDU RX markers. paggr: this MPDU arrived inside an aggregated PPDU * (rx-desc PAGGR — 8812 dword1[15], same position in the halmac layout). diff --git a/src/RxSense.h b/src/RxSense.h index 1199ed70..32794e96 100644 --- a/src/RxSense.h +++ b/src/RxSense.h @@ -7,7 +7,7 @@ * side of the DEVOURER_CW_TONE emitter: a coarse "how much in-band energy / * channel activity is here" measurement that does NOT require receiving a frame. * - * Filled by IRtlDevice::GetRxEnergy() from the chip's phydm facilities: + * Filled by IRadio::GetRxEnergy() from the chip's phydm facilities: * - false-alarm (FA) + CCA (channel-busy) counters, * - the DIG initial-gain index (a noise-floor proxy), * - and, where triggered, the NHM in-band power histogram. diff --git a/src/Sounding.h b/src/Sounding.h index 23ca1c58..18b04e46 100644 --- a/src/Sounding.h +++ b/src/Sounding.h @@ -13,7 +13,7 @@ * NIC-firmware host-NDPA path is unwired in the vendor tree. So, like the * F2P_TEST command, this is a byte-exact command surface the shipped fw does not * act on. The path that actually puts a Trigger on the air on this firmware is - * host-injection (IRtlDevice::SendTrigger, src/TriggerTwt.h). See + * host-injection (IRadio::SendTrigger, src/TriggerTwt.h). See * docs/he-trigger-ul.md. * * These aggregates are devourer-native; the Kestrel HAL maps them onto the diff --git a/src/ThermalStatus.h b/src/ThermalStatus.h index 7ba89a24..3170a590 100644 --- a/src/ThermalStatus.h +++ b/src/ThermalStatus.h @@ -1,5 +1,5 @@ /* Chip thermal-meter snapshot, generation-agnostic (moved out of the Jaguar1 - * HAL when GetThermalStatus was promoted to IRtlDevice — the meter register + * HAL when GetThermalStatus was promoted to IRadio — the meter register * family (RF 0x42) and the efuse-baseline semantics are common to all three * generations, only the field layout and baseline source differ per family). */ diff --git a/src/RtlTransport.h b/src/Transport.h similarity index 97% rename from src/RtlTransport.h rename to src/Transport.h index 8afbb1ba..82c63154 100644 --- a/src/RtlTransport.h +++ b/src/Transport.h @@ -1,6 +1,6 @@ #pragma once -/* IRtlTransport — the bus seam. USB (libusb) and PCIe (vfio) are independent +/* ITransport — the bus seam. USB (libusb) and PCIe (vfio) are independent * transports implementing this one interface; RtlAdapter (the copyable value * type every HAL holds) owns a shared_ptr to one of them and forwards. Nothing * here depends on libusb or vfio. @@ -39,9 +39,9 @@ struct UsbLinkInfo { std::vector bulk_out_eps; /* descriptor order */ }; -class IRtlTransport { +class ITransport { public: - virtual ~IRtlTransport() = default; + virtual ~ITransport() = default; virtual bool is_usb() const = 0; diff --git a/src/TxPower.h b/src/TxPower.h index 9e1b0401..a17d1a48 100644 --- a/src/TxPower.h +++ b/src/TxPower.h @@ -1,6 +1,6 @@ /* Runtime TX-power control types for the adaptive link. * - * The TX-power lever has three knobs on IRtlDevice, all live (applied + * The TX-power lever has three knobs on IRadio, all live (applied * immediately on a brought-up chip, recorded and applied at InitWrite * otherwise) and all sticky across channel switches: * @@ -125,7 +125,7 @@ inline int txpkt_pwr_db_for_step(uint8_t step) { } /* Caller-supplied per-rate TX-power diffs (signed qdB vs the reference anchor), - * programmed by IRtlDevice::SetTxPowerRateDiffs. Motivating consumer: a + * programmed by IRadio::SetTxPowerRateDiffs. Motivating consumer: a * wall-equalized rate ladder — each rate parked a uniform margin below its * measured PA-compression wall. * diff --git a/src/UsbDeviceLock.h b/src/UsbDeviceLock.h index dea52bc0..788d804b 100644 --- a/src/UsbDeviceLock.h +++ b/src/UsbDeviceLock.h @@ -16,7 +16,7 @@ namespace devourer { * processes stuck in uninterruptible USB I/O that even `kill -9` won't clear). * A real OS serialises access to a device node; this gives devourer the same * guarantee at the library boundary — the second instance's acquisition fails, - * so `CreateRtlDevice` refuses instead of racing. + * so `CreateRadio` refuses instead of racing. * * LIFETIME: the lock is held for this object's lifetime and released * automatically when the owning process exits — normally, via SIGKILL, or on a diff --git a/src/UsbOpen.h b/src/UsbOpen.h index cb5f47b6..061751c5 100644 --- a/src/UsbOpen.h +++ b/src/UsbOpen.h @@ -29,7 +29,7 @@ int find_wifi_interface(libusb_device_handle *handle); * does not report BUSY, so the lock — not the claim — is what turns a * second devourer away there, and taking it up front means that second * process resets nothing. `out_lock` receives it; the caller must keep it - * alive for as long as it drives the adapter (hand it to CreateRtlDevice, + * alive for as long as it drives the adapter (hand it to CreateRadio, * which then does NOT re-acquire); * 2. detach an attached kernel driver on `iface`; * 3. set configuration 1 (a cold, never-kernel-configured chip sits in config diff --git a/src/UsbTransport.cpp b/src/UsbTransport.cpp index a357d1ea..4cf2aece 100644 --- a/src/UsbTransport.cpp +++ b/src/UsbTransport.cpp @@ -346,7 +346,7 @@ UsbTransport::~UsbTransport() { if (!_tx_shutdown.load(std::memory_order_acquire) && _tx_inflight.load(std::memory_order_acquire) > 0) _logger->error("USB transport destroyed with TX in flight — the owner " - "should quiesce (IRtlDevice::Stop) and release the device " + "should quiesce (IRadio::Stop) and release the device " "BEFORE libusb_close/libusb_exit; see the teardown order in " "examples/common/DeviceSession.h"); quiesce_tx(); @@ -810,7 +810,7 @@ void UsbTransport::transfer_callback(struct libusb_transfer *transfer) { } /* Cancel + drain, called while the caller's libusb context is still alive. - * See IRtlTransport::quiesce_tx for the contract. */ + * See ITransport::quiesce_tx for the contract. */ void UsbTransport::quiesce_tx() { if (_tx_shutdown.exchange(true, std::memory_order_acq_rel)) return; /* already quiesced (Stop() then the destructor) */ diff --git a/src/UsbTransport.h b/src/UsbTransport.h index bbf62cea..9bb02319 100644 --- a/src/UsbTransport.h +++ b/src/UsbTransport.h @@ -1,6 +1,6 @@ #pragma once -/* UsbTransport — the libusb implementation of IRtlTransport. Everything +/* UsbTransport — the libusb implementation of ITransport. Everything * USB-wire-specific that used to live inside the adapter is here: vendor * control transfers for the register plane, sync/async bulk-OUT TX with the * wedge (mid-stream stall) recovery and TX submission counters, the @@ -16,7 +16,7 @@ #include #include "DeviceConfig.h" -#include "RtlTransport.h" +#include "Transport.h" #include "logger.h" namespace devourer { @@ -29,7 +29,7 @@ class UsbDeviceLock; namespace devourer { -class UsbTransport final : public IRtlTransport { +class UsbTransport final : public ITransport { public: UsbTransport(libusb_device_handle *dev_handle, Logger_t logger, libusb_context *ctx = nullptr, diff --git a/src/WiFiDriver.cpp b/src/WiFiDriver.cpp index 2efbef0f..566bfa24 100644 --- a/src/WiFiDriver.cpp +++ b/src/WiFiDriver.cpp @@ -81,8 +81,8 @@ constexpr uint8_t kChipId8821C = 0x09; WiFiDriver::WiFiDriver(Logger_t logger) : _logger{std::move(logger)} {} -std::unique_ptr -WiFiDriver::CreateRtlDevice(libusb_device_handle *dev_handle, +std::unique_ptr +WiFiDriver::CreateRadio(libusb_device_handle *dev_handle, libusb_context *ctx, std::shared_ptr usb_lock, const devourer::DeviceConfig &cfg) { @@ -274,11 +274,11 @@ WiFiDriver::CreateRtlDevice(libusb_device_handle *dev_handle, } #if defined(DEVOURER_HAVE_PCIE) -std::unique_ptr WiFiDriver::CreateRtlDevicePcie( +std::unique_ptr WiFiDriver::CreateRadioPcie( std::shared_ptr transport, const devourer::DeviceConfig &cfg) { if (!transport) { - _logger->error("CreateRtlDevicePcie: null transport"); + _logger->error("CreateRadioPcie: null transport"); return nullptr; } /* Chip identity from SYS_CFG2 (0x00FC) over BAR2 MMIO — the same dispatch diff --git a/src/WiFiDriver.h b/src/WiFiDriver.h index 2ebabe04..e832a333 100644 --- a/src/WiFiDriver.h +++ b/src/WiFiDriver.h @@ -4,7 +4,7 @@ #include #include "DeviceConfig.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "logger.h" struct libusb_device_handle; @@ -24,19 +24,19 @@ class WiFiDriver { /* Constructs the right device for the chip behind `dev_handle`: * RtlJaguarDevice for Jaguar wave-1 (8812/8811/8821/8814AU), the later * Jaguar/Kestrel backends, or the dedicated RTL8733B backend. Returns the - * common IRtlDevice interface. See CreateRtlDevice() for dispatch rules. + * common IRadio interface. See CreateRadio() for dispatch rules. * * `usb_lock` is the exclusive per-adapter lock. Pass the one returned by * devourer::claim_interface_then_reset (the recommended open path) so it is * held for the device lifetime and not re-acquired. When null (a caller that - * opened/claimed the handle itself), CreateRtlDevice acquires its own as a + * opened/claimed the handle itself), CreateRadio acquires its own as a * best-effort second gate, and returns nullptr if the adapter is already in * use. * * `cfg` is the construction-time configuration (see DeviceConfig.h); the * default gives stock behaviour. Fixed for the device's lifetime. */ - std::unique_ptr - CreateRtlDevice(libusb_device_handle *dev_handle, + std::unique_ptr + CreateRadio(libusb_device_handle *dev_handle, libusb_context *ctx = nullptr, std::shared_ptr usb_lock = nullptr, const devourer::DeviceConfig &cfg = {}); @@ -51,8 +51,8 @@ class WiFiDriver { * anything else logs and returns nullptr (same contract as an unsupported * chip on USB). No UsbDeviceLock: a vfio device fd is exclusive by * construction (a second open fails). */ - std::unique_ptr - CreateRtlDevicePcie(std::shared_ptr transport, + std::unique_ptr + CreateRadioPcie(std::shared_ptr transport, const devourer::DeviceConfig &cfg = {}); #endif }; diff --git a/src/jaguar1/RadioManagementModule.h b/src/jaguar1/RadioManagementModule.h index e2a5a9b8..e2b6fb99 100644 --- a/src/jaguar1/RadioManagementModule.h +++ b/src/jaguar1/RadioManagementModule.h @@ -56,7 +56,7 @@ enum RATE_SECTION { #include "RateDefinitions.h" /* ThermalStatus/ThermalBucket moved to the generation-agnostic - * src/ThermalStatus.h when GetThermalStatus was promoted to IRtlDevice; + * src/ThermalStatus.h when GetThermalStatus was promoted to IRadio; * the alias keeps the many existing Jaguar1 + demo references compiling * unchanged. */ #include "../ThermalStatus.h" @@ -123,7 +123,7 @@ class RadioManagementModule { /* Runtime TX-power offset in TXAGC index steps (0.5 dB each), folded onto * the per-rate baseline (EFUSE table or flat override) AFTER the per-rate * regulatory min and clamped only at the 6-bit rails — the relative knob - * behind IRtlDevice::SetTxPowerOffsetQdb. The saturation flags record + * behind IRadio::SetTxPowerOffsetQdb. The saturation flags record * whether the last apply hit a rail on any rate (reset per * PHY_SetTxPowerLevel8812 pass) — the "knob out of travel" signal for a * closed-loop controller. */ @@ -282,7 +282,7 @@ class RadioManagementModule { /* Read-only dump of the canary register set (BB / MAC / per-path RF) to the * diagnostic plane. Public because it is also the read-only inspection path - * for a chip that was never Init'ed — see IRtlDevice::DumpChipState. */ + * for a chip that was never Init'ed — see IRadio::DumpChipState. */ void DumpCanary(); private: diff --git a/src/jaguar1/RtlJaguarDevice.cpp b/src/jaguar1/RtlJaguarDevice.cpp index 4aa08181..7c9430ae 100644 --- a/src/jaguar1/RtlJaguarDevice.cpp +++ b/src/jaguar1/RtlJaguarDevice.cpp @@ -885,7 +885,7 @@ size_t RtlJaguarDevice::send_packets(const TxPacketView *pkts, size_t count) { * rules in src/TxAggPlan.h. Knob off -> the interface-default loop. */ const unsigned agg = _cfg.tx.usb_agg_max; if (agg <= 1 || !_device.is_usb() || count == 0) - return IRtlDevice::send_packets(pkts, count); + return IRadio::send_packets(pkts, count); devourer::TxAggLimits lim; lim.desc_size = TXDESC_SIZE; @@ -1989,7 +1989,7 @@ bool RtlJaguarDevice::NetDevOpen(SelectedChannel selectedChannel) { return true; } -/* Clean shutdown — see IRtlDevice::Stop. Quiesce TX first so the de-init writes +/* Clean shutdown — see IRadio::Stop. Quiesce TX first so the de-init writes * are not racing frames the transport still owns, then power the chip down. * * The power-down is the point: without it a Jaguar1 chip stays in ACT with its diff --git a/src/jaguar1/RtlJaguarDevice.h b/src/jaguar1/RtlJaguarDevice.h index 062d19dc..f2cfc6f7 100644 --- a/src/jaguar1/RtlJaguarDevice.h +++ b/src/jaguar1/RtlJaguarDevice.h @@ -15,7 +15,7 @@ #include "BbDbgportReader.h" #include "LaCapture.h" #include "HalModule.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "SelectedChannel.h" #include "EepromManager.h" #include "RadioManagementModule.h" @@ -28,7 +28,7 @@ extern "C" #include "ieee80211_radiotap.h" } -/* Action_ParsedRadioPacket is declared in IRtlDevice.h (shared with the +/* Action_ParsedRadioPacket is declared in IRadio.h (shared with the * Jaguar3 device and the factory). */ /* RtlJaguarDevice is the orchestrator for the Realtek "Jaguar" 802.11ac family @@ -36,7 +36,7 @@ extern "C" * baseband). The chip is identified at construction time via SYS_CFG bits and * USB PID; this class drives bring-up, RX, and TX for whichever member of the * family is present. */ -class RtlJaguarDevice : public IRtlDevice { +class RtlJaguarDevice : public IRadio { /* Declared before every component that consumes it: members initialise in * declaration order, and _eepromManager / _radioManagement / _halModule all * take _cfg in the constructor's init list. */ @@ -97,7 +97,7 @@ class RtlJaguarDevice : public IRtlDevice { ~RtlJaguarDevice() override; void Init(Action_ParsedRadioPacket packetProcessor, SelectedChannel channel) override; - /* Blocking RX worker loop on an already-brought-up chip (see IRtlDevice). + /* Blocking RX worker loop on an already-brought-up chip (see IRadio). * Init = bring-up + BFEE arm + StartRxLoop; a TX+RX caller does InitWrite * once, then runs this on its own std::thread next to the TX loop. */ void StartRxLoop(Action_ParsedRadioPacket packetProcessor) override; @@ -117,12 +117,12 @@ class RtlJaguarDevice : public IRtlDevice { * cache_rf=true additionally avoids the per-write 20 ms C-cut RF-read sleep * by writing RF_CHNLBW from a cached value. Intended for channel hopping; * keeps the device channel state in sync for the 5 GHz CCK clamp. - * (The cache_rf default binds at IRtlDevice — virtual default arguments + * (The cache_rf default binds at IRadio — virtual default arguments * resolve statically, so overrides must not re-declare it.) */ void FastRetune(uint8_t channel, bool cache_rf) override; void FastSetBandwidth(ChannelWidth_t bw) override; void InitWrite(SelectedChannel channel) override; - /* Legacy per-rate TXAGC override pair — superseded by the IRtlDevice + /* Legacy per-rate TXAGC override pair — superseded by the IRadio * runtime TX-power API (SetTxPowerIndexOverride applies in one call). * Inline forwards kept for one release cycle, Rtl8812aDevice-alias style. */ [[deprecated("use SetTxPowerIndexOverride (applies live)")]] @@ -135,7 +135,7 @@ class RtlJaguarDevice : public IRtlDevice { ReApplyTxPower(); } - /* Runtime TX-power control (IRtlDevice contract; see src/TxPower.h). + /* Runtime TX-power control (IRadio contract; see src/TxPower.h). * Jaguar1 caps: 6-bit TXAGC index, 0.5 dB (2 qdB) per step. The offset * folds into ComputeTxPowerIndex, so it reaches the per-rate TXAGC fanout * (0xc20..0xc4c / packed 0x1998 on 8814) AND the 0xc54 power-training @@ -173,11 +173,11 @@ class RtlJaguarDevice : public IRtlDevice { int SetXtalCap(int cap) override; int GetXtalCap() override { return _xtal_cap; } devourer::TxPowerState GetTxPowerState() override; - /* Per-chip TX caps (IRtlDevice): n_ss + STBC/LDPC/SGI/bw from the EFUSE + /* Per-chip TX caps (IRadio): n_ss + STBC/LDPC/SGI/bw from the EFUSE * RF-type. STBC needs >=2 chains, so 1T1R cuts (8811AU/8821AU) report * stbc_ok=false and send_packet drops an STBC request. */ devourer::TxCaps GetTxCaps() override; - /* Aggregate identity + radio + feature caps (IRtlDevice). Composes GetTxCaps + /* Aggregate identity + radio + feature caps (IRadio). Composes GetTxCaps * / GetTxPowerCaps; identity from the EFUSE version-id + RF-type. */ devourer::AdapterCaps GetAdapterCaps() override; /* Live per-chain RX-path activity (fed via _rxpaths in the RX loop). */ @@ -234,7 +234,7 @@ class RtlJaguarDevice : public IRtlDevice { devourer::FwBootStatus GetFwBootStatus() override { return _halModule.GetFwBootStatus(); } - /* Read-only canary dump, safe to call without Init — see IRtlDevice. */ + /* Read-only canary dump, safe to call without Init — see IRadio. */ void DumpChipState() override { _radioManagement->DumpCanary(); } /* Runtime TX-mode default. send_packet honours a frame's own radiotap rate @@ -246,22 +246,22 @@ class RtlJaguarDevice : public IRtlDevice { void ClearTxMode(); bool send_packet(const uint8_t* packet, size_t length) override; - /* Batch TX with USB aggregation (IRtlDevice contract): with + /* Batch TX with USB aggregation (IRadio contract): with * cfg.tx.usb_agg_max > 1 consecutive frames are packed into shared bulk-OUT * URBs — one [txdesc][frame] block per frame, first descriptor carrying the * count in USB_TXAGG_NUM (see src/TxAggPlan.h; the MAC-side TDECTRL * block-desc count is programmed at bring-up when the knob is on). Falls * back to the per-frame loop when the knob is off. */ size_t send_packets(const TxPacketView *pkts, size_t count) override; - /* Hardware ACK responder (IRtlDevice contract; src/AckResponder.h). */ + /* Hardware ACK responder (IRadio contract; src/AckResponder.h). */ bool SetAckResponder(const devourer::MacAddr &mac) override; void ClearAckResponder() override; - /* Carrier-sense gate (IRtlDevice contract): MAC 0x520[14]/[15] like the + /* Carrier-sense gate (IRadio contract): MAC 0x520[14]/[15] like the * HalMAC generations, plus this family's BB EDCCA thresholds (0x8a4) — * parked at never-trigger by the BB table, programmed to the vendor * operating point on enable (EDCCA only exists once they are set). */ void SetCcaMode(bool disabled) override; - /* A-MPDU TX mode (IRtlDevice contract; src/AmpduMode.h). Programs the + /* A-MPDU TX mode (IRadio contract; src/AmpduMode.h). Programs the * Jaguar1 aggregate-fill timer (0x0456 — NOT the 0x0455 the HalMAC chips * use) + the 8814A burst-mode gate (0x04BC), and records the descriptor * state the TX path reads. */ @@ -276,7 +276,7 @@ class RtlJaguarDevice : public IRtlDevice { bool GetPermanentMacAddress(uint8_t out[6]) override; uint64_t ReadTsf() override; - /* Hardware-timed beacon (IRtlDevice contract): download the beacon MPDU to + /* Hardware-timed beacon (IRadio contract): download the beacon MPDU to * the reserved page at the BCNQ boundary (the vendor rtl8812_download_rsvd_page * bracket: CR+1 SW-beacon-DMA, beacon function off, 0x422[6] cleared so the * QSEL-beacon bulk-OUT is stored instead of aired, BCN_VALID 0x20A[0] W1C + @@ -285,16 +285,16 @@ class RtlJaguarDevice : public IRtlDevice { * stored beacon airs with the hardware sequence pinned at 0 (kernel rtw88 * parity). `interval_tu` is the beacon interval in TU (1024 µs). */ bool StartBeacon(const uint8_t* beacon, size_t len, int interval_tu) override; - /* In-place beacon content swap (IRtlDevice contract): retain the new MPDU + + /* In-place beacon content swap (IRadio contract): retain the new MPDU + * a fresh BCNQ-boundary store; interval/TBTT/port identity untouched. */ bool UpdateBeaconPayload(const uint8_t* beacon, size_t len) override; bool StopBeacon() override; - /* Beacon-TBTT steering (IRtlDevice contract) — the Jaguar2 steer-then- + /* Beacon-TBTT steering (IRadio contract) — the Jaguar2 steer-then- * re-download pattern: re-download the retained MPDU after the re-latch to * re-arm the bcn-valid latch. */ int32_t AdjustBeaconTiming(int32_t microseconds) override; int32_t AdjustBeaconTimingFine(int32_t microseconds) override; - /* TSF-preserving TBTT arm (IRtlDevice contract, J1 subset): the J1 TBTT is + /* TSF-preserving TBTT arm (IRadio contract, J1 subset): the J1 TBTT is * hardware-locked to the TSF grid (bench: a pinned nonzero offset never * holds — the phase follows the restored TSF), so only offset 0 is * supported (the arm/igniter StartBeacon uses); nonzero refuses. Steering diff --git a/src/jaguar2/ChipVariant.h b/src/jaguar2/ChipVariant.h index 290960ac..936c73e3 100644 --- a/src/jaguar2/ChipVariant.h +++ b/src/jaguar2/ChipVariant.h @@ -13,7 +13,7 @@ namespace jaguar2 { * C8821C — RTL8811CU / RTL8821CU: 1T1R AC600 + BT combo (SYS_CFG2 chip-id 0x09, * hardware-verified on a CF-811AC; RF_TYPE bit27=0 => 1T1R) * - * Resolved at construction in WiFiDriver::CreateRtlDevice from the SYS_CFG2 + * Resolved at construction in WiFiDriver::CreateRadio from the SYS_CFG2 * (0x00FC) chip-id byte and threaded into HalJaguar2 (table/RF-path select), * HalmacJaguar2Fw (blob select) and the calibration factory. */ enum class ChipVariant { C8822B, C8821C }; diff --git a/src/jaguar2/HalJaguar2.h b/src/jaguar2/HalJaguar2.h index f090f9e7..88922c17 100644 --- a/src/jaguar2/HalJaguar2.h +++ b/src/jaguar2/HalJaguar2.h @@ -61,7 +61,7 @@ class HalJaguar2 { /* Per-unit MAC at logical EFUSE offset 0x107 — the same offset on both dies * (hal_pg.h: EEPROM_MAC_ADDR_8822BU == EEPROM_MAC_ADDR_8821CU; why the MAC - * is the identity key at all: IRtlDevice::GetPermanentMacAddress). Served + * is the identity key at all: IRadio::GetPermanentMacAddress). Served * from the cached logical map — a lookup post-bring-up, a real physical walk * on a pre-init call. false when unprogrammed (all-0xFF) or unread * (all-0x00). */ @@ -80,11 +80,11 @@ class HalJaguar2 { * VHT regulatory clamp — hw_rate 0x2c-0x3f). * * `offset_steps` is the runtime TX-power offset (TXAGC index steps, 0.5 dB - * each) behind IRtlDevice::SetTxPowerOffsetQdb: folded AFTER the min() with + * each) behind IRadio::SetTxPowerOffsetQdb: folded AFTER the min() with * the regulatory table, clamped only at the 6-bit rails (the saturation * flags below record rail hits — reset per apply). * - * A non-null `diffs` (IRtlDevice::SetTxPowerRateDiffs) REPLACES the + * A non-null `diffs` (IRadio::SetTxPowerRateDiffs) REPLACES the * calibrated per-rate shape: every rate is written at the section reference * rate's index (HT MCS7 1SS, the anchor) plus the caller's own diff for that * rate, quantized to this family's 0.5 dB step. Null keeps the calibrated diff --git a/src/jaguar2/RtlJaguar2Device.cpp b/src/jaguar2/RtlJaguar2Device.cpp index af767d34..60a120f5 100644 --- a/src/jaguar2/RtlJaguar2Device.cpp +++ b/src/jaguar2/RtlJaguar2Device.cpp @@ -1310,7 +1310,7 @@ size_t RtlJaguar2Device::send_packets(const TxPacketView *pkts, size_t count) { * interface-default per-frame loop. */ const unsigned agg = _cfg.tx.usb_agg_max; if (agg <= 1 || !_device.is_usb() || count == 0) - return IRtlDevice::send_packets(pkts, count); + return IRadio::send_packets(pkts, count); devourer::TxAggLimits lim; lim.desc_size = jaguar2::TXDESC_SIZE_8822B; diff --git a/src/jaguar2/RtlJaguar2Device.h b/src/jaguar2/RtlJaguar2Device.h index f67562ce..552ce7f7 100644 --- a/src/jaguar2/RtlJaguar2Device.h +++ b/src/jaguar2/RtlJaguar2Device.h @@ -9,7 +9,7 @@ #include #include "logger.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "TxMode.h" #include "RtlAdapter.h" #include "SelectedChannel.h" @@ -24,7 +24,7 @@ /* RtlJaguar2Device is the orchestrator for the Realtek "Jaguar2" 802.11ac family * — RTL8822BU (chip 8822B, 2T2R, USB). It is the Jaguar2 sibling of * RtlJaguarDevice (Jaguar1) and RtlJaguar3Device (Jaguar3) and implements the - * same IRtlDevice contract so the demos and the WiFiDriver factory treat all + * same IRadio contract so the demos and the WiFiDriver factory treat all * three uniformly. * * Jaguar2 is a hybrid of the two existing generations: firmware download, MAC @@ -38,7 +38,7 @@ * (Jaguar2PhyTables table data + RF-path count), HalmacJaguar2Fw (blob) and the * Jaguar2Calibration IQK factory — the same strategy-dispatch shape as the * Jaguar3 8822C/8822E HAL. */ -class RtlJaguar2Device : public IRtlDevice { +class RtlJaguar2Device : public IRadio { public: RtlJaguar2Device(RtlAdapter device, Logger_t logger, jaguar2::ChipVariant variant = jaguar2::ChipVariant::C8822B, @@ -47,7 +47,7 @@ class RtlJaguar2Device : public IRtlDevice { void Init(Action_ParsedRadioPacket packetProcessor, SelectedChannel channel) override; - /* Blocking RX worker loop on an already-brought-up chip (see IRtlDevice). + /* Blocking RX worker loop on an already-brought-up chip (see IRadio). * Init = bring_up + StartRxLoop; a TX+RX caller does InitWrite once, then * runs this on its own std::thread next to the TX loop. Starts (and on exit * stops) the DIG thread — TX-only sessions stay DIG-free. */ @@ -66,16 +66,16 @@ class RtlJaguar2Device : public IRtlDevice { void FastSetBandwidth(ChannelWidth_t bw) override; void InitWrite(SelectedChannel channel) override; bool send_packet(const uint8_t *packet, size_t length) override; - /* Batch TX with USB aggregation (IRtlDevice contract): with + /* Batch TX with USB aggregation (IRadio contract): with * cfg.tx.usb_agg_max > 1 consecutive frames are packed into shared bulk-OUT * URBs — one [txdesc][frame] block per frame, first descriptor carrying the * count in DMA_TXAGG_NUM (see src/TxAggPlan.h). Falls back to the * per-frame loop when the knob is off. */ size_t send_packets(const TxPacketView *pkts, size_t count) override; - /* Hardware ACK responder (IRtlDevice contract; src/AckResponder.h). */ + /* Hardware ACK responder (IRadio contract; src/AckResponder.h). */ bool SetAckResponder(const devourer::MacAddr &mac) override; void ClearAckResponder() override; - /* A-MPDU TX mode (IRtlDevice contract; src/AmpduMode.h). Programs the + /* A-MPDU TX mode (IRadio contract; src/AmpduMode.h). Programs the * 8822B pacing regs (0x455 max-time, 0x4BC burst-mode) under _reg_mu and * records the descriptor state the TX path reads. */ bool SetAmpduMode(const devourer::AmpduMode &mode) override; @@ -88,20 +88,20 @@ class RtlJaguar2Device : public IRtlDevice { uint64_t ReadTsf() override; void WriteTsf(uint64_t tsf) override; bool StartBeacon(const uint8_t *beacon, size_t len, int interval_tu) override; - /* In-place beacon content swap (IRtlDevice contract): retain the new MPDU + + /* In-place beacon content swap (IRadio contract): retain the new MPDU + * ride the steer re-download; interval/TBTT/port identity untouched. */ bool UpdateBeaconPayload(const uint8_t *beacon, size_t len) override; bool StopBeacon() override; /* Disable/restore the MAC EDCCA gate (BIT_DIS_EDCCA 0x520[15] + EDCCA-mask * 0x524[11] — HalMAC-common with J3) so a TBTT beacon airs on schedule. */ void SetCcaMode(bool disabled) override; - /* Beacon-TBTT steering (IRtlDevice contract). The J2 engine loses the + /* Beacon-TBTT steering (IRadio contract). The J2 engine loses the * bcn-valid latch on ANY TBTT re-latch (bench-proven on the 8812BU), so both * actuators steer then re-download the retained reserved-page beacon to * re-arm the latch — one skipped beacon per correction. */ int32_t AdjustBeaconTiming(int32_t microseconds) override; int32_t AdjustBeaconTimingFine(int32_t microseconds) override; - /* TSF-preserving absolute TBTT pin (IRtlDevice contract): steer via the + /* TSF-preserving absolute TBTT pin (IRadio contract): steer via the * shift + re-latch, then write the TSF back onto its original timeline so * a controller fitting against this port's TSF sees a continuous clock. */ int32_t PinBeaconTbtt(int32_t offset_us) override; @@ -109,7 +109,7 @@ class RtlJaguar2Device : public IRtlDevice { void SetTxMode(const devourer::TxMode &mode) override; void ClearTxMode() override; - /* Runtime TX-power control (IRtlDevice contract; see src/TxPower.h). + /* Runtime TX-power control (IRadio contract; see src/TxPower.h). * Jaguar2 caps: 6-bit TXAGC index, 0.5 dB (2 qdB) per step. The offset * folds into HalJaguar2::apply_tx_power after the regulatory min() (or onto * the flat override), covering CCK/OFDM/HT and — 8822B included — the VHT @@ -133,10 +133,10 @@ class RtlJaguar2Device : public IRtlDevice { bool SetTxPowerRateDiffs( const std::optional &diffs) override; devourer::ThermalStatus GetThermalStatus() override; - /* Per-chip TX caps (IRtlDevice): the 8821C is 1T1R (no STBC), the 8822B + /* Per-chip TX caps (IRadio): the 8821C is 1T1R (no STBC), the 8822B * 2T2R. send_packet drops an STBC request the variant can't honour. */ devourer::TxCaps GetTxCaps() override; - /* Aggregate identity + radio + feature caps (IRtlDevice). Composes GetTxCaps + /* Aggregate identity + radio + feature caps (IRadio). Composes GetTxCaps * / GetTxPowerCaps; identity from ChipVariant, transport from the adapter. */ devourer::AdapterCaps GetAdapterCaps() override; /* Live per-chain RX-path activity (fed via _rxpaths in the RX loop). */ diff --git a/src/jaguar3/ChipVariant.h b/src/jaguar3/ChipVariant.h index 0d68d9c9..59b618bf 100644 --- a/src/jaguar3/ChipVariant.h +++ b/src/jaguar3/ChipVariant.h @@ -11,7 +11,7 @@ namespace jaguar3 { * C8822C — rtl8822c: RTL8812CU / RTL8822CU (SYS_CFG2 chip-id 0x13) * C8822E — rtl8822e: RTL8812EU / RTL8822EU (SYS_CFG2 chip-id 0x17) * - * Resolved at construction in WiFiDriver::CreateRtlDevice from the SYS_CFG2 + * Resolved at construction in WiFiDriver::CreateRadio from the SYS_CFG2 * (0x00FC) chip-id byte and threaded down into HalmacJaguar3Fw for blob select. */ enum class ChipVariant { C8822C, C8822E }; diff --git a/src/jaguar3/HalJaguar3.h b/src/jaguar3/HalJaguar3.h index 505a7b2d..c160356a 100644 --- a/src/jaguar3/HalJaguar3.h +++ b/src/jaguar3/HalJaguar3.h @@ -80,7 +80,7 @@ class HalJaguar3 { bool probe_efuse_map(uint8_t *map, size_t len); /* Per-unit MAC at logical EFUSE offset 0x157 on this generation (why the MAC - * is the identity key at all: IRtlDevice::GetPermanentMacAddress). + * is the identity key at all: IRadio::GetPermanentMacAddress). * * On 8822E this is served from the value captured during rtw_hal_init: the * OTP is not reliably readable after TX/coex bring-up by design, the same diff --git a/src/jaguar3/Jaguar3Calibration.h b/src/jaguar3/Jaguar3Calibration.h index 288424c9..3738c2f6 100644 --- a/src/jaguar3/Jaguar3Calibration.h +++ b/src/jaguar3/Jaguar3Calibration.h @@ -37,7 +37,7 @@ class Jaguar3Calibration { uint8_t /*thermal_base_b*/, uint8_t /*channel*/) {} - /* One-shot thermal-meter read (path A) for IRtlDevice::GetThermalStatus: + /* One-shot thermal-meter read (path A) for IRadio::GetThermalStatus: * `raw` = the live RF 0x42[6:1] reading, `baseline` = the calibration * reference — the efuse baseline on the 8822e (0xFF = unprogrammed), the * first-read cold reference on the 8822c (no efuse baseline is wired on the diff --git a/src/jaguar3/RtlJaguar3Device.cpp b/src/jaguar3/RtlJaguar3Device.cpp index d33788c2..8cc33963 100644 --- a/src/jaguar3/RtlJaguar3Device.cpp +++ b/src/jaguar3/RtlJaguar3Device.cpp @@ -705,7 +705,7 @@ void RtlJaguar3Device::apply_replay_wseq() { _cfg.debug.replay_wseq); } -/* Clean shutdown — see IRtlDevice::Stop. Best-effort: a chip that already +/* Clean shutdown — see IRadio::Stop. Best-effort: a chip that already * dropped off the bus will make the de-init writes fail, which is fine. */ void RtlJaguar3Device::Stop() { _coex_stop = true; @@ -1762,7 +1762,7 @@ size_t RtlJaguar3Device::send_packets(const TxPacketView *pkts, size_t count) { * interface-default per-frame loop. */ const unsigned agg = _cfg.tx.usb_agg_max; if (agg <= 1 || !_device.is_usb() || count == 0) - return IRtlDevice::send_packets(pkts, count); + return IRadio::send_packets(pkts, count); devourer::TxAggLimits lim; lim.desc_size = jaguar3::TXDESC_SIZE_8822C; @@ -2047,7 +2047,7 @@ size_t RtlJaguar3Device::build_tx_block(const uint8_t *packet, size_t length, * the kernel's descriptor for group-addressed frames. */ const uint8_t *dot11 = packet + radiotap_length; bool bmc = frame_len >= 6 && (dot11[4] & 0x01); - /* STBC guard (IRtlDevice contract) — 8822C/8822E are 2T2R so this never + /* STBC guard (IRadio contract) — 8822C/8822E are 2T2R so this never * fires today, but keeps the invariant uniform across families: never air an * STBC frame the chip can't do. */ if (stbc && !GetTxCaps().stbc_ok) diff --git a/src/jaguar3/RtlJaguar3Device.h b/src/jaguar3/RtlJaguar3Device.h index 34482c54..bcff1eaf 100644 --- a/src/jaguar3/RtlJaguar3Device.h +++ b/src/jaguar3/RtlJaguar3Device.h @@ -8,7 +8,7 @@ #include "logger.h" #include "CfoTracker.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "TxMode.h" #include "RtlAdapter.h" #include "SelectedChannel.h" @@ -21,7 +21,7 @@ /* RtlJaguar3Device is the orchestrator for the Realtek "Jaguar3" 802.11ac family * — RTL8822CU, RTL8812EU, RTL8822EU. It is the Jaguar3 sibling of - * RtlJaguarDevice (Jaguar1) and implements the same IRtlDevice contract so the + * RtlJaguarDevice (Jaguar1) and implements the same IRadio contract so the * demos and WiFiDriver factory treat both uniformly. * * Bring-up is ported from Realtek vendor source (rtl88x2cu/phydm/halrf): @@ -29,7 +29,7 @@ * channel/bandwidth (incl. 5/10 MHz narrowband) and on-air TX. send_packet is * on-air; sustained continuous TX is kept alive by the coex runtime thread * (coex_runtime_loop) — see src/jaguar3/CLAUDE.md. */ -class RtlJaguar3Device : public IRtlDevice { +class RtlJaguar3Device : public IRadio { public: RtlJaguar3Device(RtlAdapter device, Logger_t logger, jaguar3::ChipVariant variant = jaguar3::ChipVariant::C8822C, @@ -38,7 +38,7 @@ class RtlJaguar3Device : public IRtlDevice { void Init(Action_ParsedRadioPacket packetProcessor, SelectedChannel channel) override; - /* Blocking RX worker loop on an already-brought-up chip (see IRtlDevice). + /* Blocking RX worker loop on an already-brought-up chip (see IRadio). * Init = bring-up + BFEE arm + StartRxLoop; a TX+RX caller (self-sounding * single-radio ground station) does InitWrite once, then runs this on its * own std::thread next to the TX loop. NB: for reliable RX the TX+RX intent @@ -66,16 +66,16 @@ class RtlJaguar3Device : public IRtlDevice { void FastSetBandwidth(ChannelWidth_t bw) override; void InitWrite(SelectedChannel channel) override; bool send_packet(const uint8_t *packet, size_t length) override; - /* Batch TX with USB aggregation (IRtlDevice contract): with + /* Batch TX with USB aggregation (IRadio contract): with * cfg.tx.usb_agg_max > 1 consecutive frames are packed into shared bulk-OUT * URBs — one [txdesc][frame] block per frame, first descriptor carrying the * count in DMA_TXAGG_NUM (see src/TxAggPlan.h). Falls back to the per-frame * loop when the knob is off. */ size_t send_packets(const TxPacketView *pkts, size_t count) override; - /* Hardware ACK responder (IRtlDevice contract; src/AckResponder.h). */ + /* Hardware ACK responder (IRadio contract; src/AckResponder.h). */ bool SetAckResponder(const devourer::MacAddr &mac) override; void ClearAckResponder() override; - /* A-MPDU TX mode (IRtlDevice contract; src/AmpduMode.h). Programs the 8822C + /* A-MPDU TX mode (IRadio contract; src/AmpduMode.h). Programs the 8822C * aggregate-fill timer (0x455) under _reg_mu (serialized against the coex * thread) and records the descriptor state the TX path reads. */ bool SetAmpduMode(const devourer::AmpduMode &mode) override; @@ -89,18 +89,18 @@ class RtlJaguar3Device : public IRtlDevice { uint64_t ReadTsf() override; void WriteTsf(uint64_t tsf) override; bool StartBeacon(const uint8_t *beacon, size_t len, int interval_tu) override; - /* In-place beacon content swap (IRtlDevice contract): a fresh + /* In-place beacon content swap (IRadio contract): a fresh * download_beacon_page; interval/TBTT/port identity untouched. */ bool UpdateBeaconPayload(const uint8_t *beacon, size_t len) override; bool StopBeacon() override; int32_t AdjustBeaconTiming(int32_t microseconds) override; int32_t AdjustBeaconTimingFine(int32_t microseconds) override; - /* TSF-preserving absolute TBTT pin (IRtlDevice contract; the J2 pattern — + /* TSF-preserving absolute TBTT pin (IRadio contract; the J2 pattern — * no reserved-page re-download needed on J3). */ int32_t PinBeaconTbtt(int32_t offset_us) override; void Stop() override; - /* Runtime TX-power control (IRtlDevice contract; see src/TxPower.h). + /* Runtime TX-power control (IRadio contract; see src/TxPower.h). * Jaguar3 caps: 7-bit TXAGC reference, 0.25 dB (1 qdB) per step. The offset * shifts the per-path reference anchor (0x18e8/0x41e8 OFDM, 0x18a0/0x41a0 * CCK) — the 0x3a00 per-rate diff table is offset-invariant, so a live step @@ -137,9 +137,9 @@ class RtlJaguar3Device : public IRtlDevice { int GetXtalCap() override { return _xtal_cap; } devourer::TxPowerState GetTxPowerState() override; devourer::ThermalStatus GetThermalStatus() override; - /* Per-chip TX caps (IRtlDevice): 8822C/8822E are 2T2R (STBC ok). */ + /* Per-chip TX caps (IRadio): 8822C/8822E are 2T2R (STBC ok). */ devourer::TxCaps GetTxCaps() override; - /* Aggregate identity + radio + feature caps (IRtlDevice). Composes GetTxCaps + /* Aggregate identity + radio + feature caps (IRadio). Composes GetTxCaps * / GetTxPowerCaps; identity from ChipVariant, transport from the adapter. */ devourer::AdapterCaps GetAdapterCaps() override; /* Live per-chain RX-path activity (fed via _rxpaths in the RX loop). */ @@ -196,7 +196,7 @@ class RtlJaguar3Device : public IRtlDevice { * vendor rtw_proc.c dis_cca recipe (MAC BIT_DIS_EDCCA 0x520[15] + EDCCA-mask * countdown 0x524[11], BB 0x1a9c[20]/0x1a14[9:8]/0x1d58[0xff8]); disabled=false * restores the inverse. Sticky across SetMonitorChannel; serialized on _reg_mu - * against the coex tick. On IRtlDevice: measured to collapse the hardware-beacon + * against the coex tick. On IRadio: measured to collapse the hardware-beacon * downlink residual from ~472 µs to 0.39 µs on a crowded channel (the TBTT * beacon airs on schedule instead of after a CSMA backoff). */ void SetCcaMode(bool disabled) override; diff --git a/src/kestrel/ChipVariant.h b/src/kestrel/ChipVariant.h index d8e18f68..55d8ff05 100644 --- a/src/kestrel/ChipVariant.h +++ b/src/kestrel/ChipVariant.h @@ -11,7 +11,7 @@ namespace kestrel { * C8852B — RTL8852BU / RTL8832BU (die-id 0x51 at R_AX_SYS_CHIPINFO) * C8852C — RTL8852CU / RTL8832CU (die-id 0x52) * - * Resolved at construction in WiFiDriver::CreateRtlDevice — from the USB PID + * Resolved at construction in WiFiDriver::CreateRadio — from the USB PID * (kestrel::variant_for_usb_id), NOT from the 0x00FC register byte the 11ac * dispatch reads: on AX silicon 0x00FC is R_AX_SYS_CHIPINFO, whose 8852A value * (0x50) collides with the 8822B cold-boot transient the Jaguar2 dispatch diff --git a/src/kestrel/RtlKestrelDevice.h b/src/kestrel/RtlKestrelDevice.h index 513c8158..c2bcd15c 100644 --- a/src/kestrel/RtlKestrelDevice.h +++ b/src/kestrel/RtlKestrelDevice.h @@ -11,7 +11,7 @@ #include "logger.h" #include "DeviceConfig.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "RtlAdapter.h" #include "RxQuality.h" /* RxQualityAccumulator + build_rx_quality */ #include "SelectedChannel.h" @@ -39,7 +39,7 @@ struct ChipInfo { /* RtlKestrelDevice is the orchestrator for the Realtek "Kestrel" Wi-Fi 6 / * 802.11ax family (G6 "phl" vendor architecture) — RTL8852BU/8832BU and - * RTL8852CU/8832CU. It implements the same IRtlDevice contract as the three + * RTL8852CU/8832CU. It implements the same IRadio contract as the three * Jaguar (11ac) generations so the demos and WiFiDriver factory treat all * four uniformly. * @@ -49,7 +49,7 @@ struct ChipInfo { * hand-ported C++ here + HalKestrel/KestrelFw; the halbb PHY and halrf * calibration planes are the vendor C compiled verbatim (hal/halbb, hal/halrf) * behind the kestrel glue. */ -class RtlKestrelDevice : public IRtlDevice { +class RtlKestrelDevice : public IRadio { public: RtlKestrelDevice(RtlAdapter device, Logger_t logger, kestrel::ChipVariant variant = kestrel::ChipVariant::C8852B, @@ -188,7 +188,7 @@ class RtlKestrelDevice : public IRtlDevice { kestrel::ChipVariant variant() const { return _variant; } /* Staged bring-up, exposed for kestrelprobe's "power" stage: power the MAC - * on and dump the efuse. Not part of the IRtlDevice contract (Init/InitWrite + * on and dump the efuse. Not part of the IRadio contract (Init/InitWrite * drive the full sequence). Returns false on failure. */ bool PowerOnAndReadEfuse(kestrel::EfuseInfo &out); diff --git a/src/mt7612u/README.md b/src/mt7612u/README.md index 4194a3c8..1b74fba9 100644 --- a/src/mt7612u/README.md +++ b/src/mt7612u/README.md @@ -3,7 +3,7 @@ **Not reachable from `CMakeLists.txt` yet.** This subtree is a complete, self-contained C library for the part — a public header, its own transport, no dependency on `RtlAdapter` — plus the bring-up harness that produced every -measurement in `docs/mt7612u.md`. Wiring it in behind `IRtlDevice` is a +measurement in `docs/mt7612u.md`. Wiring it in behind `IRadio` is a follow-up PR; nothing in the shipped library links against this today. It builds and tests on its own: diff --git a/src/mt7612u/tools/bringup.c b/src/mt7612u/tools/bringup.c index 60d61129..37f7d4b4 100644 --- a/src/mt7612u/tools/bringup.c +++ b/src/mt7612u/tools/bringup.c @@ -422,7 +422,7 @@ static int gate_chan(uint8_t chan, const char *fw_dir) } /* - * Exercise the adopt path - how a libusb-owning consumer (the IRtlDevice + * Exercise the adopt path - how a libusb-owning consumer (the IRadio * wrapper) reaches this subtree. Everything else in this tool arrives through * mt_open(), so without this gate the second entry point is never opened on * hardware at all. diff --git a/src/mt7612u/usb.c b/src/mt7612u/usb.c index ac41b1c9..bd0349ef 100644 --- a/src/mt7612u/usb.c +++ b/src/mt7612u/usb.c @@ -409,7 +409,7 @@ int mt_adopt(struct mt7612u_dev *d, libusb_device_handle *h, d->kernel_was_attached = 0; if (mt_identify(d, err)) return -1; - /* Same recovery mt_open() gets: this is the path the IRtlDevice wrapper + /* Same recovery mt_open() gets: this is the path the IRadio wrapper * takes, and a killed previous run wedges the device for it identically. */ mt_recover_usb(d); return 0; diff --git a/src/rtl8733b/CLAUDE.md b/src/rtl8733b/CLAUDE.md index 4a30e67a..a34509bb 100644 --- a/src/rtl8733b/CLAUDE.md +++ b/src/rtl8733b/CLAUDE.md @@ -11,7 +11,7 @@ them. Do not reach for a Jaguar file expecting a shared mechanism. ## HAL layout -`Rtl8733bDevice` (the `IRtlDevice` boundary), `Rtl8733bBringup` (card +`Rtl8733bDevice` (the `IRadio` boundary), `Rtl8733bBringup` (card enable/disable power sequence, system-cfg), `Halmac8733bMac` (MAC init, firmware download, EFUSE read + packed-map decode, monitor RX config), `Phy8733b` (BB/RF table apply, channel plan, TXAGC, TSSI), plus the header-only @@ -244,7 +244,7 @@ untouched) and fall back to the full path. `FastSetBandwidth`, the flat-index / per-rate-diff TX-power knobs (`SetTxPowerIndexOverride`, `SetTxPowerRateDiffs`, `ReApplyTxPower` — only the relative `SetTxPowerOffsetQdb` is ported), `rx.path` per-chain telemetry, -and CCA disable. These inherit `IRtlDevice`'s not-ported defaults (`false`, +and CCA disable. These inherit `IRadio`'s not-ported defaults (`false`, `0`, or a full-path fallback) rather than being faked. `SetCcaMode` is the one exception to the silent-default rule: it is pure virtual, so `true` throws loudly — without tearing the session down, since an unported optional knob is @@ -264,7 +264,7 @@ The TX-power knobs are the other exceptions, in the same spirit: register carries. (That path has no hardware coverage — every unit seen so far is TSSI-offset PG — but it writes no registers, only a log and a reset.) - `SetTxPowerIndexOverride` is overridden **solely to log a refusal**. The - `IRtlDevice` default returns `void` and ignores the value, so silence would + `IRadio` default returns `void` and ignores the value, so silence would be the caller's only answer on the one backend where the flat index really is unported — a knob that looks granted, in the PR that exists to abolish them. `SetTxPowerRateDiffs` needs no such override: its `false` return already says diff --git a/src/rtl8733b/Phy8733b.h b/src/rtl8733b/Phy8733b.h index ce0caa27..77bb77fe 100644 --- a/src/rtl8733b/Phy8733b.h +++ b/src/rtl8733b/Phy8733b.h @@ -110,7 +110,7 @@ inline constexpr uint8_t kMaxPgTargetQdbm8733b = 80; /* Which rail the runtime TX-power offset clamped at, if any — the signal a * closed-loop controller uses to know the knob has run out of travel - * (IRtlDevice::GetTxPowerState). `low` is set when a rate's shifted target hit + * (IRadio::GetTxPowerState). `low` is set when a rate's shifted target hit * the int8 delta field's -128 floor — a shifted target below -64 qdBm, i.e. * -16 dBm — and deliberately NOT at the 0 qdBm target, which the loop keeps * responding past by ~7 dB; `high` when a rate hit the field's +127 ceiling. @@ -247,7 +247,7 @@ class Phy8733b { bool enable_tssi_tracking(SelectedChannel channel, const EfuseInfo &efuse, uint8_t max_target_qdbm, int offset_qdb = 0); bool disable_tssi_tracking(); - /* Runtime TX-power actuator (IRtlDevice::SetTxPowerOffsetQdb). On a + /* Runtime TX-power actuator (IRadio::SetTxPowerOffsetQdb). On a * TSSI-offset PG unit the closed loop IS the TX-power control, so moving * power means moving the loop's per-rate target table: the five packed * dwords at 0x3a00..0x3a10, rewritten IN PLACE with tracking left enabled — diff --git a/src/rtl8733b/Rtl8733bDevice.cpp b/src/rtl8733b/Rtl8733bDevice.cpp index 931f96c1..25c2101d 100644 --- a/src/rtl8733b/Rtl8733bDevice.cpp +++ b/src/rtl8733b/Rtl8733bDevice.cpp @@ -590,7 +590,7 @@ SelectedChannel Rtl8733bDevice::GetSelectedChannel() { size_t Rtl8733bDevice::send_packets(const TxPacketView *pkts, size_t count) { const unsigned agg = _cfg.tx.usb_agg_max; if (agg <= 1 || !_device.is_usb() || count == 0) - return IRtlDevice::send_packets(pkts, count); + return IRadio::send_packets(pkts, count); std::lock_guard lock(_reg_mu); if (!_phy_ready || !_mac_ready || !_tx_ready) { @@ -621,7 +621,7 @@ size_t Rtl8733bDevice::send_packets(const TxPacketView *pkts, size_t count) { std::vector lens; for (size_t i = done; i < count && lens.size() < lim.max_frames; ++i) { /* A null view is treated exactly like a malformed one: it ends the run - * and, if it led, is skipped per the IRtlDevice::send_packets + * and, if it led, is skipped per the IRadio::send_packets * contract. */ const uint16_t rlen = pkts[i].data == nullptr @@ -981,7 +981,7 @@ void Rtl8733bDevice::SetCcaMode(bool disabled) { /* `true` (DEVOURER_DIS_CCA) is not ported. The HALMAC 87xx carrier-sense * gate has not been located and measured on this part, and this backend * does not guess at PHY/MAC writes it cannot read back. Refuse loudly, per - * the pure-virtual contract in IRtlDevice — but do NOT tear the session + * the pure-virtual contract in IRadio — but do NOT tear the session * down: an unsupported optional knob is not a hardware-safety event, and * card-disabling here would leave the caller with a dead chip for asking a * question. The session stays up with standard carrier-sense. */ diff --git a/src/rtl8733b/Rtl8733bDevice.h b/src/rtl8733b/Rtl8733bDevice.h index bad3b54f..ec3d3087 100644 --- a/src/rtl8733b/Rtl8733bDevice.h +++ b/src/rtl8733b/Rtl8733bDevice.h @@ -8,19 +8,19 @@ #include "DeviceConfig.h" #include "FrameParser8733b.h" #include "Halmac8733bMac.h" -#include "IRtlDevice.h" +#include "IRadio.h" #include "Phy8733b.h" #include "Rtl8733bBringup.h" #include "RtlAdapter.h" #include "SelectedChannel.h" #include "logger.h" -/* Dedicated RTL8733B IRtlDevice boundary. Power, firmware, EFUSE, HALMAC, +/* Dedicated RTL8733B IRadio boundary. Power, firmware, EFUSE, HALMAC, * PHY/RF, monitor RX, and bounded legacy/HT injection all use the production * path. Unsupported optional controls refuse loudly rather than silently * no-opping, but a refusal never tears the session down — asking for a knob * this backend has not ported is not a hardware-safety event. */ -class Rtl8733bDevice : public IRtlDevice { +class Rtl8733bDevice : public IRadio { public: Rtl8733bDevice(RtlAdapter device, Logger_t logger, devourer::DeviceConfig cfg = {}); @@ -35,7 +35,7 @@ class Rtl8733bDevice : public IRtlDevice { /* Lean intra-band, same-bandwidth hop (see Phy8733b::fast_retune — the * profile that sized it and the TSSI in-place contract live there). Falls * back to the full SetMonitorChannel on a band/width change or a cold - * radio, per the IRtlDevice contract. The cache_rf default binds at the + * radio, per the IRadio contract. The cache_rf default binds at the * interface declaration. */ void FastRetune(uint8_t channel, bool cache_rf) override; bool send_packet(const uint8_t *packet, size_t length) override; @@ -74,13 +74,13 @@ class Rtl8733bDevice : public IRtlDevice { /* Runtime TX power. Only the relative offset is ported: on a TSSI-offset PG * unit the closed loop is the power control, and moving its target is the * one lever this part has that was measured to work. The flat-index and - * per-rate-diff knobs stay on IRtlDevice's not-ported defaults — + * per-rate-diff knobs stay on IRadio's not-ported defaults — * kSafeTxAgcIndex8733b was witnessed unable to carry HT at all, and no * dB-per-step slope has been measured for the index. */ devourer::TxPowerCaps GetTxPowerCaps() override; int SetTxPowerOffsetQdb(int qdb) override; devourer::TxPowerState GetTxPowerState() override; - /* Overridden only to refuse out loud. IRtlDevice's default returns void and + /* Overridden only to refuse out loud. IRadio's default returns void and * ignores the value, so on this backend — where the flat index is genuinely * unported — silence would be the caller's only answer, and a knob that * looks granted is precisely the defect this family's offset knob was added diff --git a/tests/ack_responder_selftest.cpp b/tests/ack_responder_selftest.cpp index 3b5caaa3..e20d703f 100644 --- a/tests/ack_responder_selftest.cpp +++ b/tests/ack_responder_selftest.cpp @@ -41,7 +41,7 @@ namespace { * but modelling the whole space keeps the test honest about WHERE it writes: * an implementation that hit the wrong offset would read back zero here rather * than quietly passing. */ -class FakeRegs final : public devourer::IRtlTransport { +class FakeRegs final : public devourer::ITransport { public: std::map mem; bool fail_writes = false; diff --git a/tests/adapter_caps_probe.sh b/tests/adapter_caps_probe.sh index 1ccf04cf..c8872149 100755 --- a/tests/adapter_caps_probe.sh +++ b/tests/adapter_caps_probe.sh @@ -31,7 +31,7 @@ for spec in $PIDS; do fi echo "== probing ${vid}:${pid} ==" log=$(mktemp) - # rxdemo emits adapter.caps right after CreateRtlDevice, well before the RX + # rxdemo emits adapter.caps right after CreateRadio, well before the RX # loop; 6 s covers bring-up on the slowest chip. 2>/dev/null = pure events. sudo timeout 6 env DEVOURER_VID="0x${vid}" DEVOURER_PID="0x${pid}" \ DEVOURER_LOG_LEVEL=silent build/rxdemo >"$log" 2>/dev/null || true diff --git a/tests/ap_responder.cpp b/tests/ap_responder.cpp index 6defb2be..2bf1cf31 100644 --- a/tests/ap_responder.cpp +++ b/tests/ap_responder.cpp @@ -63,7 +63,7 @@ // refuses to emit the auth (bench-proven — flipping 0x57->0x02 made the station // transmit auth). Use 0x02 (locally-administered unicast). static const uint8_t kBssid[6] = {0x02, 0x42, 0x75, 0x05, 0xd6, 0x00}; -static IRtlDevice* g_dev = nullptr; +static IRadio* g_dev = nullptr; static std::vector g_rt; static uint8_t g_chan = 6; static std::atomic g_probe{0}, g_auth{0}, g_assoc{0}, g_sent{0}, g_data{0}; @@ -256,7 +256,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); g_dev = dev.get(); if (!g_dev) return 1; g_rt = devourer::build_stream_radiotap(devourer::parse_tx_mode_str("6M")); diff --git a/tests/ap_wpa2.cpp b/tests/ap_wpa2.cpp index c3edbf0a..119969aa 100644 --- a/tests/ap_wpa2.cpp +++ b/tests/ap_wpa2.cpp @@ -56,7 +56,7 @@ static const uint8_t kBssid[6] = {0x02, 0x42, 0x75, 0x05, 0xd6, 0x00}; static const char* kSsid = "devourerAP"; -static IRtlDevice* g_dev = nullptr; +static IRadio* g_dev = nullptr; static std::vector g_rt; static uint8_t g_chan = 6; static const char* g_psk = "devourer123"; @@ -400,7 +400,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); g_dev = dev.get(); if (!g_dev) return 1; g_rt = devourer::build_stream_radiotap(devourer::parse_tx_mode_str("6M")); g_dev->InitWrite(SelectedChannel{g_chan, 0, CHANNEL_WIDTH_20}); diff --git a/tests/beacon_fullbody.cpp b/tests/beacon_fullbody.cpp index 625bde59..140f6ae3 100644 --- a/tests/beacon_fullbody.cpp +++ b/tests/beacon_fullbody.cpp @@ -78,7 +78,7 @@ int main(int argc, char** argv) { std::shared_ptr lock; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lock) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); if (!dev) { fprintf(stderr, "no driver\n"); return 1; } dev->InitWrite(SelectedChannel{ch, 0, CHANNEL_WIDTH_20}); diff --git a/tests/beacon_interval_shift.sh b/tests/beacon_interval_shift.sh index 8776f0ca..683f9836 100755 --- a/tests/beacon_interval_shift.sh +++ b/tests/beacon_interval_shift.sh @@ -3,7 +3,7 @@ # # WriteTsf (REG_TSFTR 0x0560) was shown NOT to move the beacon TBTT air-time # (the beacon engine runs off a separate/per-port timer). This exercises + -# validates the productized actuator IRtlDevice::AdjustBeaconTiming(us): a +# validates the productized actuator IRadio::AdjustBeaconTiming(us): a # ONE-SHOT beacon-interval tweak (REG_BCN_INTERVAL 0x0554) — run one interval at # (nominal +/- delta) TU then restore, and a clean interval-phased engine # advances/retards the next TBTT by delta TU, resuming cadence phase-shifted. @@ -79,7 +79,7 @@ int main(int argc,char**argv){ std::shared_ptr lk; if(devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h),logger,true,lk)!=0)return 1; WiFiDriver wifi(logger); - auto dev=wifi.CreateRtlDevice(h,ctx,lk,devourer_config_from_env()); + auto dev=wifi.CreateRadio(h,ctx,lk,devourer_config_from_env()); if(!dev)return 1; dev->InitWrite(SelectedChannel{ch,0,CHANNEL_WIDTH_20}); std::this_thread::sleep_for(std::chrono::seconds(2)); @@ -137,7 +137,7 @@ int main(){ std::shared_ptr lk; if(devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h),logger,true,lk)!=0)return 1; WiFiDriver wifi(logger); - auto dev=wifi.CreateRtlDevice(h,ctx,lk,devourer_config_from_env()); + auto dev=wifi.CreateRadio(h,ctx,lk,devourer_config_from_env()); if(!dev)return 1; auto cb=[](const Packet&p){ if(p.Data.size()<32||p.RxAtrib.crc_err)return; diff --git a/tests/beacon_steer_check.cpp b/tests/beacon_steer_check.cpp index 9af44522..c23e1503 100644 --- a/tests/beacon_steer_check.cpp +++ b/tests/beacon_steer_check.cpp @@ -69,13 +69,13 @@ int main(int argc, char **argv) { libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING); WiFiDriver wifi(logger); - std::unique_ptr dev; + std::unique_ptr dev; const char *bdf = std::getenv("DEVOURER_PCIE_BDF"); #if defined(DEVOURER_HAVE_PCIE) if (bdf) { auto transport = devourer::PcieTransport::Open(bdf, logger); if (!transport) { fprintf(stderr, "PCIe open %s failed\n", bdf); return 1; } - dev = wifi.CreateRtlDevicePcie(std::move(transport), + dev = wifi.CreateRadioPcie(std::move(transport), devourer_config_from_env()); } else #endif @@ -89,7 +89,7 @@ int main(int argc, char **argv) { std::shared_ptr lock; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lock) != 0) return 1; - dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); } if (!dev) { fprintf(stderr, "no driver\n"); return 1; } diff --git a/tests/beacon_steer_survival.sh b/tests/beacon_steer_survival.sh index badca4d2..d3f05741 100755 --- a/tests/beacon_steer_survival.sh +++ b/tests/beacon_steer_survival.sh @@ -76,7 +76,7 @@ int main(int argc,char**argv){ std::shared_ptr lk; if(devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h),logger,true,lk)!=0)return 1; WiFiDriver wifi(logger); - auto dev=wifi.CreateRtlDevice(h,ctx,lk,devourer_config_from_env()); + auto dev=wifi.CreateRadio(h,ctx,lk,devourer_config_from_env()); if(!dev)return 1; auto cb=[](const Packet&p){ if(p.Data.size()<32||p.RxAtrib.crc_err)return; diff --git a/tests/beacon_tbtt.cpp b/tests/beacon_tbtt.cpp index 1d9ac1f8..3ebd74c6 100644 --- a/tests/beacon_tbtt.cpp +++ b/tests/beacon_tbtt.cpp @@ -1,7 +1,7 @@ // beacon_tbtt.cpp — experiment (idea 6): can the MAC transmit a beacon at each // TBTT (hardware-timed off the TSF) in devourer's monitor/injection mode? Brings // up TX on a Jaguar1 adapter, loads a beacon into the beacon queue + enables the -// beacon function (IRtlDevice::StartBeacon), then IDLES — no send loop. If +// beacon function (IRadio::StartBeacon), then IDLES — no send loop. If // the beacon function works, the chip transmits the beacon on its own at the // interval. Observe with a second adapter running rxdemo (count rx.txhit of the // canonical SA; ~1 per 102.4 ms at 100 TU => hardware-timed TX confirmed). @@ -45,7 +45,7 @@ int main(int argc, char** argv) { std::shared_ptr lock; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lock) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); if (!dev) { fprintf(stderr, "no driver\n"); return 1; } dev->InitWrite(SelectedChannel{ch, 0, CHANNEL_WIDTH_20}); diff --git a/tests/beacon_ts_check.cpp b/tests/beacon_ts_check.cpp index 00960cd3..e03ba1fd 100644 --- a/tests/beacon_ts_check.cpp +++ b/tests/beacon_ts_check.cpp @@ -34,7 +34,7 @@ int main() { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); if (!dev) return 1; auto cb = [](const Packet& p) { if (p.Data.size() < 32 || p.RxAtrib.crc_err) return; diff --git a/tests/beacon_update_probe.cpp b/tests/beacon_update_probe.cpp index 06cd0919..e0b8a7c5 100644 --- a/tests/beacon_update_probe.cpp +++ b/tests/beacon_update_probe.cpp @@ -140,7 +140,7 @@ int main(int argc, char** argv) { if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lock) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); if (!dev) { fprintf(stderr, "no driver\n"); return 1; } if (rx_mode) { diff --git a/tests/beacon_wire_check.cpp b/tests/beacon_wire_check.cpp index a0901cf0..4586bb89 100644 --- a/tests/beacon_wire_check.cpp +++ b/tests/beacon_wire_check.cpp @@ -49,7 +49,7 @@ int main() { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); if (!dev) return 1; auto cb = [](const Packet& p) { if (p.Data.size() < 32 || p.RxAtrib.crc_err) return; diff --git a/tests/dl_departure_tx.cpp b/tests/dl_departure_tx.cpp index fd5cb1eb..8cb0df3a 100644 --- a/tests/dl_departure_tx.cpp +++ b/tests/dl_departure_tx.cpp @@ -56,7 +56,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); if (!dev) return 1; dev->InitWrite(SelectedChannel{ch, 0, CHANNEL_WIDTH_20}); diff --git a/tests/fast_bw_rxcheck.cpp b/tests/fast_bw_rxcheck.cpp index 7902478d..d83310e0 100644 --- a/tests/fast_bw_rxcheck.cpp +++ b/tests/fast_bw_rxcheck.cpp @@ -50,7 +50,7 @@ int main(int argc, char **argv) { std::shared_ptr lock; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lock) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); if (!dev) return 1; auto cb = [](const Packet &p) { diff --git a/tests/in_process_hotplug_wrap.cpp b/tests/in_process_hotplug_wrap.cpp index 39d88030..a8d2f2a8 100644 --- a/tests/in_process_hotplug_wrap.cpp +++ b/tests/in_process_hotplug_wrap.cpp @@ -25,7 +25,7 @@ // 3. Construct a libusb handle from that fd via // `libusb_wrap_sys_device(ctx, fd, &handle)` — same path Android // takes from `UsbDeviceConnection.getFileDescriptor()`. -// 4. Run a regular `CreateRtlDevice` + `Init` for RX_SECONDS to count +// 4. Run a regular `CreateRadio` + `Init` for RX_SECONDS to count // RX hits. Then close. // 5. Run an externally-triggered sysfs unbind+rebind so the chip // goes through a real USB reset cycle. @@ -183,7 +183,7 @@ int run_session(libusb_context* ctx, uint16_t vid, uint16_t pid, int before = g_rx.load(); WiFiDriver drv(logger); - auto dev = drv.CreateRtlDevice(h, nullptr, nullptr, + auto dev = drv.CreateRadio(h, nullptr, nullptr, devourer_config_from_env()); std::thread t([&]{ diff --git a/tests/pcie_ptp_beacon.cpp b/tests/pcie_ptp_beacon.cpp index 823f640c..b8dc8afb 100644 --- a/tests/pcie_ptp_beacon.cpp +++ b/tests/pcie_ptp_beacon.cpp @@ -58,7 +58,7 @@ int main(int argc, char **argv) { auto t = devourer::PcieTransport::Open(bdf, logger); if (!t) { fprintf(stderr, "pcie open failed\n"); return 1; } WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevicePcie(std::move(t)); + auto dev = wifi.CreateRadioPcie(std::move(t)); if (!dev) { fprintf(stderr, "create failed\n"); return 1; } dev->InitWrite(SelectedChannel{ch, 0, CHANNEL_WIDTH_20}); diff --git a/tests/pcie_txegress_tx.cpp b/tests/pcie_txegress_tx.cpp index 235111dd..d4972822 100644 --- a/tests/pcie_txegress_tx.cpp +++ b/tests/pcie_txegress_tx.cpp @@ -41,8 +41,8 @@ int main(int argc, char **argv) { auto transport = devourer::PcieTransport::Open(bdf, logger); if (!transport) { fprintf(stderr, "pcie open failed for %s (vfio-bound?)\n", bdf); return 1; } WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevicePcie(std::move(transport)); - if (!dev) { fprintf(stderr, "CreateRtlDevicePcie failed\n"); return 1; } + auto dev = wifi.CreateRadioPcie(std::move(transport)); + if (!dev) { fprintf(stderr, "CreateRadioPcie failed\n"); return 1; } dev->InitWrite(SelectedChannel{ch, 0, CHANNEL_WIDTH_20}); dev->SetCcaMode(true); // disable EDCCA — suppress CSMA backoff so the residual diff --git a/tests/probe_responder.cpp b/tests/probe_responder.cpp index e5c1fd1f..a4aabadc 100644 --- a/tests/probe_responder.cpp +++ b/tests/probe_responder.cpp @@ -38,7 +38,7 @@ #include static const uint8_t kBssid[6] = {0x57, 0x42, 0x75, 0x05, 0xd6, 0x00}; -static IRtlDevice* g_dev = nullptr; +static IRadio* g_dev = nullptr; static std::vector g_rt; // radiotap prefix (6M) static uint8_t g_chan = 6; static std::atomic g_reqs{0}, g_resps{0}; @@ -92,7 +92,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); g_dev = dev.get(); if (!g_dev) return 1; g_rt = devourer::build_stream_radiotap(devourer::parse_tx_mode_str("6M")); diff --git a/tests/retune_bench.cpp b/tests/retune_bench.cpp index 6162876a..ae6ecdae 100644 --- a/tests/retune_bench.cpp +++ b/tests/retune_bench.cpp @@ -63,7 +63,7 @@ int main(int argc, char **argv) { } WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); if (!dev) { fprintf(stderr, "no driver for this chip\n"); return 1; } // Bring up TX at 20 MHz on the target channel. diff --git a/tests/rtl8733b_txpwr_regcheck.sh b/tests/rtl8733b_txpwr_regcheck.sh index 60be641b..0c21149d 100755 --- a/tests/rtl8733b_txpwr_regcheck.sh +++ b/tests/rtl8733b_txpwr_regcheck.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Register-level validation of the RTL8733B runtime TX-power offset -# (IRtlDevice::SetTxPowerOffsetQdb / GetTxPowerState), the on-device +# (IRadio::SetTxPowerOffsetQdb / GetTxPowerState), the on-device # counterpart to tests/rtl8733b_txpwr_selftest.cpp's pure math and to # tests/txpwr_offset_onair.sh's slope measurement. # diff --git a/tests/rx_quality_selftest.cpp b/tests/rx_quality_selftest.cpp index f99db857..1f5b3c08 100644 --- a/tests/rx_quality_selftest.cpp +++ b/tests/rx_quality_selftest.cpp @@ -1,6 +1,6 @@ /* Headless guard for the RxQuality accumulator + build_rx_quality fuse * (src/RxQuality.h) — the windowed RX-link-quality feed behind - * rx.quality event / IRtlDevice::GetRxQuality(). Verifies the aggregate + * rx.quality event / IRadio::GetRxQuality(). Verifies the aggregate * math (mean/max/min, EVM present-gate), the PASSIVE noise-floor formula * (nf_dbm = (rssi_raw-110) - snr_raw/2), the unit conversions, and that the * fused verdict matches classify_link_health. A regression fails ctest instead diff --git a/tests/tsf_probe.cpp b/tests/tsf_probe.cpp index 5588bf2d..35431073 100644 --- a/tests/tsf_probe.cpp +++ b/tests/tsf_probe.cpp @@ -54,7 +54,7 @@ int main(int argc, char** argv) { std::shared_ptr lock; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lock) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lock, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lock, devourer_config_from_env()); if (!dev) return 1; // TSF_REG=1: read the host-facing TSF register standalone (TX bring-up, no RX diff --git a/tests/tsf_tdoa_probe.cpp b/tests/tsf_tdoa_probe.cpp index 8f98c869..d61afc8e 100644 --- a/tests/tsf_tdoa_probe.cpp +++ b/tests/tsf_tdoa_probe.cpp @@ -76,7 +76,7 @@ static libusb_device_handle* open_pid(libusb_context* ctx, uint16_t vid, return h; } -static void run_rx(IRtlDevice* dev, int idx) { +static void run_rx(IRadio* dev, int idx) { Recon recon; auto cb = [&, idx](const Packet& p) { auto pr = tdma::parse_frame(p.Data.data(), p.Data.size()); @@ -119,8 +119,8 @@ int main(int argc, char** argv) { auto* hB = open_pid(ctx, vB, pB, logger, lkB); if (!hA || !hB) return 1; WiFiDriver wifi(logger); - auto devA = wifi.CreateRtlDevice(hA, ctx, lkA, devourer_config_from_env()); - auto devB = wifi.CreateRtlDevice(hB, ctx, lkB, devourer_config_from_env()); + auto devA = wifi.CreateRadio(hA, ctx, lkA, devourer_config_from_env()); + auto devB = wifi.CreateRadio(hB, ctx, lkB, devourer_config_from_env()); if (!devA || !devB) { fprintf(stderr, "device create failed\n"); return 1; } std::thread tA([&] { run_rx(devA.get(), 0); }); diff --git a/tests/tx_quiesce_selftest.cpp b/tests/tx_quiesce_selftest.cpp index fd33dce9..e2ee52b8 100644 --- a/tests/tx_quiesce_selftest.cpp +++ b/tests/tx_quiesce_selftest.cpp @@ -1,4 +1,4 @@ -/* Headless guard for the TX quiesce seam (IRtlTransport::quiesce_tx, +/* Headless guard for the TX quiesce seam (ITransport::quiesce_tx, * RtlAdapter::quiesce_tx). * * What this covers: that the quiesce call reaches the transport through the @@ -33,7 +33,7 @@ namespace { /* Models the asynchronous half of a USB transport: a send is accepted while * running and refused once quiesced, and quiesce is what drains. */ -class FakeAsyncTransport final : public devourer::IRtlTransport { +class FakeAsyncTransport final : public devourer::ITransport { public: int accepted = 0; int refused = 0; @@ -78,7 +78,7 @@ class FakeAsyncTransport final : public devourer::IRtlTransport { /* A transport whose TX is synchronous has nothing outstanding, so it inherits * the interface's no-op — the property the HalMAC generations depend on. */ -class SyncOnlyTransport final : public devourer::IRtlTransport { +class SyncOnlyTransport final : public devourer::ITransport { public: bool is_usb() const override { return false; } uint8_t read8(uint16_t) override { return 0; } diff --git a/tests/txegress_witness.cpp b/tests/txegress_witness.cpp index 233511b0..0c5c27da 100644 --- a/tests/txegress_witness.cpp +++ b/tests/txegress_witness.cpp @@ -69,7 +69,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); if (!dev) return 1; auto cb = [](const Packet& p) { diff --git a/tests/txpwr_offset_regcheck.sh b/tests/txpwr_offset_regcheck.sh index 1054f0b1..d8878a5a 100755 --- a/tests/txpwr_offset_regcheck.sh +++ b/tests/txpwr_offset_regcheck.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Register-level validation of the runtime TX-power API (IRtlDevice:: +# Register-level validation of the runtime TX-power API (IRadio:: # SetTxPowerOffsetQdb / SetTxPowerIndexOverride / GetTxPowerState). # # Cells per plugged DUT (skip-if-unplugged, PASS/FAIL/SKIP tally like diff --git a/tests/txpwr_rate_diffs_regcheck.sh b/tests/txpwr_rate_diffs_regcheck.sh index d99d15d6..4936b26c 100755 --- a/tests/txpwr_rate_diffs_regcheck.sh +++ b/tests/txpwr_rate_diffs_regcheck.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Regression validation of the per-rate TX-power diff table -# (IRtlDevice::SetTxPowerRateDiffs / GetTxPowerState.rate_diffs_custom), +# (IRadio::SetTxPowerRateDiffs / GetTxPowerState.rate_diffs_custom), # exercised end-to-end through the txpower demo's --rate-diffs flag, on every # plugged DUT that advertises the knob (txpwr.caps rate_diffs=1 — the device's # own advertisement, so this table needs no per-chip support list). diff --git a/tests/ue_rx_probe.cpp b/tests/ue_rx_probe.cpp index 615f64c2..1ab28818 100644 --- a/tests/ue_rx_probe.cpp +++ b/tests/ue_rx_probe.cpp @@ -53,7 +53,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); if (!dev) return 1; auto cb = [](const Packet& p) { diff --git a/tests/ul_trigger_ap.cpp b/tests/ul_trigger_ap.cpp index 587be9af..c61d514f 100644 --- a/tests/ul_trigger_ap.cpp +++ b/tests/ul_trigger_ap.cpp @@ -46,7 +46,7 @@ // Locally-administered unicast BSSID (a station cannot unicast-auth to a // multicast address — see ap_responder.cpp). static const uint8_t kBssid[6] = {0x02, 0x42, 0x75, 0x05, 0xd6, 0x00}; -static IRtlDevice* g_dev = nullptr; +static IRadio* g_dev = nullptr; static std::vector g_rt; static uint8_t g_chan = 36; static std::atomic g_probe{0}, g_auth{0}, g_assoc{0}, g_sent{0}, g_data{0}; @@ -309,7 +309,7 @@ int main(int argc, char** argv) { std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), logger, true, lk) != 0) return 1; WiFiDriver wifi(logger); - auto dev = wifi.CreateRtlDevice(h, ctx, lk, devourer_config_from_env()); + auto dev = wifi.CreateRadio(h, ctx, lk, devourer_config_from_env()); g_dev = dev.get(); if (!g_dev) return 1; if (!g_dev->GetAdapterCaps().trigger_ul_ok) { From 643726b8d1ad8a43c518156ee9423fb83faa20c9 Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:42:03 +0300 Subject: [PATCH 2/4] docs: describe IRadio as the vendor-neutral radio contract Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_015VtdB2ZryKELUwREjPBH3v --- CLAUDE.md | 2 ++ docs/driver-primer.md | 5 +++-- src/IRadio.h | 5 +++-- src/mt7612u/tools/bringup.c | 2 +- src/mt7612u/usb.c | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8ab6cc1c..8b74344e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -528,6 +528,8 @@ the backend's header before believing a cross-generation claim. Generation-agnostic core in `src/` (always compiled; depends on no HAL): +- `IRadio` (`src/IRadio.h`) — the vendor-neutral radio contract every backend + implements; `WiFiDriver::CreateRadio` returns one. - `WiFiDriver` — the factory (`CreateRadio`). - `DeviceConfig.h` — construction-time configuration struct; every component copies the sub-struct it consumes at construction. diff --git a/docs/driver-primer.md b/docs/driver-primer.md index 7ff42609..adb3c9ca 100644 --- a/docs/driver-primer.md +++ b/docs/driver-primer.md @@ -50,7 +50,8 @@ access is a vendor **control transfer**: the host submits a **URB** (USB request block) to the kernel's USB stack, the request crosses the wire with the register address packed into its setup fields, and the chip answers with the data. That's the whole trick — `lsusb`-level plumbing, no kernel driver magic. devourer's -`RtlAdapter` (`src/Transport.h`) is nothing but this, and the vendor equivalent +`RtlAdapter` (`src/RtlAdapter.h`, over `devourer::UsbTransport` in +`src/UsbTransport.h`) is nothing but this, and the vendor equivalent is `usb_ops_linux.c` in each tree. The address space is a map you'll internalize fast: the MAC's registers occupy the @@ -442,7 +443,7 @@ find each in the vendor trees and in devourer. | PA / LNA | power amp (TX) / low-noise amp (RX) front end | 1 | board-level; selected by RFE type | | WCPU | the MAC's embedded CPU running firmware | 1,5 | booted by FWDL | | A-die / D-die | analog / digital silicon dies in one package | 1,9 | reached via DAV / DDV | -| URB | USB request block — one queued USB transfer | 2 | `usb_ops_linux.c` / `src/Transport.h` | +| URB | USB request block — one queued USB transfer | 2 | `usb_ops_linux.c` / `src/UsbTransport.h` | | chip id | which die design; drives HAL dispatch | 3 | `SYS_CFG` / `WiFiDriver` factory | | cut | silicon revision (A/B/C…) | 3 | gates tables + firmware images | | RFE (type) | board's RF front-end wiring variant, from efuse | 3 | gates PHY table blocks | diff --git a/src/IRadio.h b/src/IRadio.h index 61561b88..50b63acd 100644 --- a/src/IRadio.h +++ b/src/IRadio.h @@ -35,8 +35,9 @@ struct TxPacketView { size_t len; }; -/* IRadio is the chip-family-agnostic device contract used by the demos and - * the WiFiDriver factory. The production family implementations are: +/* IRadio is the vendor-neutral radio contract used by the demos and the + * WiFiDriver factory (CreateRadio returns one). Every backend implements it; + * the production implementations today are the Realtek families: * - RtlJaguarDevice — Realtek "Jaguar" wave-1 (8812AU/8811AU/8821AU/8814AU) * - RtlJaguar2Device — Realtek "Jaguar2" (8822BU/8812BU) * - RtlJaguar3Device — Realtek "Jaguar3" (8822CU/8812EU/8822EU) diff --git a/src/mt7612u/tools/bringup.c b/src/mt7612u/tools/bringup.c index 37f7d4b4..1b291349 100644 --- a/src/mt7612u/tools/bringup.c +++ b/src/mt7612u/tools/bringup.c @@ -423,7 +423,7 @@ static int gate_chan(uint8_t chan, const char *fw_dir) /* * Exercise the adopt path - how a libusb-owning consumer (the IRadio - * wrapper) reaches this subtree. Everything else in this tool arrives through + * backend) reaches this subtree. Everything else in this tool arrives through * mt_open(), so without this gate the second entry point is never opened on * hardware at all. * diff --git a/src/mt7612u/usb.c b/src/mt7612u/usb.c index bd0349ef..083e37c1 100644 --- a/src/mt7612u/usb.c +++ b/src/mt7612u/usb.c @@ -409,7 +409,7 @@ int mt_adopt(struct mt7612u_dev *d, libusb_device_handle *h, d->kernel_was_attached = 0; if (mt_identify(d, err)) return -1; - /* Same recovery mt_open() gets: this is the path the IRadio wrapper + /* Same recovery mt_open() gets: this is the path the IRadio backend * takes, and a killed previous run wedges the device for it identically. */ mt_recover_usb(d); return 0; From 6747ec5b36cd4de122e83031cf9e10a097ab473c Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:45:37 +0300 Subject: [PATCH 3/4] core: move the Realtek-only members to IRtlRadio IRadio keeps only what any 802.11 monitor/injection radio can implement. The five members whose meaning is fixed by Realtek silicon move to IRtlRadio : public IRadio, which every Realtek backend derives from: SetXtalCap / GetXtalCap AFE crystal-cap trim code GetRxEnergy phydm FA/CCA/IGI/NHM snapshot (RxEnergy) ProbeEfuseStability EFUSE logical-map re-read, 0x8129 id DumpChipState rtw canary register dump GetFwBootStatus stays on IRadio: its struct names no Realtek constant. Callers reach them through dynamic_cast and treat nullptr as "not on this radio": doctor skips the EFUSE leg, chipstate refuses, rxdemo's energy telemetry and sweep, txdemo's hopset sensing and xtal stepping, chanmig's probe and chanscout's dwells each say so once and carry on with frame statistics only. tests/radio_iface_selftest.cpp implements IRadio's pure-virtual core with no Realtek type and pins the not-ported defaults; ctest cell radio_iface. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_015VtdB2ZryKELUwREjPBH3v --- CLAUDE.md | 11 +++- CMakeLists.txt | 12 ++++ docs/adapter-doctor.md | 5 +- docs/narrowband.md | 2 +- docs/rx-spectrum-sensing.md | 2 +- examples/chanmig/main.cpp | 16 +++-- examples/chanscout/main.cpp | 12 +++- examples/chipstate/main.cpp | 10 +++- examples/doctor/main.cpp | 7 ++- examples/rx/main.cpp | 25 +++++--- examples/tx/main.cpp | 21 +++++-- src/AdapterHealth.h | 6 +- src/CfoTracker.h | 2 +- src/DeviceConfig.h | 2 +- src/IRadio.h | 90 +++++------------------------ src/IRtlRadio.h | 90 +++++++++++++++++++++++++++++ src/RxPacket.h | 2 +- src/RxSense.h | 2 +- src/jaguar1/RadioManagementModule.h | 2 +- src/jaguar1/RtlJaguarDevice.h | 4 +- src/jaguar2/RtlJaguar2Device.h | 4 +- src/jaguar3/RtlJaguar3Device.h | 4 +- src/kestrel/RtlKestrelDevice.h | 4 +- src/rtl8733b/Rtl8733bDevice.h | 4 +- tests/radio_iface_selftest.cpp | 55 ++++++++++++++++++ 25 files changed, 272 insertions(+), 122 deletions(-) create mode 100644 src/IRtlRadio.h create mode 100644 tests/radio_iface_selftest.cpp diff --git a/CLAUDE.md b/CLAUDE.md index 8b74344e..56da05a0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -60,7 +60,7 @@ construction from the `SYS_CFG2` chip-id (Kestrel: PID-first): 20/40 MHz on 2.4/5 GHz, plus long-preamble CCK on 2.4 GHz at 20 MHz, plus 10 MHz narrowband (5 MHz refused — `src/rtl8733b/CLAUDE.md`). Everything the backend has not ported (TSF/beacons, A-MPDU, CCX/`tx.report`, - the flat-index and per-rate TX-power knobs) falls through to `IRadio`'s + the flat-index and per-rate TX-power knobs) falls through to `IRadio`/`IRtlRadio`'s not-ported defaults rather than being faked, so read the base class before assuming a cross-generation feature below applies here. `FastRetune` IS ported (intra-band, TSSI kept live — `src/rtl8733b/CLAUDE.md`). SGI, LDPC, STBC, VHT @@ -173,7 +173,8 @@ second back-to-back `sdr_duty` read can fail to reacquire and report ~0). Suspect a DUT itself (deaf with a green init, chronic FW-boot fails): `build/doctor` grades adapter health — EFUSE read-stability ×N, fw-boot, -RX smoke → HEALTHY/SUSPECT/FAILING in the exit code; +RX smoke → HEALTHY/SUSPECT/FAILING in the exit code (EFUSE stability is +`IRtlRadio`-only; the other legs are `IRadio`); `tests/adapter_doctor_cold.sh` wraps it in per-rep VBUS cold + a vouched flood for a definitive verdict (`docs/adapter-doctor.md`). Two cold-init traps it encodes: the in-tree rtw88 modules auto-probe (and fw-download @@ -521,7 +522,11 @@ loop; `InitWrite` = TX bring-up; `StartRxLoop` = blocking RX worker on an already-up chip, enabling TX+RX on one handle; `send_packet`) and constructs `RtlJaguarDevice` / `RtlJaguar2Device` / `RtlJaguar3Device` / `RtlKestrelDevice` / `Rtl8733bDevice` per backend. `Rtl8812aDevice` is a deprecated alias of -`RtlJaguarDevice`. Optional device methods are **virtual with not-ported +`RtlJaguarDevice`. The five Realtek backends derive from `IRtlRadio` +(`src/IRtlRadio.h`), which adds the Realtek-only members (`GetRxEnergy`, +`SetXtalCap`/`GetXtalCap`, `ProbeEfuseStability`, `DumpChipState`); reach them +via `dynamic_cast` and treat `nullptr` as "not on this radio". +Optional device methods are **virtual with not-ported defaults**, not pure virtual — a backend that hasn't ported a feature inherits `false`/`0`/a full-path fallback rather than a fake. Check the override list in the backend's header before believing a cross-generation claim. diff --git a/CMakeLists.txt b/CMakeLists.txt index be36a29e..8b1a9c03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,7 @@ add_library(devourer src/hopset/HopsetFusion.h src/hopset/HopsetEvents.h src/IRadio.h + src/IRtlRadio.h src/SignalStop.cpp src/SignalStop.h src/WiFiDriver.cpp @@ -775,6 +776,17 @@ target_link_libraries(ToneMaskSelftest PRIVATE devourer) add_test(NAME tone_mask_math COMMAND ToneMaskSelftest) +# Headless guard for the radio contract: a radio implementing only IRadio's +# pure-virtual core must compile without any Realtek type, its not-ported +# defaults must hold, and it must not be an IRtlRadio. A Realtek-typed pure +# virtual added to IRadio stops this compiling, which is the point. +add_executable(RadioIfaceSelftest + tests/radio_iface_selftest.cpp +) +target_link_libraries(RadioIfaceSelftest PRIVATE devourer) + +add_test(NAME radio_iface COMMAND RadioIfaceSelftest) + # 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 diff --git a/docs/adapter-doctor.md b/docs/adapter-doctor.md index 4f4dcb2b..3b03ecf8 100644 --- a/docs/adapter-doctor.md +++ b/docs/adapter-doctor.md @@ -28,11 +28,12 @@ build/doctor --bus 3 --port 2.3.3 # topology select (two same-PID adapters) 1. **Bring-up** — `InitWrite`; an abort is an immediate FAILING. 2. **EFUSE stability** — N fresh *physical* map reads - (`IRadio::ProbeEfuseStability`), cross-compared byte-for-byte + + (`IRtlRadio::ProbeEfuseStability`), cross-compared byte-for-byte + EEPROM-ID (0x8129) validated. Any read-to-read mismatch is conclusive by itself. Not probed on the 8822E — its OTP is not reliably readable after bring-up by design, so probing would flag - healthy units. + healthy units. Realtek-only (`IRtlRadio`): on another radio doctor + skips this step and grades the remaining legs. 3. **FW boot** — checksum + MCU-ready outcome of the bring-up's download (`IRadio::GetFwBootStatus`). 4. **RX smoke** — FCS-clean frame count over `--listen-secs`. Ambient diff --git a/docs/narrowband.md b/docs/narrowband.md index f9767949..b169f208 100644 --- a/docs/narrowband.md +++ b/docs/narrowband.md @@ -150,7 +150,7 @@ chip-specific traps. The ones this port paid for, current-state: power-up and is deaf on the next — while a closer-crystal peer decodes the same transmitter and the same pair is stable at 2.4 GHz. This is physics, not a driver bug — and it drifts, so a fixed trim is not enough (below). The - manual lever is `IRadio::SetXtalCap` (env `DEVOURER_XTAL_CAP`): + manual lever is `IRtlRadio::SetXtalCap` (env `DEVOURER_XTAL_CAP`): the AFE crystal load-capacitance trim pulls the chip's reference oscillator a few ppm, so trimming one end of a marginal pair moves the offset off the sync boundary. The trim range is per generation (`GetAdapterCaps().xtal_cap_max`: diff --git a/docs/rx-spectrum-sensing.md b/docs/rx-spectrum-sensing.md index 082bc9ad..a65523b3 100644 --- a/docs/rx-spectrum-sensing.md +++ b/docs/rx-spectrum-sensing.md @@ -87,7 +87,7 @@ event every `N` ms: "igi":..,"frames":N,"rssi_mean":..,"rssi_max":..,"snr_mean":..,"snr_min":..} ``` -`cca_*`/`fa_*`/`igi` are frame-free (`IRadio::GetRxEnergy`, `null` on a chip +`cca_*`/`fa_*`/`igi` are frame-free (`IRtlRadio::GetRxEnergy`, `null` on a chip that doesn't expose them); the FA/CCA counts are the delta since the previous event (each read resets the hardware counters). `rssi_*`/`snr_*`/`frames` are the rolling per-frame aggregate over the interval. diff --git a/examples/chanmig/main.cpp b/examples/chanmig/main.cpp index 056a1ba2..2c044734 100644 --- a/examples/chanmig/main.cpp +++ b/examples/chanmig/main.cpp @@ -40,6 +40,7 @@ #include "SignalStop.h" #include "UsbOpen.h" #include "WiFiDriver.h" +#include "IRtlRadio.h" #include "chanmig/ChannelDef.h" #include "chanmig/JsonlLite.h" #include "chanmig/MigClock.h" @@ -57,6 +58,8 @@ using devourer::Ev; static devourer::EventSink *g_ev = nullptr; static IRadio *g_dev = nullptr; +/* Realtek-only view of g_dev for the frame-free energy probe; null elsewhere. */ +static IRtlRadio *g_rtl = nullptr; static std::mutex g_dev_mu; /* serialize send/retune against the RX thread */ /* The pure state machines are single-threaded by design; the demo drives them * from the RX callback, the tick loop, and (ground) the operator thread, so @@ -380,15 +383,15 @@ static void drone_do(const std::vector &acts) { bool valid = false; { std::lock_guard lk(g_dev_mu); - if (g_dev) { - (void)g_dev->GetRxEnergy(false); /* reset the delta counters */ + if (g_rtl) { + (void)g_rtl->GetRxEnergy(false); /* reset the delta counters */ } } std::this_thread::sleep_for(std::chrono::milliseconds(dwell_ms)); { std::lock_guard lk(g_dev_mu); - if (g_dev) { - RxEnergy e = g_dev->GetRxEnergy(true); + if (g_rtl) { + RxEnergy e = g_rtl->GetRxEnergy(true); if (e.valid_nhm) { uint32_t total = 0; for (int k = 0; k < 12; k++) @@ -551,6 +554,10 @@ int main(int argc, char **argv) { session.adopt_device(std::move(owned_device)); IRadio *const dev = session.device(); g_dev = dev; + g_rtl = dynamic_cast(dev); + if (!g_rtl) + logger->warn("chanmig: the frame-free energy probe is Realtek-only " + "(IRtlRadio) — probe samples are invalid on this radio"); Ev(*g_ev, "migrate.id").t().f("role", role.c_str()) .f("chip", pick.pid).f("source", source.str().c_str()) @@ -741,6 +748,7 @@ int main(int argc, char **argv) { { std::lock_guard lk(g_dev_mu); g_dev = nullptr; + g_rtl = nullptr; } dev->Stop(); session.close(); diff --git a/examples/chanscout/main.cpp b/examples/chanscout/main.cpp index cb7f2251..259fca55 100644 --- a/examples/chanscout/main.cpp +++ b/examples/chanscout/main.cpp @@ -48,6 +48,7 @@ #include "SignalStop.h" #include "UsbOpen.h" #include "WiFiDriver.h" +#include "IRtlRadio.h" #include "caps_event.h" #include "chanmig/ChannelDef.h" #include "chanmig/ChannelEvents.h" @@ -361,8 +362,12 @@ int main() { /* --- RX loop on a worker thread (rxdemo sweep pattern) --- */ IRadio *devp = dev; + IRtlRadio *const rtl = dynamic_cast(dev); + if (!rtl) + logger->warn("chanscout: frame-free FA/CCA/NHM is Realtek-only (IRtlRadio) " + "— dwells carry frame stats only on this radio"); const cm::ScanScheduler::DwellPlan first = sched.next(steady_ms()); - std::thread rx([devp, first, &logger]() { + std::thread rx([devp, rtl, first, &logger]() { try { devp->Init(packetProcessor, first.def.to_selected()); } catch (const std::exception &e) { @@ -506,7 +511,8 @@ int main() { * frames that raced in from the previous channel. */ if (!nap_ms(cfg.settle_ms)) d.flags |= cm::kFlagTruncated; - (void)devp->GetRxEnergy(/*with_nhm=*/false); + if (rtl) + (void)rtl->GetRxEnergy(/*with_nhm=*/false); { std::lock_guard lk(g_agg_mu); g_agg = ScoutAgg{}; @@ -516,7 +522,7 @@ int main() { if (!nap_ms(cfg.dwell_ms)) d.flags |= cm::kFlagTruncated; - RxEnergy e = devp->GetRxEnergy(/*with_nhm=*/true); + RxEnergy e = rtl ? rtl->GetRxEnergy(/*with_nhm=*/true) : RxEnergy{}; ScoutAgg agg; { std::lock_guard lk(g_agg_mu); diff --git a/examples/chipstate/main.cpp b/examples/chipstate/main.cpp index 9e4e631e..0e3ea62d 100644 --- a/examples/chipstate/main.cpp +++ b/examples/chipstate/main.cpp @@ -37,7 +37,7 @@ #include #include "DeviceSession.h" -#include "IRadio.h" +#include "IRtlRadio.h" #include "RtlAdapter.h" #include "UsbOpen.h" #include "WiFiDriver.h" @@ -308,6 +308,12 @@ int main(int argc, char **argv) { "the chip is being read exactly as the last session left it"); } - dev->DumpChipState(); + auto *rtl = dynamic_cast(dev); + if (!rtl) { + logger->error("chipstate: no canary register dump on this radio (not a " + "Realtek backend)"); + return 4; + } + rtl->DumpChipState(); return 0; } diff --git a/examples/doctor/main.cpp b/examples/doctor/main.cpp index c28769be..fb1daab9 100644 --- a/examples/doctor/main.cpp +++ b/examples/doctor/main.cpp @@ -70,6 +70,7 @@ #include "SignalStop.h" #include "UsbOpen.h" #include "WiFiDriver.h" +#include "IRtlRadio.h" #include "logger.h" namespace { @@ -262,7 +263,11 @@ int main(int argc, char **argv) { if (in.init_completed) { /* 2. EFUSE stability */ - in.efuse = dev->ProbeEfuseStability(a.reads); + if (auto *rtl = dynamic_cast(dev)) + in.efuse = rtl->ProbeEfuseStability(a.reads); + else + logger->warn("doctor: the EFUSE stability probe is Realtek-only " + "(IRtlRadio) — skipped on this radio"); /* 4. RX smoke */ if (a.listen_secs > 0 && !g_devourer_should_stop) { diff --git a/examples/rx/main.cpp b/examples/rx/main.cpp index 19911464..2f6a3460 100644 --- a/examples/rx/main.cpp +++ b/examples/rx/main.cpp @@ -46,6 +46,7 @@ #include "SignalStop.h" #include "UsbOpen.h" #include "WiFiDriver.h" +#include "IRtlRadio.h" #include "env_config.h" #include "usb_select.h" #if defined(DEVOURER_HAVE_PCIE) @@ -532,7 +533,7 @@ static void run_la_capture( /* DEVOURER_RX_ENERGY_MS=N: periodic frame-free RX energy / channel-busy * telemetry — the read side of DEVOURER_CW_TONE. Each interval emits one * rx.energy event combining the chip's phydm FA/CCA counters + IGI - * (IRadio::GetRxEnergy, frame-free, all three generations) with a rolling + * (IRtlRadio::GetRxEnergy, frame-free, all three generations) with a rolling * per-frame RSSI/SNR aggregate. A second adapter running this detects the first * adapter's CW carrier as a jump in cca_ofdm / fa_ofdm and a rise in igi. * 0 = disabled. */ @@ -694,7 +695,7 @@ static const bool g_rx_pctr = []() { return e != nullptr && std::strcmp(e, "0") != 0; }(); -/* Emit the frame-free NHM power histogram (IRadio::GetRxEnergy fills it) as +/* Emit the frame-free NHM power histogram (IRtlRadio::GetRxEnergy fills it) as * a distinct rx.nhm event so it never disturbs the rx.energy * fields its consumers key on. `peak` = the fullest bucket (0 = quiet * noise floor, higher = energy is landing in a higher power band, e.g. under an @@ -1566,8 +1567,8 @@ int main(int argc, char **argv) { } /* DEVOURER_RX_ENERGY_MS: frame-free RX energy / channel-busy telemetry — the - * read side of DEVOURER_CW_TONE. Cross-generation (IRadio::GetRxEnergy), - * so it runs off the base device pointer, not the Jaguar1 downcast. The thread + * read side of DEVOURER_CW_TONE. Cross-generation (IRtlRadio::GetRxEnergy), + * so it runs off the IRtlRadio cast, not the Jaguar1 downcast. The thread * sleeps one interval first (so its first read lands after bring-up completes, * not mid-init), then each interval reads GetRxEnergy() + drains the rolling * frame aggregate and emits one rx.energy event. Concurrency caveat: @@ -1575,10 +1576,14 @@ int main(int argc, char **argv) { * poller) — keep the cadence conservative (>= a few hundred ms). */ std::atomic energy_emitter_stop{false}; std::thread energy_emitter; - if (g_rx_energy_ms > 0) { + IRtlRadio *const energy_dev = dynamic_cast(rtlDevice); + if (g_rx_energy_ms > 0 && !energy_dev) + logger->warn("DEVOURER_RX_ENERGY_MS: frame-free energy is Realtek-only " + "(IRtlRadio) — telemetry not started on this radio"); + if (g_rx_energy_ms > 0 && energy_dev) { logger->info("DEVOURER_RX_ENERGY_MS={} — starting RX energy telemetry", g_rx_energy_ms); - IRadio *dev = rtlDevice; + IRtlRadio *dev = energy_dev; energy_emitter = std::thread([&energy_emitter_stop, dev]() { auto nap = [&](uint32_t ms) { for (uint32_t s = 0; s < ms && !energy_emitter_stop.load(); s += 50) @@ -2067,8 +2072,12 @@ int main(int argc, char **argv) { logger->info("DEVOURER_RX_SWEEP: {} bins, dwell {} ms — live spectrum map", g_rx_sweep.size(), g_rx_sweep_dwell_ms); IRadio *dev = rtlDevice; + IRtlRadio *const rtl = dynamic_cast(rtlDevice); + if (!rtl) + logger->warn("DEVOURER_RX_SWEEP: frame-free energy is Realtek-only " + "(IRtlRadio) — bins carry frame stats only"); SelectedChannel first{static_cast(g_rx_sweep[0]), ch_offset, width}; - std::thread rx([dev, first, &logger]() { + std::thread rx([dev, rtl, first, &logger]() { try { dev->Init(packetProcessor, first); } catch (const std::exception &e) { @@ -2110,7 +2119,7 @@ int main(int argc, char **argv) { for (uint32_t s = 0; s < g_rx_sweep_dwell_ms && !g_devourer_should_stop; s += 50) std::this_thread::sleep_for(std::chrono::milliseconds(50)); - RxEnergy e = dev->GetRxEnergy(true); + RxEnergy e = rtl ? rtl->GetRxEnergy(true) : RxEnergy{}; RxAgg agg; { std::lock_guard lk(g_rxagg_mu); diff --git a/examples/tx/main.cpp b/examples/tx/main.cpp index 3840fb1f..01b57b02 100644 --- a/examples/tx/main.cpp +++ b/examples/tx/main.cpp @@ -64,6 +64,7 @@ #include "PcieTransport.h" #endif #include "WiFiDriver.h" +#include "IRtlRadio.h" #include "env_config.h" #include "RadiotapBuilder.h" #include "logger.h" @@ -221,7 +222,7 @@ static void hopset_route( * * window_us is measured, not nominal — the hardware keeps counting during the * read's own bus round-trips, so excluding that time would inflate the rate. */ -static bool hopset_sense_window(IRadio *dev, uint32_t settle_us, +static bool hopset_sense_window(IRtlRadio *dev, uint32_t settle_us, uint32_t window_us, bool with_nhm, devourer::hopset::SensePhase phase, uint64_t slot, uint64_t round, @@ -814,6 +815,10 @@ int main(int argc, char **argv) { #if defined(DEVOURER_HAVE_JAGUAR3) RtlJaguar3Device *jag3 = dynamic_cast(rtlDevice); #endif + /* Realtek-only members (frame-free energy counters, the crystal-cap trim). + * Null on a non-Realtek radio; every feature that needs it says so and + * skips rather than reporting a fictional measurement. */ + IRtlRadio *const rtlRadio = dynamic_cast(rtlDevice); int channel = 161; if (const char *ch_env = std::getenv("DEVOURER_CHANNEL")) { @@ -1658,6 +1663,11 @@ int main(int argc, char **argv) { * contain an unknown number of our own frames and read as interference. * A silently wrong measurement feeding an exclusion is worse than no * measurement, so refuse rather than half-gate. */ + if (!rtlRadio) { + logger->error("DEVOURER_TX_SENSE needs a Realtek radio (IRtlRadio " + "frame-free counters) — sensing not armed"); + tx_sense = false; + } if (tx_threads > 1) { logger->error("DEVOURER_TX_SENSE is incompatible with " "DEVOURER_TX_THREADS>1 — sensing not armed"); @@ -1770,13 +1780,16 @@ int main(int argc, char **argv) { int dwell = 4000; if (const char *ms = std::getenv("DEVOURER_XTAL_STEP_MS")) dwell = std::atoi(ms); + if (!rtlRadio) + logger->warn("DEVOURER_XTAL_STEP is Realtek-only (IRtlRadio) — " + "steps are logged with cap=-1 on this radio"); std::string s(steps); size_t pos = 0; while (!g_devourer_should_stop && pos < s.size()) { size_t comma = s.find(',', pos); int cap = std::strtol(s.substr(pos, comma - pos).c_str(), nullptr, 0); pos = (comma == std::string::npos) ? s.size() : comma + 1; - int applied = rtlDevice->SetXtalCap(cap); + int applied = rtlRadio ? rtlRadio->SetXtalCap(cap) : -1; devourer::Ev(*g_ev, "xtal.step").f("cap", applied); logger->info("xtal.step cap=0x{:02x}", applied); for (int t = 0; t < dwell && !g_devourer_should_stop; t += 100) @@ -2051,7 +2064,7 @@ int main(int argc, char **argv) { if (committing) { sense_armed = false; } else { - hopset_sense_window(rtlDevice, tx_sense_settle_us, + hopset_sense_window(rtlRadio, tx_sense_settle_us, tx_sense_window_us, tx_sense_nhm, devourer::hopset::SensePhase::PreBurst, desired_slot, round, @@ -2084,7 +2097,7 @@ int main(int argc, char **argv) { gen = g_hopset_view->state().generation; } sense_post_done = true; - hopset_sense_window(rtlDevice, 0, tx_sense_post_us, + hopset_sense_window(rtlRadio, 0, tx_sense_post_us, tx_sense_nhm, devourer::hopset::SensePhase::PostBurst, desired_slot, round, diff --git a/src/AdapterHealth.h b/src/AdapterHealth.h index 1b22569f..5d325d7f 100644 --- a/src/AdapterHealth.h +++ b/src/AdapterHealth.h @@ -16,8 +16,8 @@ * validity, the firmware-boot outcome of the last bring-up, and an RX smoke * count. The classifier maps those to a plain verdict + reason bits. * - * IRadio carries the probe entry points (ProbeEfuseStability, - * GetFwBootStatus); examples/doctor is the reference consumer. + * IRtlRadio carries ProbeEfuseStability and IRadio carries GetFwBootStatus; + * examples/doctor is the reference consumer. */ #ifndef DEVOURER_ADAPTER_HEALTH_H #define DEVOURER_ADAPTER_HEALTH_H @@ -46,7 +46,7 @@ struct EfuseStability { uint16_t first_mismatch_off = 0xFFFF; /* first differing offset, if any */ }; -/* Shared probe loop behind IRadio::ProbeEfuseStability — each generation +/* Shared probe loop behind IRtlRadio::ProbeEfuseStability — each generation * supplies its own fresh-physical-map reader as `read_map(uint8_t *buf)` * (return false on transport failure) and this does the cross-compare. */ template diff --git a/src/CfoTracker.h b/src/CfoTracker.h index 2ee9872b..e101ef90 100644 --- a/src/CfoTracker.h +++ b/src/CfoTracker.h @@ -9,7 +9,7 @@ namespace devourer { /* Closed-loop carrier-frequency-offset tracker (issue #217). Ported from the * vendor phydm_cfo_tracking control law: accumulate the per-frame path-A CFO * tail from the RX phy-status, and on a periodic tick step the crystal-cap - * trim (IRadio::SetXtalCap) by ±1 to drive the average CFO toward zero. + * trim (IRtlRadio::SetXtalCap) by ±1 to drive the average CFO toward zero. * * A bang-bang integrator with hysteresis: it starts correcting once |CFO| * exceeds an enable threshold and stops inside a deadband, so it doesn't diff --git a/src/DeviceConfig.h b/src/DeviceConfig.h index c3d8971d..86d9fad2 100644 --- a/src/DeviceConfig.h +++ b/src/DeviceConfig.h @@ -403,7 +403,7 @@ struct DeviceConfig { * (stub default 0xa/0xb). */ std::optional nb_adc; /* env: DEVOURER_XTAL_CAP — crystal-cap trim code applied at the end of - * bring-up (IRadio::SetXtalCap). The CFO lever for narrowband at the + * bring-up (IRtlRadio::SetXtalCap). The CFO lever for narrowband at the * edge of its budget; unset = efuse/default. Raw code, 0..0x3f (Jaguar1/2) * or 0..0x7f (Jaguar3). */ std::optional xtal_cap; diff --git a/src/IRadio.h b/src/IRadio.h index 50b63acd..a3816a00 100644 --- a/src/IRadio.h +++ b/src/IRadio.h @@ -11,7 +11,6 @@ #include "DeviceConfig.h" #include "AdapterHealth.h" #include "RxQuality.h" -#include "RxSense.h" #include "SelectedChannel.h" #include "ThermalStatus.h" #include "Sounding.h" @@ -36,17 +35,17 @@ struct TxPacketView { }; /* IRadio is the vendor-neutral radio contract used by the demos and the - * WiFiDriver factory (CreateRadio returns one). Every backend implements it; - * the production implementations today are the Realtek families: - * - RtlJaguarDevice — Realtek "Jaguar" wave-1 (8812AU/8811AU/8821AU/8814AU) - * - RtlJaguar2Device — Realtek "Jaguar2" (8822BU/8812BU) - * - RtlJaguar3Device — Realtek "Jaguar3" (8822CU/8812EU/8822EU) - * - Rtl8733bDevice — Realtek HALMAC 87xx 11n (RTL8731BU/RTL8733BU) - * - RtlKestrelDevice — Realtek G6 11ax (RTL8852BU/RTL8852CU) + * WiFiDriver factory (CreateRadio returns one). Optional members are virtual + * with not-ported defaults; the pure-virtual core is Init / InitWrite / + * StartRxLoop / SetMonitorChannel / send_packet / GetSelectedChannel / + * SetCcaMode. * - * Chip-family-specific research helpers (BB-debug-port reads, the 8814 queue - * poller, ...) are intentionally NOT part of this interface — callers that need - * them dynamic_cast down to the concrete type. */ + * Realtek-specific members (phydm energy counters, EFUSE stability, the + * crystal-cap trim, the canary register dump) live on IRtlRadio + * (src/IRtlRadio.h), which every Realtek backend derives from; per-generation + * research helpers (BB-debug-port reads, the 8814 queue poller, ...) live on + * the concrete classes. Callers that need either level dynamic_cast down and + * treat nullptr as "not available on this radio". */ class IRadio { public: virtual ~IRadio() = default; @@ -159,23 +158,6 @@ class IRadio { * any knob. Returns false when unsupported or the chip isn't brought up. */ virtual bool ReApplyTxPower() { return false; } - /* Crystal (XTAL) load-capacitance trim — the CFO lever. Writes the AFE - * crystal-cap field (a per-chip register), pulling the chip's reference - * oscillator a few ppm to align a marginal TX/RX crystal pair; the payoff - * is narrowband at the edge of its CFO budget (5 MHz at 5 GHz). `cap` is a - * raw trim code in [0, GetAdapterCaps().xtal_cap_max]; cap < 0 reverts to - * the efuse/default value. Both physical caps (Xi/Xo) are set together. - * Returns the applied code, or -1 when unsupported. Sticky across channel - * changes (an AFE register, untouched by the RF retune). */ - virtual int SetXtalCap(int cap) { - (void)cap; - return -1; - } - - /* Current crystal-cap code (the last SetXtalCap value, or the efuse default - * at bring-up). -1 when unsupported. */ - virtual int GetXtalCap() { return -1; } - /* Snapshot of the knob state + representative effective indices (register * readback where the family's TXAGC block is readable). */ virtual devourer::TxPowerState GetTxPowerState() { return {}; } @@ -555,67 +537,25 @@ class IRadio { * all-zero snapshot. */ virtual devourer::TxStats GetTxStats() { return {}; } - /* Frame-free RX energy / channel-busy snapshot (see RxSense.h) — the read side - * of the DEVOURER_CW_TONE emitter, used for spectrum-sensing / interferer - * detection. Reads the chip's phydm false-alarm + CCA counters, DIG/IGI, and - * (when asked) the NHM power histogram. FA/CCA counts are the delta since the - * previous call. Default returns an all-invalid snapshot; each generation - * overrides with a real reader. - * - * `with_nhm` is a cost decision, not a preference: the NHM read arms a ~2 ms - * measurement window and then polls a ready bit at 1 ms granularity - * (src/NhmReader.h), so it dominates the call — the scalar FA/CCA/IGI path is - * a handful of register reads. Pass false for the throwaway read that resets - * the delta counters before an observation window, and for any caller - * sampling faster than a few times a second. */ - virtual RxEnergy GetRxEnergy(bool with_nhm) { (void)with_nhm; return {}; } - /* Consolidated windowed RX link-quality snapshot (see RxQuality.h) — the * runtime feed a closed-loop adaptive-link controller reads instead of * scraping the demo's stdout. Fuses the per-frame RSSI/SNR/EVM aggregate the * device accumulates internally, a passive noise-floor estimate (rssi - snr, * the self-jamming signal), the frame-free FA/CCA/IGI energy, and the - * LinkHealth verdict. Drains the window (delta semantics) and SUBSUMES - * GetRxEnergy (it calls it internally + consumes the FA/CCA delta — don't also - * poll GetRxEnergy separately on the same cadence). Default is an all-invalid + * LinkHealth verdict. Drains the window (delta semantics); on the Realtek + * backends it consumes the same FA/CCA/IGI delta that IRtlRadio::GetRxEnergy + * reads, so do not poll both on the same cadence. Default is an all-invalid * snapshot; each generation overrides. */ virtual devourer::RxQuality GetRxQuality() { return {}; } - /* --- Adapter-health probes (see src/AdapterHealth.h; examples/doctor is - * the reference consumer) --- */ - - /* Perform `reads` fresh PHYSICAL EFUSE logical-map reads (each pass re-runs - * the efuse-controller read sequence — not the cached shadow) and - * cross-compare them. Dying silicon returns different content per read; - * healthy silicon is byte-identical every time. Post-bring-up only: returns - * supported=false before Init/InitWrite (on the 8814AU a pre-fwdl EFUSE - * read breaks the RSVD-page firmware download). Control-plane threading - * contract applies (same as SetMonitorChannel). */ - virtual devourer::EfuseStability ProbeEfuseStability(int reads = 4) { - (void)reads; - return {}; - } + /* --- Adapter health (see src/AdapterHealth.h; examples/doctor is the + * reference consumer; the EFUSE probe is on IRtlRadio) --- */ /* Outcome of the most recent firmware download (populated during * Init/InitWrite). On Jaguar1 a failed FW boot does not abort bring-up — * this is the only place the failure is visible to a caller. */ virtual devourer::FwBootStatus GetFwBootStatus() { return {}; } - /* Dump the chip's canary register set (BB / MAC / per-path RF) to the - * diagnostic plane. Reads only — no writes, no calibration, no bring-up. - * - * The point is that it is callable on a device that has NOT been Init'ed, so - * a chip left in whatever state a previous session abandoned it in can be - * inspected AS IT IS. Every other path into this driver reconfigures the chip - * on the way in, which destroys exactly the evidence a state bug leaves - * behind. Pair it with an open that skips libusb_reset_device - * (claim_interface_then_reset's `do_reset=false`) — a USB reset re-runs the - * chip's own boot and is just as destructive. - * - * Output format matches DEVOURER_DUMP_CANARY, so two dumps diff directly with - * tests/canary_diff.py. Reading a powered-down chip yields garbage or throws; - * interpreting that is the caller's job. No-op where unsupported (default). */ - virtual void DumpChipState() {} }; #endif /* IRADIO_H */ diff --git a/src/IRtlRadio.h b/src/IRtlRadio.h new file mode 100644 index 00000000..a3f07943 --- /dev/null +++ b/src/IRtlRadio.h @@ -0,0 +1,90 @@ +#ifndef IRTL_RADIO_H +#define IRTL_RADIO_H + +#include "IRadio.h" + +#include "AdapterHealth.h" /* EfuseStability */ +#include "RxSense.h" /* RxEnergy */ + +/* IRtlRadio is the Realtek-family extension of IRadio: the members whose + * semantics are defined by Realtek silicon (phydm false-alarm / CCA / IGI / NHM + * counters, the EFUSE logical map and its 0x8129 EEPROM id, the AFE crystal-cap + * register, the rtw canary register set) rather than by a vendor-neutral + * concept. Every Realtek backend derives from it: + * - RtlJaguarDevice — Realtek "Jaguar" wave-1 (8812AU/8811AU/8821AU/8814AU) + * - RtlJaguar2Device — Realtek "Jaguar2" (8822BU/8812BU) + * - RtlJaguar3Device — Realtek "Jaguar3" (8822CU/8812EU/8822EU) + * - Rtl8733bDevice — Realtek HALMAC 87xx 11n (RTL8731BU/RTL8733BU) + * - RtlKestrelDevice — Realtek G6 11ax (RTL8852BU/RTL8852CU) + * + * WiFiDriver::CreateRadio returns an IRadio; a caller that needs one of these + * members dynamic_casts to IRtlRadio and treats nullptr as "not a Realtek + * radio" — skip the feature with one diagnostic, never fake a reading. + * Per-generation research helpers (BB-debug-port reads, the 8814 queue poller, + * the CW tone) stay on the concrete classes: the same convention one level + * further down. Every member here keeps the IRadio rule — virtual with a + * not-ported default, never pure. */ +class IRtlRadio : public IRadio { +public: + /* Crystal (XTAL) load-capacitance trim — the CFO lever. Writes the AFE + * crystal-cap field (a per-chip register), pulling the chip's reference + * oscillator a few ppm to align a marginal TX/RX crystal pair; the payoff + * is narrowband at the edge of its CFO budget (5 MHz at 5 GHz). `cap` is a + * raw trim code in [0, GetAdapterCaps().xtal_cap_max]; cap < 0 reverts to + * the efuse/default value. Both physical caps (Xi/Xo) are set together. + * Returns the applied code, or -1 when unsupported. Sticky across channel + * changes (an AFE register, untouched by the RF retune). */ + virtual int SetXtalCap(int cap) { + (void)cap; + return -1; + } + + /* Current crystal-cap code (the last SetXtalCap value, or the efuse default + * at bring-up). -1 when unsupported. */ + virtual int GetXtalCap() { return -1; } + + /* Frame-free RX energy / channel-busy snapshot (see RxSense.h) — the read side + * of the DEVOURER_CW_TONE emitter, used for spectrum-sensing / interferer + * detection. Reads the chip's phydm false-alarm + CCA counters, DIG/IGI, and + * (when asked) the NHM power histogram. FA/CCA counts are the delta since the + * previous call. Default returns an all-invalid snapshot; each generation + * overrides with a real reader. + * + * `with_nhm` is a cost decision, not a preference: the NHM read arms a ~2 ms + * measurement window and then polls a ready bit at 1 ms granularity + * (src/NhmReader.h), so it dominates the call — the scalar FA/CCA/IGI path is + * a handful of register reads. Pass false for the throwaway read that resets + * the delta counters before an observation window, and for any caller + * sampling faster than a few times a second. */ + virtual RxEnergy GetRxEnergy(bool with_nhm) { (void)with_nhm; return {}; } + + /* Perform `reads` fresh PHYSICAL EFUSE logical-map reads (each pass re-runs + * the efuse-controller read sequence — not the cached shadow) and + * cross-compare them. Dying silicon returns different content per read; + * healthy silicon is byte-identical every time. Post-bring-up only: returns + * supported=false before Init/InitWrite (on the 8814AU a pre-fwdl EFUSE + * read breaks the RSVD-page firmware download). Control-plane threading + * contract applies (same as SetMonitorChannel). */ + virtual devourer::EfuseStability ProbeEfuseStability(int reads = 4) { + (void)reads; + return {}; + } + + /* Dump the chip's canary register set (BB / MAC / per-path RF) to the + * diagnostic plane. Reads only — no writes, no calibration, no bring-up. + * + * The point is that it is callable on a device that has NOT been Init'ed, so + * a chip left in whatever state a previous session abandoned it in can be + * inspected AS IT IS. Every other path into this driver reconfigures the chip + * on the way in, which destroys exactly the evidence a state bug leaves + * behind. Pair it with an open that skips libusb_reset_device + * (claim_interface_then_reset's `do_reset=false`) — a USB reset re-runs the + * chip's own boot and is just as destructive. + * + * Output format matches DEVOURER_DUMP_CANARY, so two dumps diff directly with + * tests/canary_diff.py. Reading a powered-down chip yields garbage or throws; + * interpreting that is the caller's job. No-op where unsupported (default). */ + virtual void DumpChipState() {} +}; + +#endif /* IRTL_RADIO_H */ diff --git a/src/RxPacket.h b/src/RxPacket.h index fcdf0e71..c7f1c017 100644 --- a/src/RxPacket.h +++ b/src/RxPacket.h @@ -90,7 +90,7 @@ struct rx_pkt_attrib /* Path-A CFO tail from the OFDM phy-status (signed HW units; kHz = raw * * 2.5, phydm CFO_HW_RPT_2_KHZ). The carrier-frequency offset between this * receiver's crystal and the transmitter's — the closed-loop CFO tracker's - * input (see IRadio::SetXtalCap). 0 when the phy-status carries none. */ + * input (see IRtlRadio::SetXtalCap). 0 when the phy-status carries none. */ int8_t cfo_tail = 0; /* A-MPDU RX markers. paggr: this MPDU arrived inside an aggregated PPDU * (rx-desc PAGGR — 8812 dword1[15], same position in the halmac layout). diff --git a/src/RxSense.h b/src/RxSense.h index 32794e96..873d99f9 100644 --- a/src/RxSense.h +++ b/src/RxSense.h @@ -7,7 +7,7 @@ * side of the DEVOURER_CW_TONE emitter: a coarse "how much in-band energy / * channel activity is here" measurement that does NOT require receiving a frame. * - * Filled by IRadio::GetRxEnergy() from the chip's phydm facilities: + * Filled by IRtlRadio::GetRxEnergy() from the chip's phydm facilities: * - false-alarm (FA) + CCA (channel-busy) counters, * - the DIG initial-gain index (a noise-floor proxy), * - and, where triggered, the NHM in-band power histogram. diff --git a/src/jaguar1/RadioManagementModule.h b/src/jaguar1/RadioManagementModule.h index e2b6fb99..aa71583c 100644 --- a/src/jaguar1/RadioManagementModule.h +++ b/src/jaguar1/RadioManagementModule.h @@ -282,7 +282,7 @@ class RadioManagementModule { /* Read-only dump of the canary register set (BB / MAC / per-path RF) to the * diagnostic plane. Public because it is also the read-only inspection path - * for a chip that was never Init'ed — see IRadio::DumpChipState. */ + * for a chip that was never Init'ed — see IRtlRadio::DumpChipState. */ void DumpCanary(); private: diff --git a/src/jaguar1/RtlJaguarDevice.h b/src/jaguar1/RtlJaguarDevice.h index f2cfc6f7..47a73f0c 100644 --- a/src/jaguar1/RtlJaguarDevice.h +++ b/src/jaguar1/RtlJaguarDevice.h @@ -15,7 +15,7 @@ #include "BbDbgportReader.h" #include "LaCapture.h" #include "HalModule.h" -#include "IRadio.h" +#include "IRtlRadio.h" #include "SelectedChannel.h" #include "EepromManager.h" #include "RadioManagementModule.h" @@ -36,7 +36,7 @@ extern "C" * baseband). The chip is identified at construction time via SYS_CFG bits and * USB PID; this class drives bring-up, RX, and TX for whichever member of the * family is present. */ -class RtlJaguarDevice : public IRadio { +class RtlJaguarDevice : public IRtlRadio { /* Declared before every component that consumes it: members initialise in * declaration order, and _eepromManager / _radioManagement / _halModule all * take _cfg in the constructor's init list. */ diff --git a/src/jaguar2/RtlJaguar2Device.h b/src/jaguar2/RtlJaguar2Device.h index 552ce7f7..57bc3564 100644 --- a/src/jaguar2/RtlJaguar2Device.h +++ b/src/jaguar2/RtlJaguar2Device.h @@ -9,7 +9,7 @@ #include #include "logger.h" -#include "IRadio.h" +#include "IRtlRadio.h" #include "TxMode.h" #include "RtlAdapter.h" #include "SelectedChannel.h" @@ -38,7 +38,7 @@ * (Jaguar2PhyTables table data + RF-path count), HalmacJaguar2Fw (blob) and the * Jaguar2Calibration IQK factory — the same strategy-dispatch shape as the * Jaguar3 8822C/8822E HAL. */ -class RtlJaguar2Device : public IRadio { +class RtlJaguar2Device : public IRtlRadio { public: RtlJaguar2Device(RtlAdapter device, Logger_t logger, jaguar2::ChipVariant variant = jaguar2::ChipVariant::C8822B, diff --git a/src/jaguar3/RtlJaguar3Device.h b/src/jaguar3/RtlJaguar3Device.h index bcff1eaf..ced9c7d8 100644 --- a/src/jaguar3/RtlJaguar3Device.h +++ b/src/jaguar3/RtlJaguar3Device.h @@ -8,7 +8,7 @@ #include "logger.h" #include "CfoTracker.h" -#include "IRadio.h" +#include "IRtlRadio.h" #include "TxMode.h" #include "RtlAdapter.h" #include "SelectedChannel.h" @@ -29,7 +29,7 @@ * channel/bandwidth (incl. 5/10 MHz narrowband) and on-air TX. send_packet is * on-air; sustained continuous TX is kept alive by the coex runtime thread * (coex_runtime_loop) — see src/jaguar3/CLAUDE.md. */ -class RtlJaguar3Device : public IRadio { +class RtlJaguar3Device : public IRtlRadio { public: RtlJaguar3Device(RtlAdapter device, Logger_t logger, jaguar3::ChipVariant variant = jaguar3::ChipVariant::C8822C, diff --git a/src/kestrel/RtlKestrelDevice.h b/src/kestrel/RtlKestrelDevice.h index c2bcd15c..e15d7b90 100644 --- a/src/kestrel/RtlKestrelDevice.h +++ b/src/kestrel/RtlKestrelDevice.h @@ -11,7 +11,7 @@ #include "logger.h" #include "DeviceConfig.h" -#include "IRadio.h" +#include "IRtlRadio.h" #include "RtlAdapter.h" #include "RxQuality.h" /* RxQualityAccumulator + build_rx_quality */ #include "SelectedChannel.h" @@ -49,7 +49,7 @@ struct ChipInfo { * hand-ported C++ here + HalKestrel/KestrelFw; the halbb PHY and halrf * calibration planes are the vendor C compiled verbatim (hal/halbb, hal/halrf) * behind the kestrel glue. */ -class RtlKestrelDevice : public IRadio { +class RtlKestrelDevice : public IRtlRadio { public: RtlKestrelDevice(RtlAdapter device, Logger_t logger, kestrel::ChipVariant variant = kestrel::ChipVariant::C8852B, diff --git a/src/rtl8733b/Rtl8733bDevice.h b/src/rtl8733b/Rtl8733bDevice.h index ec3d3087..49c553c3 100644 --- a/src/rtl8733b/Rtl8733bDevice.h +++ b/src/rtl8733b/Rtl8733bDevice.h @@ -8,7 +8,7 @@ #include "DeviceConfig.h" #include "FrameParser8733b.h" #include "Halmac8733bMac.h" -#include "IRadio.h" +#include "IRtlRadio.h" #include "Phy8733b.h" #include "Rtl8733bBringup.h" #include "RtlAdapter.h" @@ -20,7 +20,7 @@ * path. Unsupported optional controls refuse loudly rather than silently * no-opping, but a refusal never tears the session down — asking for a knob * this backend has not ported is not a hardware-safety event. */ -class Rtl8733bDevice : public IRadio { +class Rtl8733bDevice : public IRtlRadio { public: Rtl8733bDevice(RtlAdapter device, Logger_t logger, devourer::DeviceConfig cfg = {}); diff --git a/tests/radio_iface_selftest.cpp b/tests/radio_iface_selftest.cpp new file mode 100644 index 00000000..99f48509 --- /dev/null +++ b/tests/radio_iface_selftest.cpp @@ -0,0 +1,55 @@ +/* Headless guard for the radio contract (src/IRadio.h, src/IRtlRadio.h). + * + * NullRadio implements only IRadio's pure-virtual core. That it compiles is the + * proof that the vendor-neutral contract needs no Realtek type; the runtime + * checks pin the not-ported defaults a non-Realtek backend inherits and the + * dynamic_cast convention callers use to reach the Realtek-only members. */ +#include "IRadio.h" +#include "IRtlRadio.h" + +#include +#include + +namespace { + +struct NullRadio final : IRadio { + SelectedChannel ch_{}; + void Init(Action_ParsedRadioPacket, SelectedChannel c) override { ch_ = c; } + void InitWrite(SelectedChannel c) override { ch_ = c; } + void StartRxLoop(Action_ParsedRadioPacket) override {} + void SetMonitorChannel(SelectedChannel c) override { ch_ = c; } + bool send_packet(const uint8_t *, size_t) override { return false; } + SelectedChannel GetSelectedChannel() override { return ch_; } + void SetCcaMode(bool) override {} +}; + +int fails = 0; +void check(bool ok, const char *what) { + if (!ok) { + std::fprintf(stderr, "radio_iface: FAIL %s\n", what); + fails++; + } +} + +} // namespace + +int main() { + std::unique_ptr r = std::make_unique(); + + check(dynamic_cast(r.get()) == nullptr, + "a neutral radio is not an IRtlRadio"); + check(!r->GetAdapterCaps().supported, "GetAdapterCaps default is unsupported"); + check(!r->GetRxQuality().valid, "GetRxQuality default is invalid"); + check(!r->GetFwBootStatus().supported, "GetFwBootStatus default is unsupported"); + check(!r->GetTxPowerCaps().supported, "GetTxPowerCaps default is unsupported"); + check(!r->SetAckResponder(devourer::MacAddr{}), "SetAckResponder default refuses"); + check(r->ReadTsf() == 0, "ReadTsf default is 0"); + + r->FastRetune(6); + check(r->GetSelectedChannel().Channel == 6, + "FastRetune default falls back to SetMonitorChannel"); + + if (fails) return 1; + std::puts("radio_iface: PASS"); + return 0; +} From 822c160c73dce50b700f3f640fb6e851209f53ae Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Wed, 9 Sep 2026 16:10:29 +0300 Subject: [PATCH 4/4] docs: point CLAUDE.md at IRtlRadio.h for the Realtek-only member list Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_015VtdB2ZryKELUwREjPBH3v --- CLAUDE.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 56da05a0..ddc3ab25 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -523,11 +523,10 @@ already-up chip, enabling TX+RX on one handle; `send_packet`) and constructs `RtlJaguarDevice` / `RtlJaguar2Device` / `RtlJaguar3Device` / `RtlKestrelDevice` / `Rtl8733bDevice` per backend. `Rtl8812aDevice` is a deprecated alias of `RtlJaguarDevice`. The five Realtek backends derive from `IRtlRadio` -(`src/IRtlRadio.h`), which adds the Realtek-only members (`GetRxEnergy`, -`SetXtalCap`/`GetXtalCap`, `ProbeEfuseStability`, `DumpChipState`); reach them -via `dynamic_cast` and treat `nullptr` as "not on this radio". -Optional device methods are **virtual with not-ported -defaults**, not pure virtual — a backend that hasn't ported a feature inherits +(`src/IRtlRadio.h`), the Realtek-only extension of `IRadio` — the header +carries the member list and the downcast contract. Optional device methods +are **virtual with not-ported defaults**, not pure virtual — a backend that +hasn't ported a feature inherits `false`/`0`/a full-path fallback rather than a fake. Check the override list in the backend's header before believing a cross-generation claim.