Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/scheduled-mac.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ witness capture of a 9-copy truth. Kestrel has no CCX `tx.report` path, so
the witness copy-count is the retry ground truth there — the fw-level
delivery outcome stays invisible until a receipts-tier consumer counts it.

The ACK window itself is a knob — `DEVOURER_ACK_TIMEOUT_US`, the
hardware-ARQ *range* lever (round-trip propagation eats ~6.7 µs/km; the
per-chip defaults and the bench proof live at the field doc in
`src/DeviceConfig.h`).

Choosing the limit (`tests/arq_retry_sweep.sh`, collision regime: a ~1 k fps
retrying unicast flood into an 8812EU duplex ground station airing
PixelPilot-shaped feedback bursts, near-field): retries are backoff-spaced,
Expand Down
4 changes: 4 additions & 0 deletions examples/common/env_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ devourer::DeviceConfig devourer_config_from_env() {
std::fflush(stderr);
}
}
if (env_long("DEVOURER_ACK_TIMEOUT_US", &v) && v >= 1)
/* 1..255; out-of-range low keeps the library default (a 0 collapsing
* to 1 us would write off every frame). */
cfg.tx.ack_timeout_us = static_cast<int>(v > 255 ? 255 : v);
if (env_long("DEVOURER_TX_RETRY_LIMIT", &v))
cfg.tx.retry_limit = static_cast<int>(v < 0 ? 0 : (v > 63 ? 63 : v));
if (const char *e = env_str("DEVOURER_TX_RETRY_FALLBACK")) {
Expand Down
39 changes: 31 additions & 8 deletions src/DeviceConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,38 @@ struct DeviceConfig {
* Runtime equivalent: StartCwTone/StopCwTone on the concrete device. */
bool cw_tone = false;
uint8_t cw_tone_gain = 0;
/* env: DEVOURER_TX_RETRY_LIMIT — per-frame hardware retry limit (0..63).
* Maps to the TX descriptor DATA_RETRY_LIMIT / RTS_DATA_RTY_LMT field
* (Dword4 bits 18-23). 0 = no retries (WFB default: FEC provides
* reliability, not MAC retries). On a busy half-duplex link retries flood
* the air and blind the receiver. Hardware-ARQ (SetAckResponder + unicast
* TA, docs/scheduled-mac.md) needs a nonzero value. Inert on Kestrel
* (firmware-level retry) and on the 8814A die (vendor DATA_RETRY_LIMIT=0
* carve-out kept). */
/* env: DEVOURER_TX_RETRY_LIMIT — per-frame hardware retry limit (0..63;
* Kestrel ceiling 62 — its attempts-counting WD field folds +1). Maps to
* the TX descriptor DATA_RETRY_LIMIT / RTS_DATA_RTY_LMT field on the
* 11ac generations and wd_info DATA_TXCNT_LMT on Kestrel. 0 = no retries
* (WFB default: FEC provides reliability, not MAC retries). On a busy
* half-duplex link retries flood the air and blind the receiver.
* Hardware-ARQ (SetAckResponder + unicast TA, docs/scheduled-mac.md)
* needs a nonzero value. Inert on the 8814A die only (vendor
* DATA_RETRY_LIMIT=0 carve-out kept pending its bench). */
int retry_limit = 0;
/* env: DEVOURER_ACK_TIMEOUT_US — hardware ACK response window in µs
* (1..255, clamped), the hardware-ARQ RANGE lever: the MAC writes a
* frame off (and retries) when no ACK is counted within this window,
* and round-trip propagation eats ~6.7 µs per km. ONE default, 128 µs,
* programmed identically on every generation at bring-up — the same
* knob value means the same range budget (~15 km round trip) no matter
* which die is plugged. 128 is the vendor's interop-blessed J1/J2
* value and covers the slowest narrowband ACK in the tree (the 5 MHz
* per-bandwidth vendor value is 117 µs), so it also replaces the
* per-chip / per-bandwidth vendor defaults (which ranged 33..128 µs
* and made hardware-ARQ range silently die-dependent). The register:
* REG_ACKTO 0x640 on the 11ac generations, R_AX_RSP_CHK_SIG 0xCC00
* byte0 on Kestrel; the CTS window (REG_CTS2TO 0x641) is separate and
* untouched. Sizing: ~6.7 µs x round-trip km + ~50 µs ACK flight and
* detection margin; a longer window is NOT free — every retry of a
* LOST frame waits the full window, measured (dead RA, retry 8, max
* duty): 2719 write-offs/8 s at 33 µs vs 2015 at 128 vs 1507 at 255.
* Bench proof the register gates the ARQ verdict: at 8 µs (below the
* ACK's flight time) retries pin at the limit with 0% ok against a
* live responder; at 128/255 the responder cell runs 100% ok,
* retries ~0. */
int ack_timeout_us = 128;
/* env: DEVOURER_TX_RETRY_FALLBACK — "off" | unset. Unset = the firmware
* fallback ladder with its own floor (the current behaviour, descriptors
* byte-identical). "off" disables per-retry rate fallback (DISDATAFB /
Expand Down
12 changes: 12 additions & 0 deletions src/jaguar1/RtlJaguarDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ void RtlJaguarDevice::InitWrite(SelectedChannel channel) {
* DEVOURER_DIS_CCA. Always applied — the enable path is what programs
* the BB EDCCA thresholds off their parked never-trigger table value. */
SetCcaMode(_cfg.tuning.disable_cca);
/* ACK window (DEVOURER_ACK_TIMEOUT_US): one library default on every
* generation — see the DeviceConfig field doc. */
_device.rtw_write8(0x0640, static_cast<uint8_t>(
_cfg.tx.ack_timeout_us > 255 ? 255
: _cfg.tx.ack_timeout_us < 1 ? 1
: _cfg.tx.ack_timeout_us));

/* DEVOURER_XTAL_CAP — crystal-cap trim (issue #217, narrowband CFO lever). */
if (_cfg.tuning.xtal_cap)
Expand Down Expand Up @@ -1333,6 +1339,12 @@ void RtlJaguarDevice::Init(Action_ParsedRadioPacket packetProcessor,
* DEVOURER_DIS_CCA. Always applied — the enable path is what programs
* the BB EDCCA thresholds off their parked never-trigger table value. */
SetCcaMode(_cfg.tuning.disable_cca);
/* ACK window (DEVOURER_ACK_TIMEOUT_US): one library default on every
* generation — see the DeviceConfig field doc. */
_device.rtw_write8(0x0640, static_cast<uint8_t>(
_cfg.tx.ack_timeout_us > 255 ? 255
: _cfg.tx.ack_timeout_us < 1 ? 1
: _cfg.tx.ack_timeout_us));

/* DEVOURER_XTAL_CAP — crystal-cap trim (issue #217, narrowband CFO lever). */
if (_cfg.tuning.xtal_cap)
Expand Down
7 changes: 7 additions & 0 deletions src/jaguar2/RtlJaguar2Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ void RtlJaguar2Device::bring_up(SelectedChannel channel) {
if (_cfg.tuning.disable_cca)
SetCcaMode(true);

/* ACK window (DEVOURER_ACK_TIMEOUT_US): one library default on every
* generation — see the DeviceConfig field doc. */
_device.rtw_write8(0x0640, static_cast<uint8_t>(
_cfg.tx.ack_timeout_us > 255 ? 255
: _cfg.tx.ack_timeout_us < 1 ? 1
: _cfg.tx.ack_timeout_us));

/* DEVOURER_XTAL_CAP — apply the crystal-cap trim once the AFE is up
* (issue #217, the narrowband CFO lever). */
if (_cfg.tuning.xtal_cap)
Expand Down
8 changes: 8 additions & 0 deletions src/jaguar3/RtlJaguar3Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,14 @@ void RtlJaguar3Device::InitWrite(SelectedChannel channel) {
else
_txpkt_img.store(0, std::memory_order_relaxed);
apply_dpdt_route_8822e(); /* 8822E DPDT/eFEM pin-mux (post-coex) */
/* ACK window (DEVOURER_ACK_TIMEOUT_US): one library default on every
* generation, replacing the halmac per-bandwidth REG_ACKTO defaults
* init_wmac_cfg just wrote (the 128 default covers the slowest
* narrowband ACK) — see the DeviceConfig field doc. */
_device.rtw_write8(0x0640, static_cast<uint8_t>(
_cfg.tx.ack_timeout_us > 255 ? 255
: _cfg.tx.ack_timeout_us < 1 ? 1
: _cfg.tx.ack_timeout_us));
apply_replay_wseq(); /* DEVOURER_REPLAY_WSEQ golden-init replay (debug) */
if (_cfg.debug.bb_dump) {
/* Full MAC+BB dump (0x000..0x4ffc — MAC plane, then BB incl. the RF
Expand Down
7 changes: 7 additions & 0 deletions src/kestrel/RtlKestrelDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@ void RtlKestrelDevice::InitWrite(SelectedChannel channel) {
* re-asserts explicitly (idempotent) when the knob is set. */
if (_cfg.tuning.disable_cca)
SetCcaMode(true);
/* ACK window (DEVOURER_ACK_TIMEOUT_US): one library default on every
* generation — byte0 of R_AX_RSP_CHK_SIG (the field the vendor's
* narrowband path scales); see the DeviceConfig field doc. */
_device.rtw_write8(0xCC00, static_cast<uint8_t>(
_cfg.tx.ack_timeout_us > 255 ? 255
: _cfg.tx.ack_timeout_us < 1 ? 1
: _cfg.tx.ack_timeout_us));
_tx_mgmt_ep = _device.nth_bulk_out_ep(0); /* B0MG -> BULKOUTID0 */
_tx_data_ep = _device.nth_bulk_out_ep(3); /* ACH0 -> BULKOUTID3 */
if (_tx_mgmt_ep == 0) {
Expand Down
Loading