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
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.