@@ -235,12 +235,12 @@ void RadioLibInterface::onNotify(uint32_t notification)
235
235
case ISR_TX:
236
236
handleTransmitInterrupt ();
237
237
startReceive ();
238
- startTransmitTimer ();
238
+ setTransmitDelay ();
239
239
break ;
240
240
case ISR_RX:
241
241
handleReceiveInterrupt ();
242
242
startReceive ();
243
- startTransmitTimer ();
243
+ setTransmitDelay ();
244
244
break ;
245
245
case TRANSMIT_DELAY_COMPLETED:
246
246
@@ -250,23 +250,32 @@ void RadioLibInterface::onNotify(uint32_t notification)
250
250
if (!canSendImmediately ()) {
251
251
setTransmitDelay (); // currently Rx/Tx-ing: reset random delay
252
252
} else {
253
- if (isChannelActive ()) { // check if there is currently a LoRa packet on the channel
254
- startReceive (); // try receiving this packet, afterwards we'll be trying to transmit again
255
- setTransmitDelay ();
253
+ meshtastic_MeshPacket *txp = txQueue.getFront ();
254
+ assert (txp);
255
+ long delay_remaining = txp->tx_after ? txp->tx_after - millis () : 0 ;
256
+ if (delay_remaining > 0 ) {
257
+ // There's still some delay pending on this packet, so resume waiting for it to elapse
258
+ notifyLater (delay_remaining, TRANSMIT_DELAY_COMPLETED, false );
256
259
} else {
257
- // Send any outgoing packets we have ready as fast as possible to keep the time between channel scan and
258
- // actual transmission as short as possible
259
- meshtastic_MeshPacket *txp = txQueue.dequeue ();
260
- assert (txp);
261
- bool sent = startSend (txp);
262
- if (sent) {
263
- // Packet has been sent, count it toward our TX airtime utilization.
264
- uint32_t xmitMsec = getPacketTime (txp);
265
- airTime->logAirtime (TX_LOG, xmitMsec);
260
+ if (isChannelActive ()) { // check if there is currently a LoRa packet on the channel
261
+ startReceive (); // try receiving this packet, afterwards we'll be trying to transmit again
262
+ setTransmitDelay ();
263
+ } else {
264
+ // Send any outgoing packets we have ready as fast as possible to keep the time between channel scan and
265
+ // actual transmission as short as possible
266
+ txp = txQueue.dequeue ();
267
+ assert (txp);
268
+ bool sent = startSend (txp);
269
+ if (sent) {
270
+ // Packet has been sent, count it toward our TX airtime utilization.
271
+ uint32_t xmitMsec = getPacketTime (txp);
272
+ airTime->logAirtime (TX_LOG, xmitMsec);
273
+ }
266
274
}
267
275
}
268
276
}
269
277
} else {
278
+ // Do nothing, because the queue is empty
270
279
}
271
280
break ;
272
281
default :
@@ -277,15 +286,24 @@ void RadioLibInterface::onNotify(uint32_t notification)
277
286
void RadioLibInterface::setTransmitDelay ()
278
287
{
279
288
meshtastic_MeshPacket *p = txQueue.getFront ();
289
+ if (!p) {
290
+ return ; // noop if there's nothing in the queue
291
+ }
292
+
280
293
// We want all sending/receiving to be done by our daemon thread.
281
294
// We use a delay here because this packet might have been sent in response to a packet we just received.
282
295
// So we want to make sure the other side has had a chance to reconfigure its radio.
283
296
284
- /* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
285
- * This assumption is valid because of the offset generated by the radio to account for the noise
286
- * floor.
287
- */
288
- if (p->rx_snr == 0 && p->rx_rssi == 0 ) {
297
+ if (p->tx_after ) {
298
+ unsigned long add_delay = p->rx_rssi ? getTxDelayMsecWeighted (p->rx_snr ) : getTxDelayMsec ();
299
+ unsigned long now = millis ();
300
+ p->tx_after = max (p->tx_after + add_delay, now + add_delay);
301
+ notifyLater (now - p->tx_after , TRANSMIT_DELAY_COMPLETED, false );
302
+ } else if (p->rx_snr == 0 && p->rx_rssi == 0 ) {
303
+ /* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
304
+ * This assumption is valid because of the offset generated by the radio to account for the noise
305
+ * floor.
306
+ */
289
307
startTransmitTimer (true );
290
308
} else {
291
309
// If there is a SNR, start a timer scaled based on that SNR.
@@ -312,6 +330,20 @@ void RadioLibInterface::startTransmitTimerSNR(float snr)
312
330
}
313
331
}
314
332
333
+ /* *
334
+ * If the packet is not already in the late rebroadcast window, move it there
335
+ */
336
+ void RadioLibInterface::clampToLateRebroadcastWindow (NodeNum from, PacketId id)
337
+ {
338
+ // Look for non-late packets only, so we don't do this twice!
339
+ meshtastic_MeshPacket *p = txQueue.remove (from, id, true , false );
340
+ if (p) {
341
+ p->tx_after = millis () + getTxDelayMsecWeightedWorst (p->rx_snr );
342
+ txQueue.enqueue (p);
343
+ LOG_DEBUG (" Move existing queued packet to the late rebroadcast window %dms from now" , p->tx_after - millis ());
344
+ }
345
+ }
346
+
315
347
void RadioLibInterface::handleTransmitInterrupt ()
316
348
{
317
349
// This can be null if we forced the device to enter standby mode. In that case
0 commit comments