From 4b1bf14140fc36fbf4c18f8e6f19933d4c24bcdd Mon Sep 17 00:00:00 2001 From: MCKero Date: Fri, 28 Aug 2026 17:21:33 +0100 Subject: [PATCH] Settle the squelch interrupt: the blocker is not in the device model Second attempt, and this one produced a definite answer rather than another guess. Two real mistakes in the first version, both fixed along the way and worth recording: squelch was evaluated when the firmware configured the chip, but the startup sequence writes REG_3F as 0x0000 then 0x0C0C three times over, so a flag raised on the enabling write was disabled again before anyone read it. And the threshold came from REG_4E, whose low bits are the glitch threshold -- the RSSI open level is REG_78 bits 15:8 at 0.5 dB/step against REG_67's 0.25 dB/step, so squelch could never open at all. With both corrected, every chip-side condition lines up: en=0x0C0C, rssi=0x01E0, threshold 94, REG_0C correctly returning 1. The firmware still never acknowledged, and the reason is outside the chip: gCurrentFunction=5 (FUNCTION_POWER_SAVE), gRxIdleMode=1 against the gate at app/app.c:1697, if (gCurrentFunction != FUNCTION_POWER_SAVE || !gRxIdleMode) CheckRadioInterrupts(); Both halves false, so the interrupt loop is never entered and nothing can collect the flag. The emulator idles in power save, so that is the steady state. Gating on REG_30 -- zeroed by BK4819_Sleep on each power-save cycle -- does not help: the chip is awake when the model is asked while the firmware still has gRxIdleMode=1. Chip state and firmware state are not in step, so no condition available inside a register model can decide this correctly. So it is not a matter of a better trigger. A working version needs to keep the guest out of power save, or drive the interrupt from something that knows the firmware's receive state -- neither of which belongs in this device. Both attempts reverted; the model is back at the committed state and test_bk4819.py passes, including the REG_0C assertion that catches the armed-hang failure mode. --- AGENTS.md | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a39e0c3..1aeab85 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -477,10 +477,40 @@ the firmware had not collected the interrupt. That is a latent hang, because them with the bit stuck never returns. Shipping a model that leaves a hang armed is worse than shipping one without an S-meter. -Anyone retrying should first work out *why* the flag was not collected — a gate -upstream of the interrupt loop, or ordering against the receive state machine — rather -than raising it at a different moment and hoping. The signal that it is right is -`REG_0C` reading 0 afterwards, which `tools/test_bk4819.py` already asserts. +**Second attempt, and the actual reason.** Tried again, this time evaluating squelch +when the firmware *polls* `REG_0C` rather than when it configures the chip — which +fixed the original mistake, since the startup sequence writes `REG_3F` as `0x0000` +then `0x0C0C` three times over, so a flag raised on the enabling write was disabled +again before anyone read it. Also corrected the threshold field: the RSSI open level +is `REG_78` bits 15:8 at 0.5 dB/step against `REG_67`'s 0.25 dB/step, not anything in +`REG_4E` (those low bits are the *glitch* threshold, and using them meant squelch +never opened at all). + +With that right, everything on the chip side lines up — measured `en=0x0C0C`, +`rssi=0x01E0`, threshold 94, and `REG_0C` correctly returning 1. The firmware still +never acknowledged. The reason is not on the chip side at all: + + gCurrentFunction=5 (FUNCTION_POWER_SAVE), gRxIdleMode=1 + +and the gate is `app/app.c:1697`: + + if (gCurrentFunction != FUNCTION_POWER_SAVE || !gRxIdleMode) + CheckRadioInterrupts(); + +Both halves are false in that state, so `CheckRadioInterrupts` is never called and +nothing can collect the flag. The emulator idles in power save, which is why this is +the steady state rather than a transient. + +Gating on `REG_30` (which `BK4819_Sleep` zeroes on each power-save cycle) did not help +either: the chip is awake at the moment the model is asked, while the firmware still +has `gRxIdleMode=1`. Chip state and firmware state are not in step, so no condition +available *inside* the device model can decide this correctly. + +So this is not a matter of finding a better trigger. A working version has to either +keep the guest out of power save, or drive the interrupt from something that knows the +firmware's receive state — neither of which belongs in a register model. Both attempts +are reverted; the check that would confirm a third is `REG_0C` reading 0 afterwards, +which `tools/test_bk4819.py` asserts. **Where it stops.** This models the register interface, not the radio. It reproduces what the firmware *commanded* — frequency, power step, carrier keying in time — never