fix #513 scale retransmission times based on true packet time on wire

This commit is contained in:
Kevin Hester
2020-11-14 10:07:25 +08:00
parent f346b4f0f2
commit 1839f8f7ca
5 changed files with 100 additions and 91 deletions

View File

@@ -53,57 +53,66 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
// 1kb was too small
#define RADIO_STACK_SIZE 4096
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
* has had enough time to switch their radio back into receive mode.
*/
#define MIN_TX_WAIT_MSEC 100
/**
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
* to guarantee this.
*/
#define MAX_TX_WAIT_MSEC 2000 // stress test would still fail occasionally with 1000
/**
* Calculate airtime per https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
* Calculate airtime per
* https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
* section 4
*
*
* @return num msecs for the packet
*/
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
uint32_t RadioInterface::getPacketTime(uint32_t pl)
{
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
uint8_t sf = 12; // FIXME
uint8_t nPreamble = 32; // FIXME
uint32_t bandwidthHz = 125 * 1000; // FIXME
float bandwidthHz = bw * 1000.0f;
bool headDisable = false; // we currently always use the header
bool lowDataOptEn = false; // FIXME
uint8_t cr = 1; // from 1 to 4
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
float tSym = (1 << sf) / bandwidthHz;
float tPreamble = (nPreamble + 4.25f) * tSym;
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
float tPreamble = (preambleLength + 4.25f) * tSym;
float numPayloadSym =
8 + max(ceilf(((8 * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * (cr + 4)), 0.0f);
8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
float tPayload = numPayloadSym * tSym;
float tPacket = tPreamble + tPayload;
uint32_t msecs = tPacket / 1000;
uint32_t msecs = tPacket * 1000;
DEBUG_MSG("(bw=%d, sf=%d, cr=4/%d) packet symLen=%d ms, payloadSize=%u, time %d ms\n", (int)bw, sf, cr, (int)(tSym * 1000),
pl, msecs);
return msecs;
}
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
{
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
return getPacketTime(pl);
}
/** The delay to use for retransmitting dropped packets */
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
{
return random(20 * 1000L, 22 * 1000L);
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
}
/** The delay to use when we want to send something but the ether is busy */
uint32_t RadioInterface::getTxDelayMsec()
{
return random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC);
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
* has had enough time to switch their radio back into receive mode.
*/
const uint32_t MIN_TX_WAIT_MSEC = 100;
/**
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
* to guarantee this.
*/
// const uint32_t MAX_TX_WAIT_MSEC = 2000; // stress test would still fail occasionally with 1000
return random(MIN_TX_WAIT_MSEC, shortPacketMsec);
}
void printPacket(const char *prefix, const MeshPacket *p)
@@ -208,8 +217,47 @@ void RadioInterface::applyModemConfig()
// Set up default configuration
// No Sync Words in LORA mode
if (channelSettings.spread_factor == 0) {
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
///< range
bw = 125;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
///< range
bw = 500;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
///< range
bw = 31.25;
cr = 8;
sf = 9;
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
bw = 125;
cr = 8;
sf = 12;
break;
default:
assert(0); // Unknown enum
}
} else {
sf = channelSettings.spread_factor;
cr = channelSettings.coding_rate;
bw = channelSettings.bandwidth;
if (bw == 31) // This parameter is not an integer
bw = 31.25;
}
power = channelSettings.tx_power;
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
assert(myRegion); // Should have been found in init
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
@@ -224,6 +272,7 @@ void RadioInterface::applyModemConfig()
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", freq);
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
}
/**