Skip to content

The chip reports what it has been configured to be - #5

Merged
A13xB0 merged 1 commit into
mainfrom
radio-state-across-the-bridge
Aug 14, 2026
Merged

A13xB0 merged 1 commit into
mainfrom
radio-state-across-the-bridge

Conversation

@A13xB0

@A13xB0 A13xB0 commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

kRadioStats carried four counters. It now carries the radio: receive gain
register, transmit power, front-end line, mode, SF, CR, frequency, bandwidth,
preamble, IRQ mask and flags.

A board profile is a datasheet claim about hardware, not a claim about the
firmware running on it. Until the chip reported its own state there was no way
to tell a node whose firmware configured it correctly from one whose firmware
did not — which is exactly the pair of faults MeshCore 1.17.1 fixed: receive
gain reverting after an AGC reset, and a transmit-enable line that never went
high.

Wire format

Read on length, so a peer that stops at 16 bytes still parses and an older
node still runs.

Offset Field
0–15 irqReads, busyReads, busyMs, spuriousRaises (unchanged)
16 RX gain register 0x08AC
17 transmit power, int8, −128 = never set
18 FEM line live level
19 mode: 0 standby, 1 rx, 2 tx, 3 cad
20–21 SF, CR
22–25 frequency Hz
26–29 bandwidth Hz
30–31 preamble symbols
32–33 IRQ mask
34–35 IRQ flags
36 FEM at transmit: 0 never transmitted, 1 module out, 2 module in

Transmit power is int8 with −128 meaning never set, because 0 is a level
a radio can legitimately be set to and cannot also mean "unset".

Three decisions worth reviewing

The front-end line is latched at transmit, not read live. RadioLib holds it
low while receiving and raises it just before SetTx, so the current level says
only whether the node happens to be listening. Reading it live docked an idle
E22 25 dB for the ordinary state of waiting — caught by running it, not by a
test. Hence three states: a node that has not transmitted has not answered the
question.

bridge/main.cpp writes the same payload in the same order. Two writers of
one wire format is the arrangement RadioServerSX1262 exists to avoid, and is
only tolerable while they stay identical — an emulated node and a native one
reporting different shapes would make every comparison between them a comparison
of our own code. Worth a second opinion on whether to share the encoder instead.

main.cpp reports the front end as "not answered", never "module out." A
native node has no such pin wired; SimHal owns an array of pins and nothing
drives an enable line into it. Reporting the line low would be true of the pin
and false about the board, and would dock every native node on a board that has
a module for a fault it did not have.

Also

VirtualSX1262 handles two commands it had defined and never acted on.
SetTxParams is why transmit power is readable at all. Calibrate returns the
gain register to its reset default — the mechanism behind the 1.17.1 fault,
where MeshCore's AGC reset re-applies a compile-time macro over whatever the
operator set at runtime, and on a variant without that macro (this one included)
re-applies nothing at all.

kSetFem = 0x06 carries the enable line in from the emulator, as a command
rather than over SPI because the firmware drives it as an ordinary GPIO.

Verified

radioserver and simple_repeater both build clean from this branch. The
Windows/TCP work from #4 is untouched — this was ported on top of it rather
than copied over it, which was a live risk: the tree it was developed in
predated that merge.

Consumers

Needs MeshBench/meshbench#64, which parses the extended payload and drives
the node window's Radio tab. Release binaries need rebuilding for any of this
to reach a running sweep.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HFhR9GR4JzRuXgf2DcimqD

kRadioStats carried four counters. It now carries the radio: receive gain
register, transmit power, front-end line, mode, spreading factor, coding rate,
frequency, bandwidth, preamble, IRQ mask and flags. The engine reads it on
length, so a peer that stops at sixteen bytes still parses and an older node
still runs.

The reason is that a board profile is a datasheet claim about hardware and not
a claim about the firmware running on it. Until the chip reported its own
state there was no way to tell a node whose firmware configured it correctly
from one whose firmware did not - which is exactly the pair of faults MeshCore
1.17.1 fixed, receive gain reverting after an AGC reset and a transmit-enable
line that never went high.

The front-end line is three states rather than a flag, and it is latched at
the moment of transmission rather than read live. RadioLib holds the line low
while receiving and raises it just before SetTx, so the current level says
only whether the node happens to be listening; reading it live docked an idle
node 25 dB for the ordinary state of waiting. A node that has not transmitted
has not answered the question, and says so.

bridge/main.cpp writes the same payload in the same order. Two writers of one
wire format is the arrangement RadioServerSX1262 exists to avoid and is only
tolerable while they stay identical - an emulated node and a native one
reporting different shapes would make every comparison between them a
comparison of our own code. main.cpp reports the front end as "not answered"
rather than "module out", because a native node has no such pin wired and
reporting the line low would be true of the pin and false about the board.

VirtualSX1262 also handles two commands it had defined and never acted on.
SetTxParams is why transmit power was readable at all. Calibrate returns the
gain register to its reset default, which is the mechanism behind the 1.17.1
fault: MeshCore's own AGC reset re-applies a compile-time macro over whatever
the operator set at runtime, and on a variant without that macro - this one
included - re-applies nothing at all.

kSetFem carries the enable line in from the emulator. It arrives as a command
rather than over SPI because the firmware drives it as an ordinary GPIO: the
module sits beside the radio, not inside it, and the chip has no idea whether
its output reaches an antenna.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@A13xB0
A13xB0 merged commit 45abc4b into main Aug 14, 2026
@A13xB0
A13xB0 deleted the radio-state-across-the-bridge branch August 14, 2026 23:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants