Skip to content

Commit 9d53158

Browse files
robeklweebl2000
authored andcommitted
Respect dynamic CR in transmit timing
(cherry picked from commit d2e230d)
1 parent 5f5be67 commit 9d53158

13 files changed

Lines changed: 116 additions & 43 deletions

File tree

examples/companion_radio/MyMesh.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ float MyMesh::getAirtimeBudgetFactor() const {
258258
return _prefs.airtime_factor;
259259
}
260260

261+
uint32_t MyMesh::estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr) const {
262+
return estimateLoRaAirtimeFor(len_bytes, _prefs.sf, _prefs.bw, tx_cr != 0 ? tx_cr : _prefs.cr);
263+
}
264+
261265
int MyMesh::getInterferenceThreshold() const {
262266
return 0; // disabled for now, until currentRSSI() problem is resolved
263267
}
@@ -268,12 +272,12 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
268272
}
269273

270274
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
271-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * 0.5f);
272-
return getRNG()->nextInt(0, 5*t + 1);
275+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * 0.5f);
276+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
273277
}
274278
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
275-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * 0.2f);
276-
return getRNG()->nextInt(0, 5*t + 1);
279+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * 0.2f);
280+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
277281
}
278282

279283
uint8_t MyMesh::getExtraAckTransmitCount() const {
@@ -962,6 +966,7 @@ void MyMesh::begin(bool has_display) {
962966
_store->loadChannels(this);
963967

964968
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
969+
setDefaultCR(_prefs.cr);
965970
radio_driver.setTxPower(_prefs.tx_power_dbm);
966971
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
967972
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
@@ -1389,6 +1394,7 @@ void MyMesh::handleCmdFrame(size_t len) {
13891394
savePrefs();
13901395

13911396
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
1397+
setDefaultCR(_prefs.cr);
13921398
MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf,
13931399
(uint32_t)cr);
13941400

@@ -1754,10 +1760,13 @@ void MyMesh::handleCmdFrame(size_t len) {
17541760
memcpy(&auth, &cmd_frame[5], 4);
17551761
auto pkt = createTrace(tag, auth, flags);
17561762
if (pkt) {
1763+
if ((path_len >> path_sz) > 0) {
1764+
pkt->_tx_cr = selectCodingRateForPeer(&cmd_frame[10], 1 << path_sz);
1765+
}
17571766
sendDirect(pkt, &cmd_frame[10], path_len);
17581767

1759-
uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2);
1760-
uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len >> path_sz);
1768+
uint32_t tx_airtime_ms = estimateTxAirtimeFor(pkt->payload_len + pkt->path_len + 2, pkt->_tx_cr);
1769+
uint32_t est_timeout = calcDirectTimeoutMillisFor(tx_airtime_ms, path_len >> path_sz);
17611770

17621771
out_frame[0] = RESP_CODE_SENT;
17631772
out_frame[1] = 0;

examples/companion_radio/MyMesh.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
104104

105105
protected:
106106
float getAirtimeBudgetFactor() const override;
107+
uint32_t estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr=0) const override;
107108
int getInterferenceThreshold() const override;
108109
int calcRxDelay(float score, uint32_t air_time) const override;
109110
uint32_t getRetransmitDelay(const mesh::Packet *packet) override;

examples/simple_repeater/MyMesh.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -578,12 +578,12 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
578578
}
579579

580580
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
581-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.tx_delay_factor);
582-
return getRNG()->nextInt(0, 5*t + 1);
581+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * _prefs.tx_delay_factor);
582+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
583583
}
584584
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
585-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.direct_tx_delay_factor);
586-
return getRNG()->nextInt(0, 5*t + 1);
585+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * _prefs.direct_tx_delay_factor);
586+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
587587
}
588588

589589
bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
@@ -1326,12 +1326,14 @@ void MyMesh::loop() {
13261326
if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params
13271327
set_radio_at = 0; // clear timer
13281328
radio_driver.setParams(pending_freq, pending_bw, pending_sf, pending_cr);
1329+
setDefaultCR(pending_cr);
13291330
MESH_DEBUG_PRINTLN("Temp radio params");
13301331
}
13311332

13321333
if (revert_radio_at && millisHasNowPassed(revert_radio_at)) { // revert radio params to orig
13331334
revert_radio_at = 0; // clear timer
13341335
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
1336+
setDefaultCR(_prefs.cr);
13351337
MESH_DEBUG_PRINTLN("Radio params restored");
13361338
}
13371339

