Skip to content

Commit 45af602

Browse files
robeklweebl2000
authored andcommitted
Respect dynamic CR in transmit timing
(cherry picked from commit d2e230d)
1 parent 4237314 commit 45af602

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
}
@@ -271,12 +275,12 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
271275
}
272276

273277
uint32_t MyMesh::getRetransmitDelay(const mesh::Packet *packet) {
274-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * 0.5f);
275-
return getRNG()->nextInt(0, 5*t + 1);
278+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * 0.5f);
279+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
276280
}
277281
uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
278-
uint32_t t = (_radio->getEstAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2) * 0.2f);
279-
return getRNG()->nextInt(0, 5*t + 1);
282+
uint32_t tx_airtime_ms = (estimateTxAirtimeFor(packet->getPathByteLen() + packet->payload_len + 2, packet->_tx_cr) * 0.2f);
283+
return getRNG()->nextInt(0, 5 * tx_airtime_ms + 1);
280284
}
281285

282286
uint8_t MyMesh::getExtraAckTransmitCount() const {
@@ -965,6 +969,7 @@ void MyMesh::begin(bool has_display) {
965969
_store->loadChannels(this);
966970

967971
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
972+
setDefaultCR(_prefs.cr);
968973
radio_driver.setTxPower(_prefs.tx_power_dbm);
969974
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
970975
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
@@ -1392,6 +1397,7 @@ void MyMesh::handleCmdFrame(size_t len) {
13921397
savePrefs();
13931398

13941399
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
1400+
setDefaultCR(_prefs.cr);
13951401
MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf,
13961402
(uint32_t)cr);
13971403

@@ -1757,10 +1763,13 @@ void MyMesh::handleCmdFrame(size_t len) {
17571763
memcpy(&auth, &cmd_frame[5], 4);
17581764
auto pkt = createTrace(tag, auth, flags);
17591765
if (pkt) {
1766+
if ((path_len >> path_sz) > 0) {
1767+
pkt->_tx_cr = selectCodingRateForPeer(&cmd_frame[10], 1 << path_sz);
1768+
}
17601769
sendDirect(pkt, &cmd_frame[10], path_len);
17611770

1762-
uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2);
1763-
uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len >> path_sz);
1771+
uint32_t tx_airtime_ms = estimateTxAirtimeFor(pkt->payload_len + pkt->path_len + 2, pkt->_tx_cr);
1772+
uint32_t est_timeout = calcDirectTimeoutMillisFor(tx_airtime_ms, path_len >> path_sz);
17641773

17651774
out_frame[0] = RESP_CODE_SENT;
17661775
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
bool getCADEnabled() const override;
109110
int calcRxDelay(float score, uint32_t air_time) const 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) {
@@ -1327,12 +1327,14 @@ void MyMesh::loop() {
13271327
if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params
13281328
set_radio_at = 0; // clear timer
13291329
radio_driver.setParams(pending_freq, pending_bw, pending_sf, pending_cr);
1330+
setDefaultCR(pending_cr);
13301331
MESH_DEBUG_PRINTLN("Temp radio params");
13311332
}
13321333

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

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) {
@@ -700,6 +700,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
700700
}
701701

702702
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
703+
setDefaultCR(_prefs.cr);
703704
radio_driver.setTxPower(_prefs.tx_power_dbm);
704705
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
705706

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

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

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;
@@ -770,6 +770,7 @@ void SensorMesh::begin(FILESYSTEM* fs) {
770770
}
771771

772772
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
773+
setDefaultCR(_prefs.cr);
773774
radio_driver.setTxPower(_prefs.tx_power_dbm);
774775
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
775776

@@ -915,12 +916,14 @@ void SensorMesh::loop() {
915916
if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params
916917
set_radio_at = 0; // clear timer
917918
radio_driver.setParams(pending_freq, pending_bw, pending_sf, pending_cr);
919+
setDefaultCR(pending_cr);
918920
MESH_DEBUG_PRINTLN("Temp radio params");
919921
}
920922

921923
if (revert_radio_at && millisHasNowPassed(revert_radio_at)) { // revert radio params to orig
922924
revert_radio_at = 0; // clear timer
923925
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
926+
setDefaultCR(_prefs.cr);
924927
MESH_DEBUG_PRINTLN("Radio params restored");
925928
}
926929

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());
@@ -334,8 +353,7 @@ void Dispatcher::checkSend() {
334353
if (outbound->_tx_cr != 0 && outbound->_tx_cr != _default_cr) {
335354
_radio->setCodingRate(outbound->_tx_cr);
336355
}
337-
338-
uint32_t max_airtime = _radio->getEstAirtimeFor(len)*3/2;
356+
uint32_t max_airtime = estimateTxAirtimeFor(len, outbound->_tx_cr) * 3 / 2;
339357
outbound_start = _ms->getMillis();
340358
bool success = _radio->startSendRaw(raw, len);
341359
if (!success) {
@@ -402,4 +420,4 @@ unsigned long Dispatcher::futureMillis(int millis_from_now) const {
402420
return _ms->getMillis() + millis_from_now;
403421
}
404422

405-
}
423+
}

0 commit comments

Comments
 (0)