Skip to content

Kestrel 8852C: noise-floor gaps — NHM reads ~25 dB high + physts SNR unparsed #306

Description

@josephnef

Follow-up to #305, which shipped the Kestrel noise-floor sensing. On the C8852B (RTL8852BU) everything works and cross-validates; on the C8852C (RTL8852CU/8832CU) both floors are deliberately gated to emit null (never a wrong value) pending two 8852C-specific fixes.

On-air comparison, same idle channel (ch149, 0 frames, DEVOURER_RX_NOISE_FLOOR=1 DEVOURER_RXQUALITY=1):

8852BU (C8852B) 8832CU (C8852C)
active NHM floor −93 dBm (correct) −68 dBm (~25 dB high)
passive rssi−snr floor −94 dBm (HEALTHY) null (SNR unparsed)

Gap 1 — active NHM floor reads ~25 dB high on the 8852C

The halbb NHM env-monitor triggers and returns on the 8852C (setting bb->cr_type = BB_CLIENT in kestrel_halbb_create populates the CR bank so nhm_rdy is valid — the same fix that made the 8852B work), but the reported nhm_pwr is ~25 dB too high: idle ch149 reads −68 dBm vs the 8852B's −93. The nhm_pwr − 110 conversion is chip-agnostic, so the raw nhm_pwr itself differs — likely an 8852C-specific NHM reference / nhm_method_sel / threshold difference in the halbb BB_CLIENT env-monitor path (or an 8852C power-report offset the vendor applies elsewhere).

  • Where it's gated: RtlKestrelDevice::GetRxEnergy() only trusts nhm_noise_floor when _variant == C8852B.
  • Done looks like: the 8852C NHM floor reads a correct idle floor (~−90…−95 on a quiet channel, cross-matching the passive floor once Gap 2 lands), then drop the C8852B-only gate.

Gap 2 — physts SNR unparsed on the 8852C (passive floor null)

The passive rssi − snr floor needs per-frame SNR. devourer hand-parses it from the PPDU-status physts report: after the 8-byte physts_hdr_info, IE_01 (physts_ie_1_info) carries avg_snr at IE byte 8 [5:0]; the parse self-validates on ie_hdr == 1 at payload offset 8 (RtlKestrelDevice.cpp, the RPKT_TYPE_PPDU handler). On the 8852C the physts payload layout differs (the C uses a 16-byte drv_info unit vs the B's 8), so IE_01 is not at offset 8 → the ie_hdr == 1 guard fails → snr stays 0 → the passive floor never populates and LinkHealth misclassifies (SATURATED at a weak RSSI). Per-frame RSSI parses fine on the 8852C.

  • Done looks like: locate IE_01 for the 8852C physts layout (or route the buffer through the vendored halbb_physts_parsing and read bb->bb_physts_i) so snr populates → the passive floor + LinkHealth work on the C.

Both paths currently emit null on the 8852C (no fake data), so this is a "make it work on the C" task, not a correctness regression. Context: docs/rx-spectrum-sensing.md (the per-generation noise-floor list).

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions