171 lines
9.2 KiB
Markdown
171 lines
9.2 KiB
Markdown
# Off-channel preamble investigation
|
|
|
|
Measured 2026-09-14. **The SF8 off-channel preamble indication reproduces with
|
|
a stationary, fully initialized receiver, without profile hopping or fast RX
|
|
reuse.** Both boards reproduce it when their transmitter/receiver roles are
|
|
reversed. This is evidence of transmitter-associated off-channel detection in
|
|
this close-range bench setup, not evidence that the channel jump needs more
|
|
settling time.
|
|
|
|
The earlier SF8 scan's long software guard explains its missed listening
|
|
opportunity. The earlier SF6 scan miss remains unresolved: its trace had no
|
|
preamble indication or guard hold. No production guard or acquisition policy
|
|
was changed during this investigation.
|
|
|
|
## Controlled experiment
|
|
|
|
- XIAO ESP32-S3 + WIO SX1262 (COM31) and SenseCAP Indicator ESP32-S3 LoRa
|
|
(COM28). The Indicator RP2040 and RAK4631 were not modified.
|
|
- Receiver fixed at 910.000 MHz. Transmitter silent, on frequency, or offset
|
|
by +/-250, +/-500 or +/-1,000 kHz. These are offsets, not bandwidths.
|
|
- 125 kHz bandwidth, SF8 or SF6, CR4/5, 32 programmed preamble symbols,
|
|
-9 dBm, one 16-byte sequence-tagged synthetic payload per transmitting case.
|
|
- Each case fully initializes both radios. RX uses ordinary `startReceive()`;
|
|
profile-switch optimization and experimental omission masks are disabled.
|
|
Buffered 8 MHz SPI remains enabled. No hops, warm-retune reuse, CAD, or
|
|
`isReceiving()` software guard runs during these controls.
|
|
- TX is prepared before RX is armed. Each receive window lasts 450 ms;
|
|
all eight cases are shuffled within each balanced round, seed 814910.
|
|
The full RX window completes even when an off-frequency packet is not
|
|
received, as expected. An on-frequency positive-control failure stops the
|
|
experiment. No RF retransmissions are used to repair a result.
|
|
- The HAL records actual outgoing `SetRfFrequency` bytes on both boards,
|
|
and the frequency word present at `SetTx`. The host verifies these words
|
|
against the requested frequencies. This checks commands sent to the chip,
|
|
not an independent measurement of the emitted RF spectrum.
|
|
- Existing IRQ replies are observed and IRQs additionally polled at a nominal
|
|
64 us interval. Events are buffered in RAM; timestamps are software
|
|
observations, not synchronized RF arrival times. Unknown payload contents
|
|
are not exported.
|
|
|
|
The three completed matrices contain **128 windows: 112 transmitted probes
|
|
and 16 silent controls**. A separate initial 450 ms receiver-only smoke check
|
|
was also performed. These are bounded diagnostic controls, not another
|
|
100-packets-per-channel capacity sweep.
|
|
|
|
## Results
|
|
|
|
Entries below are windows with a preamble indication / tested windows. Each
|
|
positive window reported one indication; latched IRQs do not count continuous
|
|
detector activity or prove a valid packet.
|
|
|
|
| Transmitter offset | SF8, XIAO RX | SF8, Indicator RX | SF6, XIAO RX |
|
|
| --- | ---: | ---: | ---: |
|
|
| Silent | 0/8 | 0/4 | 0/4 |
|
|
| On frequency | 8/8 | 4/4 | 4/4 |
|
|
| -250 kHz | 8/8 | 4/4 | 1/4 |
|
|
| +250 kHz | 8/8 | 4/4 | 0/4 |
|
|
| -500 kHz | 5/8 | 3/4 | 0/4 |
|
|
| +500 kHz | 1/8 | 3/4 | 0/4 |
|
|
| -1,000 kHz | 5/8 | 4/4 | 0/4 |
|
|
| +1,000 kHz | 5/8 | 3/4 | 0/4 |
|
|
|
|
All **16 on-frequency probes delivered valid payloads**. None of the 96
|
|
off-frequency probes delivered a valid payload. No silent control detected a
|
|
preamble. Completed windows ended in RX mode with zero device errors; there
|
|
were no foreign valid payloads or trace overflows.
|
|
|
|
Most off-frequency detections stopped at `PreambleDetected` (0x0004). Four
|
|
progressed further but failed CRC (`seen_irq=0x0056`: preamble, header, RxDone,
|
|
CRC error): two at +250 kHz with XIAO RX, and one each at +250 and +1,000 kHz
|
|
with Indicator RX. Therefore **HeaderValid alone would not prove that these
|
|
off-frequency indications are legitimate traffic**.
|
|
|
|
In forward SF8 on-frequency controls, receiver signal strength (RSSI) sampled
|
|
at the first preamble was -42 to -41 dBm; at +/-250 kHz it was -91 to -88 dBm.
|
|
These are single-point receiver readings, not calibrated measurements of
|
|
transmitted leakage or a sensitivity test. Board positions and attenuation
|
|
were not systematically varied. Reversing roles reproduces the behavior but
|
|
does not isolate its physical path.
|
|
|
|
## What this explains
|
|
|
|
The [earlier SF8 four-channel scan](sf8_5p1_trace_validation.md) missed probe
|
|
13 on 910.250 MHz after detecting a bare preamble while tuned to 910.000 MHz.
|
|
The existing `CustomSX1262::isReceiving()` guard allowed 91 ms for preamble
|
|
progression, consistent with the observed 92.257 ms from first preamble
|
|
observation to the stale-bit clear. That produced approximately 102 ms total
|
|
occupancy on the wrong channel and a 135.145 ms target-channel revisit gap.
|
|
The programmed 32-symbol preamble lasted only 65.536 ms.
|
|
|
|
The delayed retune itself took 550 us. These controls reproduce the suspect
|
|
off-frequency indication with no retunes at all. Together the evidence
|
|
supports **off-channel acquisition plus a long guard hold** as the SF8
|
|
failure mechanism, rather than slow SPI or a demonstrated need for a longer
|
|
post-jump delay. It does not independently prove the RF source of that one
|
|
historical scan event.
|
|
|
|
The controlled-transmitter association and quiet silent controls make random
|
|
ambient RF alone an inadequate explanation of the repeated bench result.
|
|
Exact RF cause remains unmeasured: receiver selectivity/false acquisition,
|
|
transmitter spectral leakage, and coupling between the nearby boards are
|
|
not separated by these tests. No spectrum-analyzer capture or calibrated
|
|
attenuation sweep was performed. Increasing channel spacing is not established
|
|
as a fix: SF8 indications also occurred at +/-1 MHz.
|
|
|
|
The [earlier SF6 miss](sf6_5p1_trace_validation.md) had no observed nonzero IRQ
|
|
or guard hold. The four successful stationary SF6 positive controls show the
|
|
fixed-channel link works, but do not establish the acquisition time needed
|
|
after a retune. These small, differently sized samples are not packet-error
|
|
rate estimates or proof of a zero-loss channel count.
|
|
|
|
## Follow-up candidates, not implemented fixes
|
|
|
|
Semtech documents that false LoRa detections can occur and describes
|
|
`SetLoRaSymbNumTimeout` as validating reception over multiple symbols before
|
|
continuing when the modem locks. This is a candidate to investigate, not a
|
|
drop-in verified fix. Its behavior in continuous RX and through each retune
|
|
must be measured. See section 13.4.9, page 99 of the
|
|
[Semtech SX1261/2 datasheet, revision 2.2](https://resource.heltec.cn/download/WiFi_LoRa_32_V4/datasheet/SX1261_2%20V2-2.pdf).
|
|
|
|
Useful next experiments would qualify/revalidate preambles before granting a
|
|
long scan hold, and repeat the controls with lower signal levels or increased
|
|
physical isolation. Any candidate must preserve legitimate weak signals and
|
|
long preambles. Blindly shortening the current guard, or requiring only a
|
|
header indication, is not justified by these results. No production radio
|
|
change was made in this diagnostic turn.
|
|
|
|
## Reproduction, provenance, and checks
|
|
|
|
See the [stationary diagnostic instructions](../tools/hil/profile_switch_README.md#stationary-off-channel-preamble-controls).
|
|
The same diagnostic firmware binaries were used for all three matrices.
|
|
Base commit `c329cf1fc1e7f2e8c8733ab0d000094730458fe3` plus local changes;
|
|
RadioLib 7.7.1 at `187ef24791c3d844939b2be13a68bd890bd04e4c`, Espressif32
|
|
6.11.0 / Arduino ESP32 2.0.17. Both HIL targets built and uploaded successfully.
|
|
All **29 selected host/native tests passed** after testing.
|
|
|
|
Raw results and SHA-256:
|
|
|
|
- [Forward SF8, eight rounds](../tools/hil/preamble_stationary_sf8_results.json):
|
|
`e876a8b1727c5584aa67cb4fcdcae5ca30701e90f7ed998b5df36c37d245f7b0`
|
|
- [Reverse SF8, four rounds](../tools/hil/preamble_stationary_sf8_reverse_results.json):
|
|
`83b576544f807c6b81ee83a7db487137ef2584cb4981e475c7e7ac50e4fa2363`
|
|
- [Forward SF6, four rounds](../tools/hil/preamble_stationary_sf6_run2_results.json):
|
|
`bdb65b4e23d8b05c8523cec092533509021f878518a38523b02135b810da991b`
|
|
- [Aborted initial SF6 launch](../tools/hil/preamble_stationary_sf6_results.json)
|
|
is retained: no trials and no RF probes. A host reboot-command quoting
|
|
failure left the diagnostic image unready after the preceding run. After
|
|
correcting the command and rebooting both boards, the complete SF6 matrix
|
|
was recorded to the separate `run2` path. A subsequent host cleanup change
|
|
ensures an already-opened receiver port is closed if opening TX fails.
|
|
|
|
Tested firmware SHA-256:
|
|
|
|
- XIAO: `f89da2a2e542df481ff6c26d2492dcc46db8794b5549d3b4f73217767130a21d`
|
|
- Indicator: `e58207c7e63de625bee2d4e4400eb934b2737f51e8babc7c1fddd85c48efdda6`
|
|
|
|
## Device handoff
|
|
|
|
Fresh full 8 MiB backups were taken and separately verified before flashing,
|
|
in the private current-user MeshCore backup directory. No backup contents
|
|
or identity/channel secrets are in the diagnostic results.
|
|
|
|
- XIAO backup: `5e5825b625a0e6ded65aafa72658eb3b15b466316a9efe8239b2f09de9418e63`
|
|
- Indicator backup: `6f834296d4e29e4fe17297aad0a9e2bf2adcf0a1391cf645de1bc51aebfd70de`
|
|
|
|
Both original images were restored after the controls, separately verified
|
|
against the complete 8 MiB flash with matching digests, and hardware-reset.
|
|
The RAK4631 and Indicator RP2040 were untouched; the XIAO soak logger was not
|
|
restarted. The temporary HIL build overlay was removed. Investigation source,
|
|
tests, and results were initially handed off locally before publication.
|