Files
OpenIPC_RTL8812AU_Forword_cpp/3rd/devourer/src/IRtlRadio.h
T
2026-09-13 13:30:21 +08:00

91 lines
4.7 KiB
C++

#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 */