rtl8733b: add RTL8731BU/RTL8733BU USB RX and TX - #388
Conversation
|
/review |
Code Review by Qodo
1. CR upper byte not cleared
|
PR Summary by Qodortl8733b: add USB monitor RX and raw TX support
AI Description
Diagram
High-Level Assessment
Files changed (38)
|
|
Code review by qodo was updated up to the latest commit 0bfd8c3 |
josephnef
left a comment
There was a problem hiding this comment.
Review
Overall: high-quality backend — the code reads like the existing HALs, the RX parse is genuinely bounds-safe, caps are honest, and the extractors are the best hash-pinning in tools/. A handful of items below are worth resolving before merge; three of them cluster around one design decision (the hardcoded thermal-policy layer), plus the destructive SetCcaMode refusal.
Verified during review (not just read)
- Both ON and 8733B-only builds compiled here; ctest 53/53 and 49/49 pass, matching the PR claims.
git diff master...HEAD -- src/jaguar1 src/jaguar2 src/jaguar3 src/kestrelis empty — no existing HAL touched. TheRxParseAbort.hrefactor is behavior-preserving for the four existing generations (checked combination-by-combination).- Dispatch is conservative in exactly the right way: chip-id
0x16required, a known 8733B PID with a failed/wrong chip-id read is refused rather than falling through to Jaguar1, andDEVOURER_8733B=OFFreturns nullptr+log on both paths. - All 9 generated-array SHA-256 pins in the extractors were recomputed against the checked-in
hal/hal8733b_*.c— all match, and the tools do no network access. - The 12 KiB RX-aggregate cap is real, enforced at init and readback-verified via
MacState::matches_normal_usb3out(). - EFUSE packed-map decoding (extended-header block math, active-low word-enable, bounds on truncated headers) was hand-checked against vendor semantics; the TX golden descriptors were hand-decoded field-by-field.
- The
examples/rxrework fixes a real pre-existing bug (the qd/thermal emitter threads were never stopped/joined — astd::terminateon early-return paths).
Findings not tied to a single diff line
- 8733B PIDs missing from the demo discovery lists:
examples/doctorgained0xf72b/0xb733inkRealtekPids, but neitherexamples/rxnorexamples/txkRealtekProductIdsdid — a plugged 8733B is invisible to rxdemo/txdemo withoutDEVOURER_PID=0xf72b. Add to both or note why not. DEVOURER_TX_FRAMES(new txdemo demo-local var) is referenced nowhere — README/docs need a line.- The first-8 RX completion/frame breadcrumbs log at
info; convention puts per-frame diagnostics at debug/trace (bounded to 8, so cosmetic). rtl8733bprobe'sadd_executablesits mid-Kestrel section in CMakeLists.txt, far from the other example targets — works, but breaks the file's grouping.- Extractors use
read_text()/write_text()without explicitencoding=/newline=: on Windows--checkwon't be byte-identical (CRLF). Pre-existing pattern in older extractors, but these otherwise raise the bar — worth the two keywords. - Headless test gaps: STBC/VHT radiotap rejection lives only in
Rtl8733bDevice.cppand has no selftest; the RX walk's tail case (last frame's 8-byte-roundednext_offsetpastbuflen) is untested.
The hardware-validation narrative in the PR description and docs/rtl8733b.md is unusually honest (SGI decode failure, the dead second unit, the failed vendor-module cross-test all disclosed) — appreciated.
Review follow-ups on the RTL8733B backend (OpenIPC#388). Thermal readings become telemetry, matching every other generation: - rxdemo's cross-generation poller no longer stops RX at a hardcoded delta >= 25. Generalizing it onto IRtlDevice::GetThermalStatus was the point; the kill-switch rode along and applied that threshold to Jaguar1/2/3 and Kestrel too — sharpest on the 8822C, whose baseline is a first-read cold reference rather than an EFUSE constant. It emits and warns, nothing more. - InitWrite no longer refuses TX on a warm chip. It keeps a one-shot bring-up snapshot, the same shape as the Kestrel InitWrite snapshot. - send_packet reads no register at all. read_thermal() is 3 RF writes + a 15 us settle + an RF read, several USB control transfers per frame on a USB-HS part, and no other generation does register I/O on the send path. - enable_tssi_tracking's verdict is register readback only. It runs on every CCK<->OFDM rate-table transition — i.e. inside send_packet — and the meter tracks PA bias, not whether those BB writes landed. - rtl8733bprobe reports the "critical" bucket instead of aborting. The meter is a PA-bias tracking index, not a calibrated junction temperature, and docs/warm-tx-degradation.md shows it is not a validated degradation predictor. The remaining bound, kTssiAuditThermalCeiling, is named and confined to the audit_tssi_* probe stages. Other device-side fixes: - SetCcaMode(false) is the universal default and now succeeds as a no-op instead of card-disabling the chip and throwing. Only `true` refuses, and it no longer tears the session down; radio_operation_unavailable goes with it. - The RX URB floor is the device-side aggregate ceiling (kRxAggregateBytes8733b, 12 KiB) rather than 4096, so DEVOURER_RX_URB_BYTES cannot reintroduce the aggregate straddle from the host side. A static_assert keeps the constant and the programmed RXDMA_AGG page count in step. - A fatal TSSI rate-table failure latches its reason in _tx_fatal, so later rejections say the session was stopped rather than "TX rejected before InitWrite". send_packet keeps its bool contract. - parse_physical_efuse treats address-space exhaustion as success-with-whatever-parsed. A fully written map has no 0xff terminator left to find, and failing there bricked bring-up on a valid but heavily reprogrammed EFUSE. - _power_ready is armed before power_on(), so a mid-sequence failure still rolls back through power_off() instead of leaving the card half-enabled. - power_on() logs the computed verdict instead of asserting "card active" one line before the caller throws "card-enable sequence failed". - The first-8 RX completion/frame breadcrumbs move to the debug plane. - The modulation-admission contract moves into two pure predicates in TxDescriptor8733b.h, shared by the SetTxMode and radiotap branches, so the SGI/LDPC/STBC refusals are testable without hardware. - rxdemo and txdemo discover 0bda:f72b / 0bda:b733, so a plugged RTL8733B is visible without DEVOURER_PID. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both extractors read reference/rtl8733bu-20230626, but nothing pinned it, so `--check` was irreproducible from a fresh checkout and neither the generated firmware/tables nor the hand-transcribed halmac_reg2.h and power-sequence constants in src/rtl8733b/ could be re-verified by a reviewer. Add libc0607/rtl8733bu-20230626 at 9e5f684 (branch v5.13.0.1, shallow, matching the other reference pins), document it in reference/README.md, and make both extractors' missing-input errors name the pinned commit and the exact `git submodule update --init` line. The 2024 tree (2ec19e1) stays out of the submodule set and is recorded as a deviation: nothing in hal/ is generated from it, and the already hardware-validated artifacts were not replaced with untested ones. Verified against the pinned tree: both `--check` runs reproduce every checked-in artifact byte-for-byte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Soak script: - set -euo pipefail (was set -u), with the doctor exit captured explicitly and the negated parse_abort match rewritten as `! grep || failed=1` — as written it exited non-zero on the expected no-match case. mkdir/sha256sum failures no longer fall through. shellcheck clean. - Anchor the JSON value delimiter on the numeric gates: '"efuse_reads":4' also matched '"efuse_reads":40'. - Canonicalise VID/PID to lowercase 0xNNNN and lowercase the sysfs read, so a VID=0x0BDA no longer fails verification of a present, correct device. Extractors: explicit encoding="utf-8", newline="" on the generated-artifact read/write, so `--check` compares bytes identically on Windows instead of passing a CRLF round-trip while the checked-in file differs. Selftests, closing the gaps the review named: - The CCK-on-5GHz / CCK-at-40MHz chain end-to-end: tx_rate_id_8733b returns the 0xff sentinel *and* fill_tx_desc_8733b refuses it, plus an out-of-range rate_id. The two halves were only tested in isolation. - The modulation-admission contract (HT MCS0-7, 20/40 MHz, no SGI/LDPC/STBC; legacy 20 MHz only), which previously had no headless coverage at all — the descriptor encoder has no STBC field to reject on. - The RX walk's tail case: a last frame whose 8-byte-rounded next_offset lands past buflen must still parse, and must terminate the walk. - EFUSE address-space exhaustion is accepted with the full span reported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- README: split RTL8731BU and RTL8733BU into one row per chip, matching the
table's schema. The validated surface belongs to the tested unit — a bare
unbranded 1T1R module, 0bda:f72b cut D, an RTL8731BU. The RTL8733BU row says
what it is: recognized from the vendor ID table only, no physical unit, no
Bluetooth/coexistence.
- docs/rtl8733b.md: state present-tense facts instead of PR-relative changelog
("is now capped", "the claims in this PR", the OpenIPC#233 framing). Name the single
DUT the whole matrix rests on, and record that the unit that overheated and
stopped enumerating was the same chip — so the RTL8731BU row is a one-unit
result, not a population. Rewrite the thermal paragraph as telemetry, document
the SetCcaMode contract, and point the extraction commands at the submodule.
- CLAUDE.md: document DEVOURER_TX_FRAMES, and correct the thermal knob's entry —
it claimed a rising delta is "the early TX-degradation warning", which
docs/warm-tx-degradation.md contradicts and which is what the removed policy
layer was built on.
- CMakeLists: move rtl8733bprobe out of the middle of the Kestrel section to sit
with pcieprobe and kestrelprobe, its siblings.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The review's last named test gap. tx_mode_supported_8733b folds the PPDU family
into the shared admission predicate, so build_tx_block's SetTxMode branch no
longer carries its own `else { return 0; }` and the VHT/HE refusal is asserted
in tests/rtl8733b_tx_desc_selftest.cpp alongside the STBC/SGI/LDPC and
second-stream cases.
The two radiotap VHT/HE case labels in build_tx_block still have no headless
coverage — they sit inside the iterator switch and testing them would need a
device — but they now enforce the same contract this predicate states.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks — that was a genuinely useful review, and the thermal cluster was the right thing to lead with. Five commits pushed ( The thermal layer is gone, not made configurableYour three thermal findings shared one root cause, so rather than gate each one behind a knob I checked what the other backends actually do: thermal is pure telemetry everywhere —
The only threshold left is I also corrected For the record on where the layer came from: an adapter overheated and died early in this bring-up (almost certainly a faulty bench supply, not the chip), and the guards were added to protect the hardware while new features were being written. They were development scaffolding that should not have shipped in the library. Non-line findings
Two places I did not do what you suggested
VerificationHeadless only: full build 53/53, RTL8733B-only 49/49, RTL8733B-only ASan+UBSan 49/49. Both extractors' Nothing here has been re-tested on hardware. The changes with real on-air exposure are the removal of the |
Hardware re-validation of
|
| build | ms/frame | submission rate |
|---|---|---|
c374834 |
2.707 / 2.708 | 369 fps |
03502d3 |
0.200 / 0.196 | ~5060 fps |
Per-transition read — 500 frames, every frame a table switch:
| build | ms/transition |
|---|---|
c374834 |
91.96 / 92.19 |
03502d3 |
86.71 / 86.72 |
So the per-frame read was 2.51 ms of a 2.71 ms budget — @josephnef's "at injection rates this dominates the per-frame budget" was literally right, at 93% — and the per-transition read was a further 5.36 ms.
RX URB floor — clamps on hardware
DEVOURER_RX_URB_BYTES=4096, the exact window that previously let an aggregate straddle two URBs:
devourer [W] RTL8733B RX: raising urb_bytes 4096 -> 12288 (device RX aggregate cap)
devourer [I] RTL8733B RX: stopped completions=691 frames=1117 malformed=0 agg_mismatch=0
Post-stress health
Doctor after everything: HEALTHY, 4/4 identical EFUSE reads, 686 clean + 161 corrupt ambient frames on ch36, clean card-disable (CR=0xea, RF_CTRL=0x00).
Not claimed
- No witness adapter was plugged, so nothing above is an on-air result. The TX numbers are submission rate — bulk-OUT accepted by the chip,
failed=0— not airtime and not delivery. The independently-witnessed CCK/OFDM captures in the PR description still stand on the earlier runs; I have not re-witnessed them since these commits. - No SDR, so the occupied-bandwidth / mask / EVM gaps are unchanged.
- Still warm-only — the hub cannot switch VBUS.
One finding that is not about this PR
The residual ~84 ms per CCK↔OFDM table switch is the switch itself — disable tracking → rewrite the thermal table → re-enable, all USB control transfers — and it caps a mixed CCK/OFDM stream at ~11.5 fps on this backend. It predates this PR and I have not touched it here; happy to open a separate issue if that is worth pursuing.
Two diagnostic corrections found while profiling the CCK<->OFDM table switch on hardware. `prepare_tssi_thermal` logged `offsets[0]` and `offsets[15]` as "cold_edge" / "hot_edge". Those two words are `00000000` in *both* the CCK and the OFDM/HT plan — the tables differ only in words 4..11, the swing ramp either side of the baseline — so the line could never show whether a rate-table swap took effect. Every log from a churn run read `edge=00000000/00000000` regardless of rate. Report `swing_lo`/`swing_hi` (words 4 and 8) plus `fold`, an XOR over all 16 words that moves if any word changes. On the DUT the two tables are now distinguishable: `swing=00000000/00000000 fold=00000000` for OFDM/HT versus `swing=fdfd0000/05050505 fold=0300fdfb` for CCK. The `0x881a` entry added to the rx/tx demo discovery lists was commented as RTL8812EU only. That PID also ships on the Jaguar1 RTL8812AU-VS — observed here on hardware, reporting chip-id 0x04, 2T2R, `EFUSE_HIDDEN_8812AU_VS`. Harmless, because the factory dispatches on the SYS_CFG2 chip-id rather than the PID, but the comment said otherwise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Re-validated on the DUT with an RTL8812AU (0bda:8812) witnessing in monitor mode — the independent-capture gap the earlier post-review runs could not close, because no second adapter was plugged at the time. Per-rate delivery at 300 frames each: 1 Mbps CCK, 6 Mbps OFDM and HT MCS7 all 300/300 with zero FCS errors; 11 Mbps CCK >= 900/1000 over two repetitions. The mixed run alternating all eight rates put a CCK/OFDM table switch on every frame and the witness decoded all eight rate_hw values on air with valid FCS, 20 MHz, STBC and LDPC clear. Also records two things the profiling turned up, both pre-existing and neither introduced here: the 84 ms CCK<->OFDM table switch (OpenIPC#389), and the TSSI settling behaviour behind it — alternating at ~9 ms/frame leaves CCK about 5 dB above its settled level, while the same stream paced to ~86 ms/frame lands on it. That is the closed loop converging, and it is a trap for anyone reading power numbers off a fast rate-switching run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Witnessed on-air results — closing the gap from my last commentA working RTL8812AU turned up, so the "submission rate, not airtime" caveat on my previous comment no longer applies. Recorded in Witness: RTL8812AU
11 Mbps first landed exactly on a counter boundary, so I re-ran it at 1,000 frames; both repetitions landed in the same bucket. The small deficit relative to the other three is repeatable rather than noise, and expected — it is the least robust CCK rate. Mixed run: 250 frames alternating all eight rates, i.e. a CCK/OFDM TSSI table switch on every frame. The witness decoded all eight Two more commits since the review, both from things the profiling turned up:
Full matrix re-run on every commit: 53/53, RTL8733B-only 49/49, RTL8733B-only ASan+UBSan 49/49. Still not claimedNo SDR, so occupied bandwidth, spectral mask, EVM and absolute power remain unmeasured — the witness gives delivery and relative RSSI, not calibrated power. Narrowband TX, the Two questions from my earlier replies still open for youWhether the fatal TSSI path should throw rather than return |
josephnef
left a comment
There was a problem hiding this comment.
Follow-up review — all 13 comments addressed
Re-reviewed at c516d5d. Every item from the previous round is resolved, several beyond what I asked for. Verified independently rather than taken on faith:
- Fresh worktree at PR head +
git submodule update --init reference/rtl8733bu-20230626→ checked out exactly9e5f6845b4e3393207720fc1886668bc80b6af1c, then both extractors'--checkverified all 9 arrays byte-for-byte from that clone — which is precisely the property that was missing before. Full build clean (no new warnings), ctest 53/53,bash -nclean. git grep -n 'delta >= 25'now returns onlyPhy8733b.cpp'skTssiAuditThermalCeiling, correctly scoped to theaudit_tssi_*probe stages with the comment explaining why a probe verdict is not a runtime gate. The device send path,InitWrite, the rxdemo poller andrtl8733bprobeare all clear.
On the measurements you added
The per-frame thermal read at 2.51 ms of a 2.71 ms budget is a better result than I expected — and thank you for labelling it submission rate with no witness plugged rather than letting 13.7× read as an on-air number. That distinction is exactly the house style. Same for the negative control on the soak script (LISTEN_SECS=8 TIMEOUT_SECS=10 → rc=124 captured, gates ran, cleanup trap fired) — proving set -euo pipefail didn't convert a graded failure into a silent abort is the check that actually matters when adding -e to a script whose whole job is grading non-zero exits. And the note that the verdict line itself read HEALTHY there while the gate still failed on the exit code is the kind of detail that usually gets left out.
The [,}] anchoring turning out to be load-bearing ("init":1} at end-of-object) is a good catch on my behalf — I'd have suggested a comma and broken that gate.
Two things you volunteered that weren't asked for and are worth keeping: the TSSI settling observation (CCK airing ~5 dB above its settled level when alternating at ~9 ms/frame, converging at 86 ms/frame) paired with the favourable delivery table, and the 11 Mbps deficit reported as repeatable-across-two-runs rather than smoothed away. Both are the adversarial counterpart the docs convention asks for. Filing the 84 ms table-switch cost as #389 instead of burying it in this PR is the right call.
Fixes that went past the ask
kRxAggregateBytes8733bwith astatic_asserttying the URB floor to the programmedRXDMA_AGGpage count — I asked for a clamp; pinning the two constants to each other so they can't drift is better, and thewarnon raise means a user who setDEVOURER_RX_URB_BYTES=4096learns why it moved._power_readyarmed beforepower_on()with the reasoning spelled out (power_off()is the full card-disable flow and is safe against a partially-enabled card) — that's the correct inversion, not just a rollback bolt-on.tx_mode_supported_8733b/ht_request_supported_8733bfactored out so theSetTxModeand radiotap branches share one predicate. That converts "these two branches happen to agree today" into a structural property, and makes the STBC refusal testable on a descriptor encoder that has no STBC field to reject on._tx_fatallatching a static reason string so a retry loop can distinguish "InitWrite hasn't run" from "the session was deliberately stopped" — cleaner than the throw I floated.- The
881aPID collision comment (Jaguar3 8812EU vs Jaguar1 8812AU-VS, chip-id dispatch makes it harmless) is a genuinely useful drive-by that has nothing to do with this backend.
README
The split is exactly right, and separating RTL8731BU (1T1R, the validated row) from RTL8733BU (1T1R + BT, vendor-table-only, BT/coex not implemented) matches how RTL8812EU/RTL8822EU and RTL8852BU/RTL8832BU are handled. "bare unbranded 1T1R module" is an honest DUT description — it's the right answer when there's no brand to name. And docs/rtl8733b.md now stating that the second f72b unit would have covered the same README row, so the RTL8731BU row rests on one surviving sample — "a one-unit result, not a population" — is the sentence that makes the table readable a year from now.
One remaining nit (non-blocking, your call)
_cfg.tuning.disable_cca is silently dropped on this backend. Every other generation applies the knob during bring-up (if (_cfg.tuning.disable_cca) SetCcaMode(true); — jaguar1:82/1349, jaguar2:251, jaguar3:102/868, kestrel:257), so DEVOURER_DIS_CCA=1 is a no-op here while the direct setter throws. Given you deliberately made the setter refuse loudly rather than no-op, the config path is the one door left where the request vanishes without a word. Wiring it would surface as a hard throw at InitWrite — arguably correct but harsh for a knob CLAUDE.md describes as on-by-default for the streamtx FPV downlink; a one-line warn in bring-up when the knob is set would probably be the better trade. Either way it doesn't need to hold the PR.
LGTM. Nothing blocking from my side.
|
Deferred work from this PR is now tracked, all of it gated on the incoming BL-M8733BU2 board so nothing here blocks the merge:
#233 stays open as the umbrella; its USB-first scope is delivered here and the remainder is the list above. Merging. Thanks for the two review rounds — the follow-ups measured the things I could only assert, and the 93%-of-send-budget number turned a code-review opinion into a fact. |
josephnef
left a comment
There was a problem hiding this comment.
Approving. Round-two verification: fresh worktree at PR head, submodule init checked out exactly 9e5f684, both extractors' --check verified all 9 arrays byte-for-byte from that clone, full build clean, ctest 53/53. All 13 review comments resolved, several beyond the ask. Deferred RF work tracked in #390-#394.
|
Thanks for the re-review, and for re-verifying the submodule property from a fresh clone rather than trusting my word for it — that was the one claim that couldn't be checked before.
|
| requested | delivered | decoded as | FCS errors |
|---|---|---|---|
| 1 Mbps CCK | 298 / 300 | 1 Mbps | 0 |
| 2 Mbps CCK | 300 / 300 | 2 Mbps | 0 |
| 5.5 Mbps CCK | 300 / 300 | 5.5 Mbps | 0 |
| 11 Mbps CCK | 294 / 300 | 11 Mbps | 0 |
| 6 Mbps OFDM | 300 / 300 | 6 Mbps | 0 |
| HT MCS0 | 270 / 300 | MCS0 | 0 |
| HT MCS7 | 277 / 300 | MCS7 | 0 |
Single probes, so ~±3 points each. The HT column sitting under the legacy column is not a finding on this evidence — MCS0 reading below MCS7 is the giveaway, since MCS0 is the more robust rate. I've said so in the doc rather than presenting the ordering as a modulation effect.
Note this supersedes my earlier "11 Mbps deficit is repeatable" claim in the direction of less certainty: with exact counts, 11 Mbps at 294/300 sits inside the same band as 1 Mbps at 298/300, so I'd no longer call it a distinguishable deficit.
53/53, 49/49 RTL8733B-only, 49/49 ASan+UBSan on every commit.
Still not claimed
No SDR — occupied bandwidth, spectral mask, EVM and absolute power remain unmeasured; the witness gives delivery and relative RSSI only. Narrowband TX, the 0bda:b733 combo module and true VBUS-cold boots are unchanged.
|
Small precision note on the send-path claim in my last comment, since it is the kind of thing someone will re-check. Running that same grep against the merged Line 16 is a comment. Lines 82-84 are six reads guarded by So the accurate statement is: steady-state per-frame register I/O is zero, matching the other four generations, with six reads on the first frame of a session only. The grep counts text, not executions. I did not want the parity claim resting on a number that does not reproduce. |
|
Both of these landed after the merge, so replying here — and one of them collides with something I merged 20 minutes later. Heads-up:
|
Summary
Adds a dedicated userspace HALMAC 87xx backend for the RTL8731BU/RTL8733BU Wi-Fi function.
0bda:f72band0bda:b733, while requiring live RTL8733B chip ID0x16.rtl8733bprobe, adapter-doctor integration and capability documentation.rx.parse_aborttelemetry added in rx.parse_abort: count the abandoned-aggregate RX loss on every generation #387.This progresses the USB-first portion of #233. It does not auto-close that issue because narrowband RF validation and combo-module/coexistence work remain outside this PR.
Why a separate backend
RTL8733B is HALMAC 87xx, not a Jaguar2/3 variant. Its power, firmware, MAC, RX/TX descriptor and PHY paths therefore remain isolated under
src/rtl8733b/.Both reviewed vendor trees describe this device as 1SS 802.11b/g/n with a 20/40 MHz capability mask. The 2024 tree also contains a later
Fix VHT flagscommit that removes the accidentally enabled VHT flag. This PR consequently does not adopt #233's provisional VHT/80 MHz/2T2R assumptions.Firmware and tables are pinned to libc0607/rtl8733bu-20230626 commit
9e5f6845b4e3393207720fc1886668bc80b6af1c. The implementation was compared with libc0607/rtl8733bu-20240806 commit2ec19e154cffbc2abd98d43d59278dffa6e50d49, including its active-path TSSI, SRRC band-edge, GPIO/coexistence, power-saving and C2H/TX-tasklet changes. The already hardware-validated artifacts were not silently replaced.Hardware tested
Test device: one
0bda:f72b, RTL8733B cut D, USB high speed. Independent witness: RTL8812AU in monitor mode.Verified through the normal
WiFiDriver/IRtlDevicepath:RF_CTRL=0x00,CR=0xea.Checks
bash -n, ShellCheck and failure-cleanup exercise fortests/rtl8733b_lifecycle_soak.sh: passed.--check: reproduced both checked-in NIC images byte-for-byte.--check: reproduced all checked-in MAC/BB/AGC/RF/RFK arrays byte-for-byte.OpenIPC/devourer:master(da06ccc) for the final local builds and hardware checks.Explicitly not tested or claimed
narrowband_okremains false.0bda:b733combo module was available. Its ID is from the vendor table; Bluetooth/coexistence is not implemented or claimed.MODULE_IMPORT_NSsyntax and missingplatform_ops.h. No vendor module was loaded, so no vendor-driver parity result is claimed.f72bpassed early identity/EFUSE/firmware checks, but later stopped enumerating and overheated while attached to a custom power supply. It is excluded from all radio-validation claims.The full tested/deferred matrix and provenance are in
docs/rtl8733b.md.