examples/simple_repeater/MyMesh.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
135135
float getAirtimeBudgetFactor() const override {
136136
return _prefs.airtime_factor;
137137
}
138+
uint32_t estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr=0) const override {
139+
return estimateLoRaAirtimeFor(len_bytes, _prefs.sf, _prefs.bw, tx_cr != 0 ? tx_cr : _prefs.cr);
140+
}
138141

139142
bool allowPacketForward(const mesh::Packet* packet) override;
140143
const char* getLogDateTime() override;

examples/simple_room_server/MyMesh.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,12 @@ const char *MyMesh::getLogDateTime() {
272272
}
273273

274274
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
275-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.tx_delay_factor);
276-
return getRNG()->nextInt(0, 5*t + 1);
275+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * _prefs.tx_delay_factor);
276+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
277277
}
278278
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
279-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.direct_tx_delay_factor);
280-
return getRNG()->nextInt(0, 5*t + 1);
279+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * _prefs.direct_tx_delay_factor);
280+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
281281
}
282282

283283
bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
@@ -699,6 +699,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
699699
}
700700

701701
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
702+
setDefaultCR(_prefs.cr);
702703
radio_driver.setTxPower(_prefs.tx_power_dbm);
703704
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
704705

@@ -1008,12 +1009,14 @@ void MyMesh::loop() {
10081009
if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params
10091010
set_radio_at = 0; // clear timer
10101011
radio_driver.setParams(pending_freq, pending_bw, pending_sf, pending_cr);
1012+
setDefaultCR(pending_cr);
10111013
MESH_DEBUG_PRINTLN("Temp radio params");
10121014
}
10131015

10141016
if (revert_radio_at && millisHasNowPassed(revert_radio_at)) { // revert radio params to orig
10151017
revert_radio_at = 0; // clear timer
10161018
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
1019+
setDefaultCR(_prefs.cr);
10171020
MESH_DEBUG_PRINTLN("Radio params restored");
10181021
}
10191022

examples/simple_room_server/MyMesh.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
130130
float getAirtimeBudgetFactor() const override {
131131
return _prefs.airtime_factor;
132132
}
133+
uint32_t estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr=0) const override {
134+
return estimateLoRaAirtimeFor(len_bytes, _prefs.sf, _prefs.bw, tx_cr != 0 ? tx_cr : _prefs.cr);
135+
}
133136

134137
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
135138
void logRx(mesh::Packet* pkt, int len, float score) override;

examples/simple_secure_chat/main.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
193193
float getAirtimeBudgetFactor() const override {
194194
return _prefs.airtime_factor;
195195
}
196+
uint32_t estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr=0) const override {
197+
return estimateLoRaAirtimeFor(len_bytes, LORA_SF, LORA_BW, tx_cr != 0 ? tx_cr : LORA_CR);
198+
}
196199

