aethersdr / aethersdr/AetherSDR
HL2: the automatic RF gain arms by default and then refuses to arm — the constructed baseline is 1 dB above the ceiling that gates it
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 302
Description
Hl2Backend arms the automatic RF gain by default and then declines to arm it, because the constructed LNA baseline is one decibel above the ceiling that gates arming.
Measured on merged main 020d31fb, socket-free — no radio, no network, nothing keyed.
The failure
fresh backend: kLnaDefaultGainDb=20, ceiling=19
[FAIL] auto RF gain ARMS from a freshly constructed backend
(no stored per-band gain, i.e. a first connect)
Construct hl2::Hl2Backend, call setAutoRfGain(true), read back autoRfGainEnabled(). It is false.
Why
Three facts, each read from main rather than inferred:
value on 020d31fb |
|
|---|---|
m_lnaGainDb is seeded with hl2::kLnaDefaultGainDb (Hl2BandMemoryPolicy.h) |
20 |
Hl2Backend::kAutoRfGainMaxBaselineDb (Hl2Backend.h) |
19 |
Hl2Backend::setAutoRfGain refuses when the baseline exceeds that ceiling |
strict > |
20 exceeds 19, so the arming path takes its refusal branch, logs the qWarning and returns. #5652 arms the control by default, so on a first connect the shipped state is a control that reads as on and does not engage.
The refusal is logged, so it is not silent in a terminal. It is silent to an operator.
Who sees it
Anyone whose stored per-band gain for the current band is above 19 dB, which includes anyone with no stored gain at all — a fresh install, a new band, a cleared profile. An operator whose stored gains are all at or below 19 never sees it, which is why this did not surface on our bench: ours are −12 and below.
The code comment says the opposite
Hl2Backend.cpp, in the paragraph justifying the default flip:
"With the ceiling at +19 and the default at 0 dB, arming from a fresh connect works and starts from a baseline that means what it says."
The default is not 0 dB. It is 20 — on main now, and as @ten9876 stated on #5753, "the +20 dB default stands". That sentence is ours and it is wrong; we are reporting it rather than waiting to be asked about it.
Provenance, because it is the fourth of these today
kAutoRfGainMaxBaselineDb = 19 is sized on the & 0x1F gain fold, and its own refusal message cites it — "#5354: +48 dB measures like +18 dB".
#5752 merged declining that premise: the native range −12…+48 stands, and the merged decision records that the single-unit observation "remains unresolved against the native bit-6-selected RTL path".
The same premise produced three other errors that landed or nearly landed today: a docs/HERMES.md row claiming kLnaGainMaxDb is +19 when it is +48 (corrected by @ten9876 in #5753), a paragraph in #5652's body asserting the fold as settled (corrected on that PR), and this ceiling. We are not re-litigating the fold here — only noting that a constant derived from it now gates a default-on control.
Reproduction
A case added to tests/hl2_gain_split_test.cpp, which already constructs Hl2Backend directly and links aethercore:
hl2::Hl2Backend fresh;
fresh.setAutoRfGain(true);
check(fresh.autoRfGainEnabled(),
"auto RF gain ARMS from a freshly constructed backend");
Both constants are public, so the case prints them alongside the result and carries its own evidence. Happy to open it as a PR if a guard there is wanted.
We are not proposing the fix
Three candidates — raise kAutoRfGainMaxBaselineDb, lower kLnaDefaultGainDb, or lower the baseline on the connect path before arming — and each interacts with the unsettled fold question in a different way. Choosing one would be deciding that question by the back door, which is precisely what #5752 declined to do. That call is yours.
What this does not establish
- Whether a real connect always leaves the baseline at 20. The test constructs the backend directly. A connect that restores a stored gain of 19 or below arms normally; this measures the no-stored-gain path, which is the default one.
- Any on-air consequence. Nothing was keyed, no radio was involved, and the control failing to arm is a missing protection rather than an active fault.
- Whether the ceiling is the right number. Untouched here on purpose.
🤖 Generated with Claude Code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with Hl2Backend.h, Hl2Backend.cpp, and Hl2BandMemoryPolicy.h to verify the baseline, ceiling, and arming path described in the issue. Run the added case in tests/hl2_gain_split_test.cpp and review #5752, #5652, and #5753 for the unresolved gain-fold context. Done requires an agreed fix and a passing regression test for fresh-backend arming.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100