Skip to content

LR1110 boards cannot receive on dev: startReceive() passes an IRQ bit as the RX timeout #3075

Description

@MDamon

Summary

On dev, CustomLR1110::startReceive() passes RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED as RadioLib's first argument. That parameter is the RX timeout, not an IRQ mask. The constant is 1 << 4 = 16, so the receiver is armed with a 16-tick timeout — at the LR11x0's 30.52 µs tick that is a ~488 µs receive window. The radio leaves RX before any packet can arrive, so the node never receives anything, while transmitting normally.

https://github.com/meshcore-dev/MeshCore/blob/dev/src/helpers/radiolib/CustomLR1110.h#L38-L41

int16_tstartReceive() override {
// include the PREAMBLE_DETECTED irq bit in reported flagsreturnLR1110::startReceive(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED, RADIOLIB_IRQ_RX_DEFAULT_FLAGS | (1UL << RADIOLIB_IRQ_PREAMBLE_DETECTED), RADIOLIB_IRQ_RX_DEFAULT_MASK, 0);
}

RadioLib's own implementation passes the timeout correctly:

// RadioLib LR11x0.cppint16_tLR11x0::startReceive() {
return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
}

Affected

All variants built with RADIO_CLASS=CustomLR1110:

t1000-e, wio_wm1110, minewsemi_me25ls01, thinknode_m3, thinknode_m7, thinknode_m9

main is not affected — the introducing commit is not an ancestor of main, and main's CustomLR1110.h has no startReceive() override.

This looks like a copy-paste slip

The sibling wrappers added in the same series all pass the timeout correctly. LR1110 is the only one passing an IRQ bit:

Wrapperfirst arg to startReceive()
CustomLLCC68RADIOLIB_SX126X_RX_TIMEOUT_INF
CustomSTM32WLxRADIOLIB_SX126X_RX_TIMEOUT_INF
CustomSX1262RADIOLIB_SX126X_RX_TIMEOUT_INF
CustomSX1268RADIOLIB_SX126X_RX_TIMEOUT_INF
CustomLR1110RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED

Introduced in ea5d7c8 ("LR1110: add PREAMBLE_DETECTED to reported irq flags", 2026-07-25).

Why it is easy to miss

The failure is silent and misdirects. The radio initialises cleanly, stats-core reports errors: 0, TX counters and airtime increment normally, and the noise floor reads a believable value. Nothing points at the firmware — it looks like a bad antenna, a region/preset mismatch, or a dead unit.

Evidence

Two SenseCAP T1000-E units, matched at 910.525 MHz / BW 62.5 / SF 8 / CR 5, a few feet apart, both on dev. Neither could receive anything:

repeater : {"recv":0,"sent":9,"flood_tx":8,"direct_tx":1,"flood_rx":0,"direct_rx":0,"recv_errors":0}
{"noise_floor":-120,"last_rssi":0,"last_snr":0.00,"tx_air_secs":8,"rx_air_secs":0}
companion: {"recv":0,"sent":7,"flood_tx":7,"direct_tx":0,"flood_rx":0,"direct_rx":0,"recv_errors":0}
{"noise_floor":-120,"last_rssi":0,"last_snr":0.00,"tx_air_secs":3,"rx_air_secs":0}

Both transmit (tx_air_secs rising) but rx_air_secs and recv_errors stay at 0 — the receiver is never open long enough to detect even a failed preamble. (-120 is the clamp floor; it is also close to the true thermal floor at BW 62.5 kHz, which is part of why this reads as normal.)

Applying the fix to only one of the two units isolates it. The fixed repeater immediately started receiving while the unfixed companion stayed deaf:

repeater RX delta: {'recv': 1, 'flood_rx': 1, 'recv_errors': 0}
last_rssi -29, last_snr 17.0, noise_floor -104
companion RX delta: {'recv': 0, 'flood_rx': 0, 'recv_errors': 0}

After fixing both, packets flow in each direction (-29/-31 dBm, SNR ~15).

Ruled out beforehand: frequency/BW/SF/CR mismatch (identical on both, also applied live via tempradio), TX power and near-field desense (fails identically at 0 dBm), USB brownout, and radio init failure (stats-coreerrors: 0).

Fix

- return LR1110::startReceive(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED, ...);+ return LR1110::startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, ...);

The PREAMBLE_DETECTED flag the original commit intended is unaffected — it is in the second argument, where it already is. PR to follow.

Caveat

Confirmed by behaviour on T1000-E only. The other five variants are affected by inspection (same override, same constant), not by testing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions