Dies ist eine alte Version des Dokuments!


MeshCore RX Delay Calculator

RX Delay (rxdelay / rx_delay_base) is a MeshCore repeater setting that delays processing of flood-routed packets based on how good the received signal is (the packet score).

Purpose: MeshCore uses „first packet wins“ for route discovery. Without RX delay, a repeater might forward a packet from a weak, distant hop before a stronger, better path arrives. RX delay gives better signals a head start by holding weaker copies longer in an internal queue.

Only affects flood routes. Direct-route packets are processed immediately.

Default: rxdelay = 0 (disabled). Recommended minimum for repeaters is often 2 or higher, depending on neighbor density.

Limits (firmware):

  • Delay < 50 ms → packet processed immediately (no queue)
  • Delay > 32 000 ms → capped at 32 seconds
  • rxdelay CLI range: 0 … 20 (0 = off)

Sources: MyMesh.cpp, Issue #2064, Issue #2123

/**
 * MeshCore RX delay (milliseconds)
 *
 * @param {number} rxDelayBase  - CLI value "rxdelay" (0 = disabled, typical 2–10)
 * @param {number} score        - packet score 0.0 … 1.0 (from SNR + packet length)
 * @param {number} airtimeMs    - estimated on-air time of the packet in ms
 * @returns {number} delay in ms (can be negative → treated as immediate)
 */
function calcRxDelay(rxDelayBase, score, airtimeMs) {
  if (rxDelayBase <= 0) return 0;
  return (Math.pow(rxDelayBase, 0.85 - score) - 1) * airtimeMs;
}

Excel equivalent (same formula as in your spreadsheet):

=(rx_delay_base ^ (0.85 - score) - 1) * airtime

Your spreadsheet uses airtime = 150 ms as a fixed example. In firmware, airtime comes from getEstAirtimeFor(packet_length) and depends on SF, bandwidth, and payload size.

The score is not raw SNR. It is computed in packetScoreInt() from SNR, spreading factor, and packet length:

score = clamp(0, 1, ((SNR - SNR_threshold[SF]) / 10) * (1 - packet_len / 256))

Interpretation:

  • score = 1.0 → excellent signal, well above decoding threshold, short packet
  • score = 0.5 → moderate margin above threshold
  • score = 0.0 → at or below SNR threshold (should not decode reliably)

SNR thresholds per SF (approx.): SF7 −7.5 dB, SF8 −10, SF9 −12.5, SF10 −15, SF11 −17.5, SF12 −20.

Example: SF10, SNR = −5 dB, 64-byte packet → score ≈ 1) / 10) × (1 − 64/256) = 0.75

Your Excel sheet layout:

rx_delay_base score0.10.20.30.40.50.60.70.80.91.0
1 0000000000
2 1028570554128165−5−15
  • Rows = rx_delay_base (1 … 19 in your sheet; CLI allows up to 20)
  • Columns = packet score (0.1 … 1.0)
  • Cells = delay in milliseconds (for airtime = 150 ms)

Key behaviors:

  • rx_delay_base = 1 → always 0 ms delay (feature effectively off)
  • rx_delay_base between 0 and 1inverted behavior: weak signals delayed less than strong ones (avoid!)
  • Higher rx_delay_base → longer delays overall → stronger collision/backoff spreading
  • Higher score (better signal) → shorter delay → better paths propagate first

Paste the block below into a DokuWiki page. Requires HTML embed enabled (htmlok in config, or the htmlok plugin). Wrap in <html>…</html> if your wiki needs it.

<html> <style>

#mc-rxdelay { font-family: sans-serif; max-width: 960px; }
#mc-rxdelay table { border-collapse: collapse; width: 100%; font-size: 13px; }
#mc-rxdelay th, #mc-rxdelay td { border: 1px solid #ccc; padding: 4px 6px; text-align: right; }
#mc-rxdelay th { background: #eef; position: sticky; top: 0; }
#mc-rxdelay td.row-hdr { background: #f5f5f5; font-weight: bold; text-align: center; }
#mc-rxdelay .neg { color: #888; }
#mc-rxdelay .imm { background: #e8f5e9; }
#mc-rxdelay .queued { background: #fff8e1; }
#mc-rxdelay .controls { margin: 12px 0; display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
#mc-rxdelay .controls label { display: flex; align-items: center; gap: 6px; }
#mc-rxdelay .result-box { background: #f0f7ff; border: 1px solid #9cf; padding: 10px; margin: 12px 0; border-radius: 4px; }

</style>

<div id=„mc-rxdelay“>

<div class="controls">
  <label>Airtime (ms): <input type="number" id="mc-airtime" value="150" min="1" max="5000" step="1"></label>
  <label>Highlight rx_delay_base: <input type="number" id="mc-highlight-rx" value="2" min="0" max="20" step="0.1"></label>
  <label>Highlight score: <input type="number" id="mc-highlight-score" value="0.5" min="0" max="1" step="0.05"></label>
  <button type="button" onclick="mcRxDelayUpdate()">Recalculate</button>
</div>
<div class="result-box" id="mc-single-result"></div>
<div style="overflow-x:auto; max-height: 480px; overflow-y: auto;">
  <table id="mc-rxdelay-table">
    <thead></thead>
    <tbody></tbody>
  </table>
</div>
<p style="font-size:12px;color:#666;margin-top:8px;">
  Green = <50 ms (processed immediately) · Yellow = queued · Grey italic = negative (also immediate)
</p>

</div>

<script type=„text/javascript“> /* MeshCore RX delay – matches Excel „rxdelay calc.xlsx“ and firmware MyMesh::calcRxDelay */

var MC_RX_SCORES = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]; var MC_RX_BASES = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]; var MC_RX_THRESHOLD_MS = 50; var MC_RX_MAX_MS = 32000;

function mcCalcRxDelay(rxDelayBase, score, airtimeMs) {

if (rxDelayBase <= 0) return 0;
return (Math.pow(rxDelayBase, 0.85 - score) - 1) * airtimeMs;

}

/ Optional: compute packet score from SNR (SF7–SF12), matching RadioLibWrappers.cpp */ function mcPacketScore(snr, sf, packetLen) { var thresholds = [-7.5, -10, -12.5, -15, -17.5, -20]; if (sf < 7 || sf > 12) return 0; if (snr < thresholds[sf - 7]) return 0; var rate = (snr - thresholds[sf - 7]) / 10.0; var penalty = 1 - (packetLen / 256.0); return Math.max(0, Math.min(1, rate * penalty)); } / Firmware-applied delay (clamp + threshold) */ function mcEffectiveRxDelay(rxDelayBase, score, airtimeMs) {

var raw = mcCalcRxDelay(rxDelayBase, score, airtimeMs);
if (raw <MC_RX_THRESHOLD_MS) return 0;
return Math.min(Math.round(raw), MC_RX_MAX_MS);

}

function mcRxDelayUpdate() {

var airtime = parseFloat(document.getElementById('mc-airtime').value) || 150;
var hlRx    = parseFloat(document.getElementById('mc-highlight-rx').value) || 0;
var hlScore = parseFloat(document.getElementById('mc-highlight-score').value) || 0;
var raw = mcCalcRxDelay(hlRx, hlScore, airtime);
var eff = mcEffectiveRxDelay(hlRx, hlScore, airtime);
document.getElementById('mc-single-result').innerHTML =
  '<strong>Single value:</strong> rx_delay_base=' + hlRx +
  ', score=' + hlScore + ', airtime=' + airtime + ' ms<br>' +
  'Formula: (' + hlRx + '<sup>(0.85 − ' + hlScore + ')</sup>   − 1) × ' + airtime +
  ' = <strong>' + raw.toFixed(1) + ' ms</strong> (raw)<br>' +
  'Firmware effective delay: <strong>' + eff + ' ms</strong>' +
  (raw <MC_RX_THRESHOLD_MS ? ' (below 50 ms threshold → immediate)' : '');
var thead = '<tr><th>rx_delay_base \\ score</th>';
for (var s = 0; s <MC_RX_SCORES.length; s++) {
  thead += '<th>' + MC_RX_SCORES[s].toFixed(1) + '</th>';
}
thead += '</tr>';
document.querySelector('#mc-rxdelay-table thead').innerHTML = thead;
var tbody = '';
for (var r = 0; r <MC_RX_BASES.length; r++) {
  var rx = MC_RX_BASES[r];
  var rowClass = (Math.abs(rx - hlRx) <0.01) ? ' style="outline:2px solid #39f;"' : '';
  tbody += '<tr' + rowClass + '><td class="row-hdr">' + rx + '</td>';
  for (var c = 0; c <MC_RX_SCORES.length; c++) {
    var sc = MC_RX_SCORES[c];
    var val = mcCalcRxDelay(rx, sc, airtime);
    var cls = '';
    if (val <0) cls = 'neg';
    else if (val <MC_RX_THRESHOLD_MS) cls = 'imm';
    else cls = 'queued';
    var hi = (Math.abs(rx - hlRx) <0.01 && Math.abs(sc - hlScore) <0.001) ? ' outline:2px solid #f90;' : '';
    tbody += '<td class="' + cls + '" style="' + hi + '">' +
      (val <0 ? '<span class="neg">' + val.toFixed(0) + '</span>' : val.toFixed(0)) +
      '</td>';
  }
  tbody += '</tr>';
}
document.querySelector('#mc-rxdelay-table tbody').innerHTML = tbody;

}

if (document.readyState === 'loading') {

document.addEventListener('DOMContentLoaded', mcRxDelayUpdate);

} else {

mcRxDelayUpdate();

} </script> </html>

<html> <style>

#mc-score-calc { font-family: sans-serif; max-width: 480px; }
#mc-score-calc .controls { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 8px; }
#mc-score-calc .out { background: #f5f5f5; padding: 8px; border-radius: 4px; }

</style> <div id=„mc-score-calc“>

<p><strong>Estimate packet score from SNR</strong></p>
<div class="controls">
  <label>SNR (dB): <input type="number" id="mc-snr" value="-5" step="0.5"></label>
  <label>SF: <select id="mc-sf"><option>7</option><option>8</option><option>9</option><option selected>10</option><option>11</option><option>12</option></select></label>
  <label>Packet len: <input type="number" id="mc-plen" value="64" min="1" max="256"></label>
  <button type="button" onclick="mcScoreUpdate()">Calc</button>
</div>
<div class="out" id="mc-score-out"></div>

</div> <script type=„text/javascript“> function mcScoreUpdate() {

var snr = parseFloat(document.getElementById('mc-snr').value);
var sf  = parseInt(document.getElementById('mc-sf').value, 10);
var pl  = parseInt(document.getElementById('mc-plen').value, 10);
var score = mcPacketScore(snr, sf, pl);
document.getElementById('mc-score-out').innerHTML =
  'Score = <strong>' + score.toFixed(3) + '</strong> — use this in the table above.';

} mcScoreUpdate(); </script> </html>

  1. Start with rxdelay 2 on repeaters in busy areas; increase if you still see duplicate flood collisions.
  2. Never use 0 < rxdelay < 1 — it reverses the logic (bad paths win).
  3. rxdelay 1 gives zero delay for all scores (same as off).
  4. Compare delays for your typical packet airtime: a 300 ms airtime doubles all table values.
  5. Newer firmware may autotune delays from neighbor count (CLI: get autotune / set autotune on).
  6. RX delay is complementary to TX delay (txdelay): TX delay spreads transmissions, RX delay spreads reception/processing of floods.
get rxdelay          # show current value (float, 0 = off)
set rxdelay 2          # enable with base 2

Companion radio stores the value internally as millis × 1000; repeater/room/sensor use the float directly.



1)
−5 − (−15
  • mc_rxdelay_calc.1780222900.txt.gz
  • Zuletzt geändert: 2026/05/31 12:21
  • von bmke-a-2345-tdeck