Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/mesh/LR11x0Interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,7 @@ template <class T> class LR11x0Interface : public RadioLibInterface
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;

virtual void setStandby() override;

uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); }
};
#endif
4 changes: 3 additions & 1 deletion src/mesh/RF95Interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ class RF95Interface : public RadioLibInterface
*/
virtual void configHardwareForSend() override;

uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(*lora, pl, received); }

private:
/** Some boards require GPIO control of tx vs rx paths */
void setTransmitEnable(bool txon);
};
#endif
#endif
35 changes: 4 additions & 31 deletions src/mesh/RadioInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/

/**
* 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 RadioInterface::getPacketTime(const meshtastic_MeshPacket *p, bool received)
{
uint32_t pl = 0;
if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) {
Expand All @@ -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);
pl = numbytes + sizeof(PacketHeader);
}
return getPacketTime(pl);
return getPacketTime(pl, received);
}

/** The delay to use for retransmitting dropped packets */
Expand Down Expand Up @@ -624,8 +598,7 @@ void RadioInterface::applyModemConfig()
saveFreq(freq + loraConfig.frequency_offset);

slotTimeMsec = computeSlotTimeMsec();
preambleTimeMsec = getPacketTime((uint32_t)0);
maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader));
preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw);

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,
Expand All @@ -635,7 +608,7 @@ void RadioInterface::applyModemConfig()
LOG_INFO("numChannels: %d x %.3fkHz", numChannels, bw);
LOG_INFO("channel_num: %d", channel_num + 1);
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:
Expand Down
9 changes: 4 additions & 5 deletions src/mesh/RadioInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,8 @@ class RadioInterface
const uint8_t NUM_SYM_CAD = 2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48
const uint8_t NUM_SYM_CAD_24GHZ = 4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280
uint32_t slotTimeMsec = computeSlotTimeMsec();
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 maxPacketTimeMsec = 3246; // calculated on startup, this is the default for LongFast
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
const uint32_t PROCESSING_TIME_MSEC =
4500; // time to construct, process and construct a packet again (empirically determined)
const uint8_t CWmin = 3; // minimum CWsize
Expand Down Expand Up @@ -202,8 +201,8 @@ class RadioInterface
*
* @return num msecs for the packet
*/
uint32_t getPacketTime(const meshtastic_MeshPacket *p);
uint32_t getPacketTime(uint32_t totalPacketLen);
uint32_t getPacketTime(const meshtastic_MeshPacket *p, bool received = false);
virtual uint32_t getPacketTime(uint32_t totalPacketLen, bool received = false) = 0;

/**
* Get the channel we saved.
Expand Down
37 changes: 20 additions & 17 deletions src/mesh/RadioLibInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,21 @@ bool RadioLibInterface::receiveDetected(uint16_t irq, ulong syncWordHeaderValidF
if (detected) {
if (!activeReceiveStart) {
activeReceiveStart = millis();
} else if (!Throttle::isWithinTimespanMs(activeReceiveStart, 2 * preambleTimeMsec) && !(irq & syncWordHeaderValidFlag)) {
// The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection");
return false;
} else 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
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection");
return false;
} 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
activeReceiveStart = 0;
LOG_DEBUG("Ignore false preamble detection");
return false;
} 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
activeReceiveStart = 0;
LOG_DEBUG("Ignore false header detection");
return false;
}
}
}
}
return detected;
Expand Down Expand Up @@ -411,8 +416,6 @@ void RadioLibInterface::completeSending()

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
// Condition?
if (!isReceiving) {
Expand All @@ -425,12 +428,12 @@ void RadioLibInterface::handleReceiveInterrupt()
// read the number of actually received bytes
size_t length = iface->getPacketLength();

xmitMsec = getPacketTime(length);
uint32_t rxMsec = getPacketTime(length, true);

#ifndef DISABLE_WELCOME_UNSET
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
LOG_WARN("lora rx disabled: Region unset");
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
airTime->logAirtime(RX_ALL_LOG, rxMsec);
return;
}
#endif
Expand All @@ -446,7 +449,7 @@ void RadioLibInterface::handleReceiveInterrupt()
radioBuffer.header.to, radioBuffer.header.from, radioBuffer.header.flags);
rxBad++;

airTime->logAirtime(RX_ALL_LOG, xmitMsec);
airTime->logAirtime(RX_ALL_LOG, rxMsec);

} else {
// Skip the 4 headers that are at the beginning of the rxBuf
Expand All @@ -456,7 +459,7 @@ void RadioLibInterface::handleReceiveInterrupt()
if (payloadLen < 0) {
LOG_WARN("Ignore received packet too short");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
airTime->logAirtime(RX_ALL_LOG, rxMsec);
} else {
rxGood++;
// altered packet with "from == 0" can do Remote Node Administration without permission
Expand Down Expand Up @@ -494,7 +497,7 @@ void RadioLibInterface::handleReceiveInterrupt()

printPacket("Lora RX", mp);

airTime->logAirtime(RX_LOG, xmitMsec);
airTime->logAirtime(RX_LOG, rxMsec);

deliverToReceiver(mp);
}
Expand Down
41 changes: 41 additions & 0 deletions src/mesh/RadioLibInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);

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
* loads 0x14) Note: do not use 0x34 - that is reserved for lorawan
Expand Down Expand Up @@ -209,6 +220,36 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/
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=";

/**
Expand Down
2 changes: 1 addition & 1 deletion src/mesh/ReliableRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
If we don't add this, we will likely retransmit too early.
*/
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);
Expand Down
2 changes: 2 additions & 0 deletions src/mesh/SX126xInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ template <class T> class SX126xInterface : public RadioLibInterface

virtual void setStandby() override;

uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); }

private:
/** Some boards require GPIO control of tx vs rx paths */
void setTransmitEnable(bool txon);
Expand Down
2 changes: 2 additions & 0 deletions src/mesh/SX128xInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ template <class T> class SX128xInterface : public RadioLibInterface
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;

virtual void setStandby() override;

uint32_t getPacketTime(uint32_t pl, bool received) override { return computePacketTime(lora, pl, received); }
};
33 changes: 29 additions & 4 deletions src/platform/portduino/SimRadio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void SimRadio::onNotify(uint32_t notification)
assert(txp);
startSend(txp);
// 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);

notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
Expand Down Expand Up @@ -252,7 +252,7 @@ void SimRadio::startReceive(meshtastic_MeshPacket *p)
if (isActivelyReceiving()) {
LOG_WARN("Collision detected, dropping current and previous packet!");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket));
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true));
packetPool.release(receivingPacket);
receivingPacket = nullptr;
return;
Expand All @@ -270,7 +270,7 @@ void SimRadio::startReceive(meshtastic_MeshPacket *p)
}
isReceiving = true;
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
#else
isReceiving = true;
Expand Down Expand Up @@ -311,7 +311,7 @@ void SimRadio::handleReceiveInterrupt()

printPacket("Lora RX", mp);

airTime->logAirtime(RX_LOG, getPacketTime(mp));
airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true));

deliverToReceiver(mp);
}
Expand All @@ -332,4 +332,29 @@ int16_t SimRadio::readData(uint8_t *data, size_t len)
}

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;
}
2 changes: 2 additions & 0 deletions src/platform/portduino/SimRadio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
void completeSending();

virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override;
};

extern SimRadio *simRadio;
Loading