mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-21 10:12:50 +00:00
Calculate airtime of transmitted and received packets separately (#8205)
This commit is contained in:
@@ -65,5 +65,7 @@ template <class T> class LR11x0Interface : public RadioLibInterface
|
|||||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||||
|
|
||||||
virtual void setStandby() override;
|
virtual void setStandby() override;
|
||||||
|
|
||||||
|
uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -65,6 +65,8 @@ class RF95Interface : public RadioLibInterface
|
|||||||
*/
|
*/
|
||||||
virtual void configHardwareForSend() override;
|
virtual void configHardwareForSend() override;
|
||||||
|
|
||||||
|
uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(*lora, pl, received); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Some boards require GPIO control of tx vs rx paths */
|
/** Some boards require GPIO control of tx vs rx paths */
|
||||||
void setTransmitEnable(bool txon);
|
void setTransmitEnable(bool txon);
|
||||||
|
|||||||
@@ -230,33 +230,7 @@ The band is from 902 to 928 MHz. It mentions channel number and its respective c
|
|||||||
separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts at 903.08 MHz center frequency.
|
separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts at 903.08 MHz center frequency.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p, bool received)
|
||||||
* 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(uint32_t pl)
|
|
||||||
{
|
|
||||||
float bandwidthHz = bw * 1000.0f;
|
|
||||||
bool headDisable = false; // we currently always use the header
|
|
||||||
float tSym = (1 << sf) / bandwidthHz;
|
|
||||||
|
|
||||||
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.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;
|
|
||||||
|
|
||||||
return msecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p)
|
|
||||||
{
|
{
|
||||||
uint32_t pl = 0;
|
uint32_t pl = 0;
|
||||||
if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) {
|
if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) {
|
||||||
@@ -265,7 +239,7 @@ uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p)
|
|||||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
|
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
|
||||||
pl = numbytes + sizeof(PacketHeader);
|
pl = numbytes + sizeof(PacketHeader);
|
||||||
}
|
}
|
||||||
return getPacketTime(pl);
|
return getPacketTime(pl, received);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The delay to use for retransmitting dropped packets */
|
/** The delay to use for retransmitting dropped packets */
|
||||||
@@ -624,8 +598,7 @@ void RadioInterface::applyModemConfig()
|
|||||||
saveFreq(freq + loraConfig.frequency_offset);
|
saveFreq(freq + loraConfig.frequency_offset);
|
||||||
|
|
||||||
slotTimeMsec = computeSlotTimeMsec();
|
slotTimeMsec = computeSlotTimeMsec();
|
||||||
preambleTimeMsec = getPacketTime((uint32_t)0);
|
preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw);
|
||||||
maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader));
|
|
||||||
|
|
||||||
LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f", freq, loraConfig.frequency_offset);
|
LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f", freq, loraConfig.frequency_offset);
|
||||||
LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d", myRegion->name, channelName, loraConfig.modem_preset,
|
LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d", myRegion->name, channelName, loraConfig.modem_preset,
|
||||||
@@ -635,7 +608,7 @@ void RadioInterface::applyModemConfig()
|
|||||||
LOG_INFO("numChannels: %d x %.3fkHz", numChannels, bw);
|
LOG_INFO("numChannels: %d x %.3fkHz", numChannels, bw);
|
||||||
LOG_INFO("channel_num: %d", channel_num + 1);
|
LOG_INFO("channel_num: %d", channel_num + 1);
|
||||||
LOG_INFO("frequency: %f", getFreq());
|
LOG_INFO("frequency: %f", getFreq());
|
||||||
LOG_INFO("Slot time: %u msec", slotTimeMsec);
|
LOG_INFO("Slot time: %u msec, preamble time: %u msec", slotTimeMsec, preambleTimeMsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Slottime is the time to detect a transmission has started, consisting of:
|
/** Slottime is the time to detect a transmission has started, consisting of:
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ class RadioInterface
|
|||||||
uint32_t slotTimeMsec = computeSlotTimeMsec();
|
uint32_t slotTimeMsec = computeSlotTimeMsec();
|
||||||
uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
||||||
uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast
|
uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast
|
||||||
uint32_t maxPacketTimeMsec = 3246; // calculated on startup, this is the default for LongFast
|
|
||||||
const uint32_t PROCESSING_TIME_MSEC =
|
const uint32_t PROCESSING_TIME_MSEC =
|
||||||
4500; // time to construct, process and construct a packet again (empirically determined)
|
4500; // time to construct, process and construct a packet again (empirically determined)
|
||||||
const uint8_t CWmin = 3; // minimum CWsize
|
const uint8_t CWmin = 3; // minimum CWsize
|
||||||
@@ -202,8 +201,8 @@ class RadioInterface
|
|||||||
*
|
*
|
||||||
* @return num msecs for the packet
|
* @return num msecs for the packet
|
||||||
*/
|
*/
|
||||||
uint32_t getPacketTime(const meshtastic_MeshPacket *p);
|
uint32_t getPacketTime(const meshtastic_MeshPacket *p, bool received = false);
|
||||||
uint32_t getPacketTime(uint32_t totalPacketLen);
|
virtual uint32_t getPacketTime(uint32_t totalPacketLen, bool received = false) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the channel we saved.
|
* Get the channel we saved.
|
||||||
|
|||||||
@@ -116,18 +116,23 @@ bool RadioLibInterface::receiveDetected(uint16_t irq, ulong syncWordHeaderValidF
|
|||||||
if (detected) {
|
if (detected) {
|
||||||
if (!activeReceiveStart) {
|
if (!activeReceiveStart) {
|
||||||
activeReceiveStart = millis();
|
activeReceiveStart = millis();
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) && !(irq & syncWordHeaderValidFlag)) {
|
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec)) {
|
||||||
|
if (!(irq & syncWordHeaderValidFlag)) {
|
||||||
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
|
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
|
||||||
activeReceiveStart = 0;
|
activeReceiveStart = 0;
|
||||||
LOG_DEBUG("Ignore false preamble detection");
|
LOG_DEBUG("Ignore false preamble detection");
|
||||||
return false;
|
return false;
|
||||||
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
|
} else {
|
||||||
|
uint32_t maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader));
|
||||||
|
if (!Throttle::isWithinTimespanMs(activeReceiveStart, maxPacketTimeMsec)) {
|
||||||
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
|
// We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
|
||||||
activeReceiveStart = 0;
|
activeReceiveStart = 0;
|
||||||
LOG_DEBUG("Ignore false header detection");
|
LOG_DEBUG("Ignore false header detection");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return detected;
|
return detected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,8 +416,6 @@ void RadioLibInterface::completeSending()
|
|||||||
|
|
||||||
void RadioLibInterface::handleReceiveInterrupt()
|
void RadioLibInterface::handleReceiveInterrupt()
|
||||||
{
|
{
|
||||||
uint32_t xmitMsec;
|
|
||||||
|
|
||||||
// when this is called, we should be in receive mode - if we are not, just jump out instead of bombing. Possible Race
|
// when this is called, we should be in receive mode - if we are not, just jump out instead of bombing. Possible Race
|
||||||
// Condition?
|
// Condition?
|
||||||
if (!isReceiving) {
|
if (!isReceiving) {
|
||||||
@@ -425,12 +428,12 @@ void RadioLibInterface::handleReceiveInterrupt()
|
|||||||
// read the number of actually received bytes
|
// read the number of actually received bytes
|
||||||
size_t length = iface->getPacketLength();
|
size_t length = iface->getPacketLength();
|
||||||
|
|
||||||
xmitMsec = getPacketTime(length);
|
uint32_t rxMsec = getPacketTime(length, true);
|
||||||
|
|
||||||
#ifndef DISABLE_WELCOME_UNSET
|
#ifndef DISABLE_WELCOME_UNSET
|
||||||
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||||
LOG_WARN("lora rx disabled: Region unset");
|
LOG_WARN("lora rx disabled: Region unset");
|
||||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
airTime->logAirtime(RX_ALL_LOG, rxMsec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -446,7 +449,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
|||||||
radioBuffer.header.to, radioBuffer.header.from, radioBuffer.header.flags);
|
radioBuffer.header.to, radioBuffer.header.from, radioBuffer.header.flags);
|
||||||
rxBad++;
|
rxBad++;
|
||||||
|
|
||||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
airTime->logAirtime(RX_ALL_LOG, rxMsec);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Skip the 4 headers that are at the beginning of the rxBuf
|
// Skip the 4 headers that are at the beginning of the rxBuf
|
||||||
@@ -456,7 +459,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
|||||||
if (payloadLen < 0) {
|
if (payloadLen < 0) {
|
||||||
LOG_WARN("Ignore received packet too short");
|
LOG_WARN("Ignore received packet too short");
|
||||||
rxBad++;
|
rxBad++;
|
||||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
airTime->logAirtime(RX_ALL_LOG, rxMsec);
|
||||||
} else {
|
} else {
|
||||||
rxGood++;
|
rxGood++;
|
||||||
// altered packet with "from == 0" can do Remote Node Administration without permission
|
// altered packet with "from == 0" can do Remote Node Administration without permission
|
||||||
@@ -494,7 +497,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
|||||||
|
|
||||||
printPacket("Lora RX", mp);
|
printPacket("Lora RX", mp);
|
||||||
|
|
||||||
airTime->logAirtime(RX_LOG, xmitMsec);
|
airTime->logAirtime(RX_LOG, rxMsec);
|
||||||
|
|
||||||
deliverToReceiver(mp);
|
deliverToReceiver(mp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,17 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
|||||||
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ModemType_t modemType = RADIOLIB_MODEM_LORA;
|
||||||
|
DataRate_t getDataRate() const { return {.lora = {.spreadingFactor = sf, .bandwidth = bw, .codingRate = cr}}; }
|
||||||
|
PacketConfig_t getPacketConfig() const
|
||||||
|
{
|
||||||
|
return {.lora = {.preambleLength = preambleLength,
|
||||||
|
.implicitHeader = false,
|
||||||
|
.crcEnabled = true,
|
||||||
|
// We use auto LDRO, meaning it is enabled if the symbol time is >= 16msec
|
||||||
|
.ldrOptimize = (1 << sf) / bw >= 16}};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old
|
* We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old
|
||||||
* loads 0x14) Note: do not use 0x34 - that is reserved for lorawan
|
* loads 0x14) Note: do not use 0x34 - that is reserved for lorawan
|
||||||
@@ -209,6 +220,36 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
|||||||
*/
|
*/
|
||||||
virtual void setStandby();
|
virtual void setStandby();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive packet time either for a received (using header info) or a transmitted packet
|
||||||
|
*/
|
||||||
|
template <typename T> uint32_t computePacketTime(T &lora, uint32_t pl, bool received)
|
||||||
|
{
|
||||||
|
if (received) {
|
||||||
|
// First get the actual coding rate and CRC status from the received packet
|
||||||
|
uint8_t rxCR;
|
||||||
|
bool hasCRC;
|
||||||
|
lora.getLoRaRxHeaderInfo(&rxCR, &hasCRC);
|
||||||
|
// Go from raw header value to denominator
|
||||||
|
if (rxCR < 5) {
|
||||||
|
rxCR += 4;
|
||||||
|
} else if (rxCR == 7) {
|
||||||
|
rxCR = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Received packet configuration must be the same as configured, except for coding rate and CRC
|
||||||
|
DataRate_t dr = getDataRate();
|
||||||
|
dr.lora.codingRate = rxCR;
|
||||||
|
|
||||||
|
PacketConfig_t pc = getPacketConfig();
|
||||||
|
pc.lora.crcEnabled = hasCRC;
|
||||||
|
|
||||||
|
return lora.calculateTimeOnAir(modemType, dr, pc, pl) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lora.getTimeOnAir(pl) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
const char *radioLibErr = "RadioLib err=";
|
const char *radioLibErr = "RadioLib err=";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
|||||||
If we don't add this, we will likely retransmit too early.
|
If we don't add this, we will likely retransmit too early.
|
||||||
*/
|
*/
|
||||||
for (auto i = pending.begin(); i != pending.end(); i++) {
|
for (auto i = pending.begin(); i != pending.end(); i++) {
|
||||||
i->second.nextTxMsec += iface->getPacketTime(p);
|
i->second.nextTxMsec += iface->getPacketTime(p, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isBroadcast(p->to) ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p);
|
return isBroadcast(p->to) ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p);
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ template <class T> class SX126xInterface : public RadioLibInterface
|
|||||||
|
|
||||||
virtual void setStandby() override;
|
virtual void setStandby() override;
|
||||||
|
|
||||||
|
uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Some boards require GPIO control of tx vs rx paths */
|
/** Some boards require GPIO control of tx vs rx paths */
|
||||||
void setTransmitEnable(bool txon);
|
void setTransmitEnable(bool txon);
|
||||||
|
|||||||
@@ -67,4 +67,6 @@ template <class T> class SX128xInterface : public RadioLibInterface
|
|||||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
|
||||||
|
|
||||||
virtual void setStandby() override;
|
virtual void setStandby() override;
|
||||||
|
|
||||||
|
uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ void SimRadio::onNotify(uint32_t notification)
|
|||||||
assert(txp);
|
assert(txp);
|
||||||
startSend(txp);
|
startSend(txp);
|
||||||
// Packet has been sent, count it toward our TX airtime utilization.
|
// Packet has been sent, count it toward our TX airtime utilization.
|
||||||
uint32_t xmitMsec = getPacketTime(txp);
|
uint32_t xmitMsec = RadioInterface::getPacketTime(txp);
|
||||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||||
|
|
||||||
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
|
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
|
||||||
@@ -252,7 +252,7 @@ void SimRadio::startReceive(meshtastic_MeshPacket *p)
|
|||||||
if (isActivelyReceiving()) {
|
if (isActivelyReceiving()) {
|
||||||
LOG_WARN("Collision detected, dropping current and previous packet!");
|
LOG_WARN("Collision detected, dropping current and previous packet!");
|
||||||
rxBad++;
|
rxBad++;
|
||||||
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket));
|
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true));
|
||||||
packetPool.release(receivingPacket);
|
packetPool.release(receivingPacket);
|
||||||
receivingPacket = nullptr;
|
receivingPacket = nullptr;
|
||||||
return;
|
return;
|
||||||
@@ -270,7 +270,7 @@ void SimRadio::startReceive(meshtastic_MeshPacket *p)
|
|||||||
}
|
}
|
||||||
isReceiving = true;
|
isReceiving = true;
|
||||||
receivingPacket = packetPool.allocCopy(*p);
|
receivingPacket = packetPool.allocCopy(*p);
|
||||||
uint32_t airtimeMsec = getPacketTime(p);
|
uint32_t airtimeMsec = getPacketTime(p, true);
|
||||||
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
|
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
|
||||||
#else
|
#else
|
||||||
isReceiving = true;
|
isReceiving = true;
|
||||||
@@ -311,7 +311,7 @@ void SimRadio::handleReceiveInterrupt()
|
|||||||
|
|
||||||
printPacket("Lora RX", mp);
|
printPacket("Lora RX", mp);
|
||||||
|
|
||||||
airTime->logAirtime(RX_LOG, getPacketTime(mp));
|
airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true));
|
||||||
|
|
||||||
deliverToReceiver(mp);
|
deliverToReceiver(mp);
|
||||||
}
|
}
|
||||||
@@ -333,3 +333,28 @@ int16_t SimRadio::readData(uint8_t *data, size_t len)
|
|||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 SimRadio::getPacketTime(uint32_t pl, bool received)
|
||||||
|
{
|
||||||
|
float bandwidthHz = bw * 1000.0f;
|
||||||
|
bool headDisable = false; // we currently always use the header
|
||||||
|
float tSym = (1 << sf) / bandwidthHz;
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
return msecs;
|
||||||
|
}
|
||||||
@@ -88,6 +88,8 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr
|
|||||||
/**
|
/**
|
||||||
* If a send was in progress finish it and return the buffer to the pool */
|
* If a send was in progress finish it and return the buffer to the pool */
|
||||||
void completeSending();
|
void completeSending();
|
||||||
|
|
||||||
|
virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SimRadio *simRadio;
|
extern SimRadio *simRadio;
|
||||||
Reference in New Issue
Block a user