From 4e697970eb305524f0555834907d801806117f35 Mon Sep 17 00:00:00 2001 From: R0ck Date: Sat, 17 Oct 2026 04:58:02 +0100 Subject: [PATCH 1/3] bridge: receive only what the receiver was listening for, with --lenient-receive to restore the grace Moves virtual-sx1262 to strict receive (ABI 1.7) and turns it on: this build's clock is the engine's, so the chip can tell when a frame began and refuse one its receiver was in standby, in CAD or transmitting for, as silicon does. --lenient-receive brings the inbox grace back, for reproducing an earlier run. --- bridge/main.cpp | 7 +++++++ vendor/virtual-sx1262 | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bridge/main.cpp b/bridge/main.cpp index b12caf5..2649dda 100644 --- a/bridge/main.cpp +++ b/bridge/main.cpp @@ -53,6 +53,7 @@ void loop(); // Defined by the host variant. extern uint32_t g_sim_millis; int g_stuck_irq_ms = 0; +bool g_lenient_receive = false; // The receiver-noise stream the chip model draws from. Distinct per node so // two nodes do not read the same "random" bytes at the same instants - which // is what seeds each node's RNG, its CSMA backoff and its advert jitter. Left @@ -201,6 +202,9 @@ int main(int argc, char** argv) { // without a way to reproduce it the difference between 1.16 and 1.17 // cannot be observed at all. else if (!strcmp(argv[i], "--stuck-irq-ms")) g_stuck_irq_ms = atoi(next()); + // The chip's inbox grace, back on: for reproducing a run made before this + // build received only what its receiver was listening for. + else if (!strcmp(argv[i], "--lenient-receive")) g_lenient_receive = true; else if (!strcmp(argv[i], "--print-airtime")) printAirtimeFor = atoi(next()); } @@ -234,6 +238,9 @@ int main(int argc, char** argv) { : (g_identity_seed ^ 0x9E3779B97F4A7C15ULL)); if (g_stuck_irq_ms > 0) sim_hal.chip().setStuckIrqMs((uint32_t)g_stuck_irq_ms); + // This node's clock is the engine's, so the chip can judge when a frame began + // and refuse one its receiver was not listening for, as silicon does. + sim_hal.chip().setStrictReceive(!g_lenient_receive); setup(); drainTx(); flushConsole(); diff --git a/vendor/virtual-sx1262 b/vendor/virtual-sx1262 index f0261f3..932ae39 160000 --- a/vendor/virtual-sx1262 +++ b/vendor/virtual-sx1262 @@ -1 +1 @@ -Subproject commit f0261f3f3d9f0bb7f6ab5d844c30e2148aa8069a +Subproject commit 932ae396cd237fd9e6e163f47ededf7e304d52cc From be0e883745c5ae027b0a1ce80b8c17ff18195af9 Mon Sep 17 00:00:00 2001 From: R0ck Date: Sat, 17 Oct 2026 05:04:32 +0100 Subject: [PATCH 2/3] bridge: say the chip reads a frame never locked onto, and latch detection flags under strict receive Moves virtual-sx1262 to the head of strict receive, where the detection flags stay latched past the carrier and failure 3 withdraws a header the receiver never locked onto. Stats byte 47 bit 1 tells the engine this chip reads failure 3, because an older one reads it as a CRC error. --- bridge/main.cpp | 5 ++++- vendor/virtual-sx1262 | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bridge/main.cpp b/bridge/main.cpp index 2649dda..ebb7996 100644 --- a/bridge/main.cpp +++ b/bridge/main.cpp @@ -82,6 +82,7 @@ constexpr uint8_t kChannelBusy = 0x08; // is another station on the air here? constexpr uint8_t kRadioStats = 0x09; // node -> host: what the chip has seen constexpr uint8_t kFrameFailed = 0x0A; // host -> node: a frame locked onto and lost constexpr uint8_t kCapFrameFailed = 0x01; // stats byte 47: this bridge takes kFrameFailed +constexpr uint8_t kCapNoLock = 0x02; // and its chip reads failure 3 as never locked onto sock_t gFd = BAD_SOCK; std::deque gConsoleIn; @@ -400,7 +401,9 @@ int main(int argc, char** argv) { // engine sends kFrameFailed only to a node that says so here, because // a bridge without that case ends its connection on a kind it does // not know, and the engine cannot tell the two apart any other way. - sb[47] = kCapFrameFailed; + // A chip older than ABI 1.7 reads failure 3 as a CRC error, so the + // engine sends it only where this bit says the chip knows better. + sb[47] = kCapFrameFailed | kCapNoLock; writeMsg(gFd, kRadioStats, sb, sizeof(sb)); } if (!writeMsg(gFd, kAck, payload.data(), 4)) goto done; diff --git a/vendor/virtual-sx1262 b/vendor/virtual-sx1262 index 932ae39..5b326f9 160000 --- a/vendor/virtual-sx1262 +++ b/vendor/virtual-sx1262 @@ -1 +1 @@ -Subproject commit 932ae396cd237fd9e6e163f47ededf7e304d52cc +Subproject commit 5b326f9bc4290ae264d4ac72b8e65f9ad5d133d2 From 2de2cc55f64a433fe8af24c0dfedd65b65a9d6a0 Mon Sep 17 00:00:00 2001 From: R0ck Date: Sat, 17 Oct 2026 06:52:37 +0100 Subject: [PATCH 3/3] vendor: virtual-sx1262 keeps a carrier's preamble detected once under strict receive --- vendor/virtual-sx1262 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/virtual-sx1262 b/vendor/virtual-sx1262 index 5b326f9..a5430e2 160000 --- a/vendor/virtual-sx1262 +++ b/vendor/virtual-sx1262 @@ -1 +1 @@ -Subproject commit 5b326f9bc4290ae264d4ac72b8e65f9ad5d133d2 +Subproject commit a5430e22ffbeac7fc470e0222d6bf8d56e164b63