Skip to content

Commit dc7dd51

Browse files
authored
Merge pull request #2977 from oltaco/rx-irq-timeout
Add IRQ timeout logic for SX1262 and LR1121
2 parents 795989b + b28bf00 commit dc7dd51

6 files changed

Lines changed: 116 additions & 9 deletions

File tree

src/helpers/radiolib/CustomLR1110.h

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#include "MeshCore.h"
55

66
class CustomLR1110 : public LR1110 {
7+
uint32_t _preambleMillis = 66;
8+
uint32_t _maxPayloadMillis = 3934;
9+
uint32_t _activityAt = 0;
10+
bool _headerSeen = false;
711
bool _rx_boosted = false;
812

913
public:
@@ -32,9 +36,46 @@ class CustomLR1110 : public LR1110 {
3236
bool getRxBoostedGainMode() const { return _rx_boosted; }
3337

3438
bool isReceiving() {
35-
uint16_t irq = getIrqStatus();
36-
bool detected = ((irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID) || (irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
37-
return detected;
39+
uint32_t irq = getIrqStatus();
40+
bool preamble = irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED; // bit 4
41+
bool header = irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID; // bit 5
42+
bool hdrErr = irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR; // bit 6
43+
uint32_t now = millis();
44+
if (hdrErr) {
45+
clearIrqState(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED | RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_HEADER_ERR);
46+
_activityAt = 0;
47+
_headerSeen = false;
48+
return false;
49+
}
50+
if (header) {
51+
if (!_headerSeen) { _headerSeen = true; _activityAt = now; };
52+
if (now - _activityAt > _maxPayloadMillis) {
53+
MESH_DEBUG_PRINTLN("Clearing header IRQ after %ums", _maxPayloadMillis);
54+
clearIrqState(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED | RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_HEADER_ERR);
55+
_activityAt = 0; _headerSeen = false;
56+
return false;
57+
}
58+
return true;
59+
}
60+
if (preamble) {
61+
if (_activityAt == 0) _activityAt = now;
62+
if (now - _activityAt > _preambleMillis) {
63+
clearIrqState(RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED);
64+
_activityAt = 0;
65+
MESH_DEBUG_PRINTLN("Clearing preamble IRQ after %ums", _preambleMillis);
66+
67+
return false;
68+
}
69+
return true;
70+
}
71+
_activityAt = 0; _headerSeen = false;
72+
return false;
73+
}
74+
75+
void setMaxPacketMillis(PacketMillis maxPacketMillis) {
76+
MESH_DEBUG_PRINTLN("Setting _preambleMillis=%u, _maxPacketMillis=%u", maxPacketMillis.preambleMillis, maxPacketMillis.payloadMillis);
77+
_preambleMillis = maxPacketMillis.preambleMillis;
78+
_maxPayloadMillis = maxPacketMillis.payloadMillis;
3879
}
3980

4081
uint8_t getSpreadingFactor() const { return spreadingFactor; }

src/helpers/radiolib/CustomLR1110Wrapper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class CustomLR1110Wrapper : public RadioLibWrapper {
1414
((CustomLR1110 *)_radio)->setBandwidth(bw);
1515
((CustomLR1110 *)_radio)->setCodingRate(cr);
1616
updatePreamble(sf);
17+
((CustomLR1110 *)_radio)->setMaxPacketMillis(calcMaxPacketMillis(sf, bw, cr, preambleLengthForSF(sf)));
18+
1719
}
1820

1921
void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1110 *)_radio)->getFreqMHz()); }

src/helpers/radiolib/CustomSX1262.h

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
#include <RadioLib.h>
44
#include "MeshCore.h"
55

