Jaguar1/2/3: unified TX retry-limit knob (DEVOURER_TX_RETRY_LIMIT, default 0) - #354
Conversation
PR Summary by QodoUnify Jaguar1/2/3 TX retry limit via DEVOURER_TX_RETRY_LIMIT (default 0)
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo
1. Retry env ignored
|
f8a57e5 to
311adfb
Compare
josephnef
left a comment
There was a problem hiding this comment.
Mechanism verified on hardware — works exactly as described on all three generations. But the default-0 flip silently breaks the shipped hardware-ARQ feature and its test matrix, so this needs the test/docs consequences carried in the same PR (or default 12).
On-air A/B (off-phase: unanswered unicast QoS + DEVOURER_TX_REPORT, ch36, no responder)
| Cell | master (a71060f) | PR default | PR + DEVOURER_TX_RETRY_LIMIT=12 |
|---|---|---|---|
| j2-8812BU (2357:012d) | retries_mean 12.00 / max 12 (500 rpts) | 0.00 / 0 | 12.00 / 12 |
| j3-8822CU (0bda:c812) | 12.00 / 12 (1282 rpts) | 0.00 / 0 | 12.00 / 12 |
| j1-8821AU (2357:0120) | 12 | 0 | 12 |
So: the knob works, the override lands in the descriptor on every generation, and =12 restores master behavior bit-for-bit. Headless ctest: 48/48 pass on the PR build.
Code mechanics are sound: the jaguar2/3 post-builder override + re-checksum is idempotent (cal_txdesc_chksum_* zeroes the field before XOR) and matches the existing tx.report / A-MPDU mutation-block pattern; the env layer clamps 0..63 and the 6-bit descriptor macros mask direct-API overflow.
Blocking: default 0 regresses hardware ARQ + fails the ACK test matrix
With retry_limit = 0 by default:
- The hardware-ACK closed loop (
SetAckResponder+ unicast TA — autonomous MAC retransmission until ACK,docs/scheduled-mac.md) silently loses retransmission. That's a shipped, bench-validated capability, not an accident of the hardcoded 12. tests/ack_txreport_matrix.shnow fails:ack_txreport_analyze.pyhard-asserts off-phaseretries_max >= 8and pinned== 12— the table above shows those go to 0.
Default 0 is defensible for the FPV/WFB use case (same spirit as DEVOURER_DIS_CCA defaulting on for streamtx — the link owns its reliability via FEC). But then the PR should also:
- Update
tests/ack_txreport_matrix.shto passDEVOURER_TX_RETRY_LIMIT=12into the TX env (and letack_txreport_analyze.pytake the expected pin as a parameter rather than a literal 12). - Fix the
docs/scheduled-mac.mdwording ("retries pinned at the descriptor limit") to name the knob. - Extend the
DeviceConfig.hdoc comment: hardware-ARQ (SetAckResponder) needs a nonzero value; and the knob is inert on Kestrel (firmware-level retry) and on the 8814A die (the vendor's DATA_RETRY_LIMIT=0 carve-out is kept) — so "uniform across jaguar1/2/3" needs that asterisk.
Alternative that avoids all three: keep the default at 12 and let WFB deployments set DEVOURER_TX_RETRY_LIMIT=0 explicitly. Either resolution is fine; shipping the default flip without the test/docs updates is not.
Note: overlap with #334
#334 reaches the same end state (retry 0) via the radiotap NOACK flag, jaguar3-only, with no opt-out (every devourer demo sets NOACK unconditionally) and an extra EN_HWSEQ flip. This PR's explicit knob is the cleaner mechanism and effectively supersedes #334's retry half — the two conflict on the same descriptor lines and should be reconciled, not both merged.
🤖 Generated with Claude Code
All three Jaguar generations hardcoded a per-frame TX retry limit of 12 (jaguar1: SET_TX_DESC_DATA_RETRY_LIMIT, jaguar2/3: RTS_DATA_RTY_LMT in the fill_data_tx_desc builders). On a busy half-duplex link the chip retried each frame up to 12x on collision, flooding the air and blinding the receiver — consecutive video fragments lost, downlink FEC cannot repair. Now every chip honors cfg.tx.retry_limit (env DEVOURER_TX_RETRY_LIMIT), applied per frame with tx_desc re-checksum; the A-MPDU path uses it too. Default 0 restores the pre-regression behaviour (verified: 0 losses with alink enabled on 8812AU). Review follow-up: the ACK/ARQ capability matrix keeps testing the hardware-ARQ loop by pinning the descriptor limit via DEVOURER_TX_RETRY_LIMIT=12 (ack_txreport_analyze.py takes the expected pin as --expect-retries); docs name the knob and note it is inert on Kestrel and the 8814A die, and that SetAckResponder ARQ needs a nonzero value.
311adfb to
7abd756
Compare
|
Thanks for the on-air A/B and the clear resolution. Default stays 0 (WFB semantics — FEC owns reliability); the three follow-ups are in the branch:
|
josephnef
left a comment
There was a problem hiding this comment.
All three follow-ups verified on the new head (7abd756) — approving.
- Descriptor/env code is byte-identical to the head I hardware-validated (the delta is docs + tests + the
DeviceConfig.hcomment only), so the on-air A/B table stands: master 12.00 → PR-default 0.00 →=1212.00 on j1/j2/j3. - Updated matrix passes end-to-end on hardware (j3-8822CU cell, 8814AU responder, ch36, PR build): on
ack_rate=1.0 retries_mean=0.21, retarget1.0 / 0.2, offack_rate=0.0 retries_mean=12.00 retries_max=12— allcapability_ok=true. The hardware-ARQ contract is preserved with the knob as the single source of truth. ack_txreport_analyze.py --selftestpasses incl. the new custom-pin cases; headlessctest48/48.- Qodo's "env ignored" finding is stale — it reviewed an intermediate commit; the current head wires
DEVOURER_TX_RETRY_LIMITinenv_config.cppwith the 0..63 clamp.
Two non-blocking nits, take or leave:
RETRY_LIMIT=0makes the off-phase assertionretries_max >= 0— trivially true, so a zero-pin run can't detect a dead report path via retries. Operator-chosen, so fine, but a one-line guard (refuseRETRY_LIMIT=0or warn) would keep the phase meaningful.- Docs wording: "the value the descriptors used to hardcode" / "is now the single source of truth" is historical phrasing — this repo's docs convention is current-state-only (git is the changelog). "the matrix runs 12" alone carries it.
🤖 Generated with Claude Code
…ry_limit_ok) from the measured matrix (#365) (#372) Steps 1–2 of #365 (the 8821AU responder root-cause and the Kestrel retry H2C port remain open on the issue). ## What ships Two bench-derived capability flags, following the `ldpc_rx_*` convention (truth table doc-commented at the declaration, never a vendor advertisement): - **`ack_responder_ok`** — SetAckResponder measurably closes a hardware-ARQ loop as the responder. From the six-cell on-air matrix (issue comment): true on 8812A/8814A/8822B/8822C/8822E (98%/98%/98%/69%/79% single-shot ACK closure vs 0% with the responder off), **false on the 8821A die** (0% closure, third independent confirmation) and **false on Kestrel** (SetAckResponder not implemented on the AX generation — measured, not assumed). - **`tx_retry_limit_ok`** — `DEVOURER_TX_RETRY_LIMIT` drives hardware autonomous retransmission (the 12/0/12 A/B from #354's review). **False on the 8814A die** (vendor DATA_RETRY_LIMIT=0 carve-out kept, knob inert) and **Kestrel** (fw-level retry). Both ride the `adapter.caps` event so integrators (PixelPilot et al.) can gate ARQ features per adapter instead of discovering a dead responder in the field. ## Validation On-air, all six plugged dies report exactly the measured matrix: | die | ack_responder | tx_retry_limit | |---|---|---| | RTL8822E | 1 | 1 | | RTL8822C | 1 | 1 | | RTL8822B | 1 | 1 | | RTL8814A | 1 | 0 | | RTL8821A | **0** | 1 | | RTL8852C | **0** | **0** | `ctest` 49/49. One bring-up correction en route: the 8821A die's J1 enum is `CHIP_8821`, not `CHIP_8821A` (caught by the compiler, then re-validated per-die on air). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Problem
All three Jaguar generations hardcode a per-frame TX retry limit of 12:
src/jaguar1/RtlJaguarDevice.cpp):SET_TX_DESC_DATA_RETRY_LIMIT_8812(..., 12)(plain + A-MPDU paths)src/jaguar2/RtlJaguar2Device.cpp,src/jaguar3/RtlJaguar3Device.cpp): thefill_data_tx_desc_*builders hardcodeRTS_DATA_RTY_LMT = 12, then nothing overrides itWith
RETRY_LIMIT_ENABLE=1, on a busy half-duplex link (bidirectional monitor-mode FPV) the chip retries every frame up to 12× on collision with the continuous downlink. TX airtime explodes, the receiver's half-duplex blind windows drop consecutive video fragments — the one loss pattern the downlink FEC cannot repair (k=11/n=15, max 4). Observed as ~20-30 non-recoverable losses/s when enabling the uplink (adaptive link) on the ground station; with retry=0 losses drop to zero.Change
cfg.tx.retry_limit(DEVOURER_TX_RETRY_LIMIT, default 0) toDeviceConfig::Txcfg.tx.retry_limitinto the TX descriptor instead of 12 (plain + A-MPDU paths)RTS_DATA_RTY_LMTafter the builder withcfg.tx.retry_limitand re-run the txdesc checksum (the field lives inside the checksummed span)Default 0 = no MAC retries, matching WFB semantics (reliability comes from FEC, not MAC retries). Verified on-air: 8812AU ground station, alink enabled, 0 lost packets; drone side rebuilt with the same knob.
Notes
DEVOURER_TX_RETRY_LIMITnow works uniformly across jaguar1/2/3 on both link ends.