197200
int calcRxDelay(float score, uint32_t air_time) const override {
198201
return 0; // disable rxdelay
@@ -578,6 +581,7 @@ void setup() {
578581
#endif
579582

580583
radio_driver.setParams(the_mesh.getFreqPref(), LORA_BW, LORA_SF, LORA_CR);
584+
the_mesh.setDefaultCR(LORA_CR);
581585
radio_driver.setTxPower(the_mesh.getTxPowerPref());
582586

583587
the_mesh.showWelcome();

examples/simple_sensor/SensorMesh.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,12 +313,12 @@ int SensorMesh::calcRxDelay(float score, uint32_t air_time) const {
313313
}
314314

315315
uint32_t SensorMesh::getRetransmitDelay(const mesh::Packet* packet) {
316-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.tx_delay_factor);
317-
return getRNG()->nextInt(0, 6)*t;
316+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * _prefs.tx_delay_factor);
317+
return getRNG()->nextInt(0, 6) * tx_airtime_ms;
318318
}
319319
uint32_t SensorMesh::getDirectRetransmitDelay(const mesh::Packet* packet) {
320-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * _prefs.direct_tx_delay_factor);
321-
return getRNG()->nextInt(0, 6)*t;
320+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * _prefs.direct_tx_delay_factor);
321+
return getRNG()->nextInt(0, 6) * tx_airtime_ms;
322322
}
323323
int SensorMesh::getInterferenceThreshold() const {
324324
return _prefs.interference_threshold;
@@ -766,6 +766,7 @@ void SensorMesh::begin(FILESYSTEM* fs) {
766766
}
767767

768768
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
769+
setDefaultCR(_prefs.cr);
769770
radio_driver.setTxPower(_prefs.tx_power_dbm);
770771
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
771772

@@ -911,12 +912,14 @@ void SensorMesh::loop() {
911912
if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params
912913
set_radio_at = 0; // clear timer
913914
radio_driver.setParams(pending_freq, pending_bw, pending_sf, pending_cr);
915+
setDefaultCR(pending_cr);
914916
MESH_DEBUG_PRINTLN("Temp radio params");
915917
}
916918

917919
if (revert_radio_at && millisHasNowPassed(revert_radio_at)) { // revert radio params to orig
918920
revert_radio_at = 0; // clear timer
919921
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
922+
setDefaultCR(_prefs.cr);
920923
MESH_DEBUG_PRINTLN("Radio params restored");
921924
}
922925

examples/simple_sensor/SensorMesh.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class SensorMesh : public mesh::Mesh, public CommonCLICallbacks {
115115

116116
// Mesh overrides
117117
float getAirtimeBudgetFactor() const override;
118+
uint32_t estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr=0) const override {
119+
return estimateLoRaAirtimeFor(len_bytes, _prefs.sf, _prefs.bw, tx_cr != 0 ? tx_cr : _prefs.cr);
120+
}
118121
bool allowPacketForward(const mesh::Packet* packet) override;
119122
int calcRxDelay(float score, uint32_t air_time) const override;
120123
uint32_t getRetransmitDelay(const mesh::Packet* packet) override;

src/Dispatcher.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,25 @@ uint32_t Dispatcher::getCADFailMaxDuration() const {
6363
return 4000; // 4 seconds
6464
}
6565

66+
uint32_t Dispatcher::estimateTxAirtimeFor(int len_bytes, uint8_t tx_cr) const {
67+
(void)tx_cr;
68+
return _radio->getEstAirtimeFor(len_bytes);
69+
}
70+
71+
// Matches the standard LoRa time-on-air equation for the configured modem settings.
72+
uint32_t Dispatcher::estimateLoRaAirtimeFor(int len_bytes, uint8_t sf, float bw_khz, uint8_t cr) const {
73+
bool ldro_enabled = (((float)(1UL << sf)) / bw_khz) > 16.0f;
74+
float low_data_rate_optimize = ldro_enabled ? 1.0f : 0.0f;
75+
float implicit_header = 0.0f;
76+
float crc_enabled = 1.0f;
77+
float preamble_symbols = 16.0f;
78+
float payload_symbols = 8.0f + fmaxf(ceilf((8.0f * (float)len_bytes - 4.0f * (float)sf + 28.0f + 16.0f * crc_enabled - 20.0f * implicit_header) /
79+
(4.0f * (float)sf - 8.0f * low_data_rate_optimize)) * (float)cr, 0.0f);
80+
float total_symbols = preamble_symbols + payload_symbols + 4.25f;
81+
float symbol_length_ms = ((float)(uint32_t(1) << sf) / bw_khz);
82+
return (uint32_t)ceilf(symbol_length_ms * total_symbols);
83+
}
84+
6685
void Dispatcher::loop() {
6786
if (millisHasNowPassed(next_floor_calib_time)) {
6887
_radio->triggerNoiseFloorCalibrate(getInterferenceThreshold());
@@ -333,8 +352,7 @@ void Dispatcher::checkSend() {
333352
if (outbound->_tx_cr != 0 && outbound->_tx_cr != _default_cr) {
334353
_radio->setCodingRate(outbound->_tx_cr);
335354
}
336-
337-
uint32_t max_airtime = _radio->getEstAirtimeFor(len)*3/2;
355+
uint32_t max_airtime = estimateTxAirtimeFor(len, outbound->_tx_cr) * 3 / 2;
338356
outbound_start = _ms->getMillis();
339357
bool success = _radio->startSendRaw(raw, len);
340358
if (!success) {
@@ -401,4 +419,4 @@ unsigned long Dispatcher::futureMillis(int millis_from_now) const {
401419
return _ms->getMillis() + millis_from_now;
402420
}
403421

404-
}
422+
}

0 commit comments

Comments
 (0)