6-
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
7-
#define SX126X_IRQ_PREAMBLE_DETECTED 0x04
8-
96
class CustomSX1262 : public SX1262 {
7+
uint32_t _preambleMillis = 66;
8+
uint32_t _maxPayloadMillis = 3934;
9+
uint32_t _activityAt = 0;
10+
bool _headerSeen = false;
11+
1012
public:
1113
CustomSX1262(Module *mod) : SX1262(mod) { }
1214

@@ -99,9 +101,46 @@ class CustomSX1262 : public SX1262 {
99101
}
100102

101103
bool isReceiving() {
102-
uint16_t irq = getIrqFlags();
103-
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
104-
return detected;
104+
uint32_t irq = getIrqFlags();
105+
bool preamble = irq & RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED; // bit 2
106+
bool header = irq & RADIOLIB_SX126X_IRQ_HEADER_VALID; // bit 4
107+
bool hdrErr = irq & RADIOLIB_SX126X_IRQ_HEADER_ERR; // bit 5
108+
uint32_t now = millis();
109+
if (hdrErr) {
110+
clearIrqFlags(RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED | RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_HEADER_ERR | RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID);
111+
_activityAt = 0;
112+
_headerSeen = false;
113+
return false;
114+
}
115+
if (header) {
116+
if (!_headerSeen) { _headerSeen = true; _activityAt = now; };
117+
if (now - _activityAt > _maxPayloadMillis) {
118+
MESH_DEBUG_PRINTLN("Clearing header IRQ after %ums", _maxPayloadMillis);
119+
clearIrqFlags(RADIOLIB_SX126X_IRQ_PREAMBLE_DETECTED | RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_HEADER_ERR | RADIOLIB_SX126X_IRQ_SYNC_WORD_VALID);
120+
_activityAt = 0; _headerSeen = false;
121+
return false;
122+
}
123+
return true;
124+
}
125+
if (preamble) {
126+
if (_activityAt == 0) _activityAt = now;
127+
if (now - _activityAt > _preambleMillis) {
128+
clearIrqStatus(RADIOLIB_IRQ_PREAMBLE_DETECTED);
129+
_activityAt = 0;
130+
MESH_DEBUG_PRINTLN("Clearing preamble IRQ after %ums", _preambleMillis);
131+
132+
return false;
133+
}
134+
return true;
135+
}
136+
_activityAt = 0; _headerSeen = false;
137+
return false;
138+
}
139+
140+
void setMaxPacketMillis(PacketMillis maxPacketMillis) {
141+
MESH_DEBUG_PRINTLN("Setting _preambleMillis=%u, _maxPacketMillis=%u", maxPacketMillis.preambleMillis, maxPacketMillis.payloadMillis);
142+
_preambleMillis = maxPacketMillis.preambleMillis;
143+
_maxPayloadMillis = maxPacketMillis.payloadMillis;
105144
}
106145

107146
bool getRxBoostedGainMode() {

src/helpers/radiolib/CustomSX1262Wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class CustomSX1262Wrapper : public RadioLibWrapper {
1818
((CustomSX1262 *)_radio)->setBandwidth(bw);
1919
((CustomSX1262 *)_radio)->setCodingRate(cr);
2020
updatePreamble(sf);
21+
((CustomSX1262 *)_radio)->setMaxPacketMillis(calcMaxPacketMillis(sf, bw, cr, preambleLengthForSF(sf)));
2122
}
2223

2324
bool isReceivingPacket() override {

src/helpers/radiolib/RadioLibWrappers.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,21 @@ float RadioLibWrapper::packetScoreInt(float snr, int sf, int packet_len) {
228228

229229
return max(0.0, min(1.0, success_rate_based_on_snr * collision_penalty));
230230
}
231+
232+
PacketMillis RadioLibWrapper::calcMaxPacketMillis(uint8_t sf, float bw, uint8_t cr, uint8_t preambleSymbols) {
233+
// based on RadioLib's calculateTimeOnAir()
234+
uint32_t tsym_us = ((uint32_t)10000 << sf) / (bw * 10);
235+
uint32_t sfCoeff1_x4 = (sf == 5 || sf == 6) ? 25 : 17; // 6.25 : 4.25, semtech magic numbers to account for sync word + sfd
236+
237+
// preamble + syncword + sfd + header
238+
uint32_t preamble_us = (((preambleSymbols + 8) * 4 + sfCoeff1_x4) * tsym_us) / 4;
239+
240+
// airtime for max packet at current radio settings
241+
uint32_t total_us = _radio->getTimeOnAir(MAX_TRANS_UNIT);
242+
// airtime for payload only (no preamble, header or SOF)
243+
uint32_t payload_us = total_us > preamble_us ? total_us - preamble_us : 4000 - preamble_us; // fallback to 4 secs at worst case
244+
// rescale payload_us for max possible CR
245+
if (cr >= 5 && cr < 8) { payload_us = (payload_us * 8) / cr; }
246+
247+
return PacketMillis {(preamble_us + 999) / 1000, (payload_us + 999) / 1000};
248+
}

src/helpers/radiolib/RadioLibWrappers.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
#include <Mesh.h>
44
#include <RadioLib.h>
55

6+
struct PacketMillis {
7+
uint32_t preambleMillis; // preamble-detect -> header-valid deadline
8+
uint32_t payloadMillis; // header-valid -> rx-done deadline
9+
};
10+
611
class RadioLibWrapper : public mesh::Radio {
712
protected:
813
PhysicalLayer* _radio;
@@ -47,6 +52,7 @@ class RadioLibWrapper : public mesh::Radio {
4752
virtual uint8_t getSpreadingFactor() const { return LORA_SF; }
4853
static uint16_t preambleLengthForSF(uint8_t sf) { return sf <= 8 ? 32 : 16; }
4954
void updatePreamble(uint8_t sf) { _preamble_sf = sf; _radio->setPreambleLength(preambleLengthForSF(sf)); }
55+
PacketMillis calcMaxPacketMillis(uint8_t sf, float bw, uint8_t cr, uint8_t preambleSymbols);
5056
virtual int16_t performChannelScan();
5157

5258
int getNoiseFloor() const override { return _noise_floor; }

0 commit comments

Comments
 (0)