mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-22 02:32:23 +00:00
Fix #11
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "RadioLibInterface.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "OSTimer.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <NodeDB.h> // FIXME, this class shouldn't need to look into nodedb
|
||||
#include <configuration.h>
|
||||
@@ -89,14 +90,17 @@ bool RadioLibInterface::canSendImmediately()
|
||||
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
||||
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
|
||||
// we almost certainly guarantee no one outside will like the packet we are sending.
|
||||
PendingISR isPending = pending;
|
||||
bool busyTx = sendingPacket != NULL;
|
||||
bool busyRx = isReceiving && isActivelyReceiving();
|
||||
|
||||
if (busyTx || busyRx || isPending)
|
||||
DEBUG_MSG("Can not send yet, busyTx=%d, busyRx=%d, intPend=%d\n", busyTx, busyRx, isPending);
|
||||
|
||||
return !busyTx && !busyRx && !isPending;
|
||||
if (busyTx || busyRx) {
|
||||
if (busyTx)
|
||||
DEBUG_MSG("Can not send yet, busyTx\n");
|
||||
if (busyRx)
|
||||
DEBUG_MSG("Can not send yet, busyRx\n");
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Send a packet (possibly by enquing in a private fifo). This routine will
|
||||
@@ -104,8 +108,8 @@ bool RadioLibInterface::canSendImmediately()
|
||||
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
||||
ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("enqueuing for send on mesh fr=0x%x,to=0x%x,id=%d\n (txGood=%d,rxGood=%d,rxBad=%d)\n", p->from, p->to, p->id,
|
||||
txGood, rxGood, rxBad);
|
||||
DEBUG_MSG("enqueuing for send on mesh fr=0x%x,to=0x%x,id=%d (txGood=%d,rxGood=%d,rxBad=%d)\n", p->from, p->to, p->id, txGood,
|
||||
rxGood, rxBad);
|
||||
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
@@ -113,7 +117,9 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
return res;
|
||||
}
|
||||
|
||||
startTransmitTimer(false); // We want all sending/receiving to be done by our daemon thread
|
||||
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
|
||||
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
|
||||
startTransmitTimer(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -127,6 +133,19 @@ bool RadioLibInterface::canSleep()
|
||||
return res;
|
||||
}
|
||||
|
||||
/** 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
|
||||
|
||||
/** radio helper thread callback.
|
||||
|
||||
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
|
||||
@@ -138,7 +157,7 @@ and then they will wait until that packet finishes.
|
||||
NOTE: the large flood rebroadcast delay might still be needed even with this approach. Because we might not be able to hear other
|
||||
transmitters that we are potentially stomping on. Requires further thought.
|
||||
|
||||
FIXME, the 50ms and 200ms values should be tuned via logic analyzer later.
|
||||
FIXME, the MIN_TX_WAIT_MSEC and MAX_TX_WAIT_MSEC values should be tuned via logic analyzer later.
|
||||
*/
|
||||
void RadioLibInterface::loop()
|
||||
{
|
||||
@@ -162,8 +181,6 @@ void RadioLibInterface::loop()
|
||||
if (!canSendImmediately()) {
|
||||
startTransmitTimer(); // try again in a little while
|
||||
} else {
|
||||
DEBUG_MSG("Transmit timer completed!\n");
|
||||
|
||||
// Send any outgoing packets we have ready
|
||||
MeshPacket *txp = txQueue.dequeuePtr(0);
|
||||
assert(txp);
|
||||
@@ -176,9 +193,11 @@ void RadioLibInterface::loop()
|
||||
}
|
||||
}
|
||||
|
||||
#include "OSTimer.h"
|
||||
#ifndef NO_ESP32
|
||||
#define USE_HW_TIMER
|
||||
#endif
|
||||
|
||||
void RadioLibInterface::timerCallback(void *p1, uint32_t p2)
|
||||
void IRAM_ATTR RadioLibInterface::timerCallback(void *p1, uint32_t p2)
|
||||
{
|
||||
RadioLibInterface *t = (RadioLibInterface *)p1;
|
||||
|
||||
@@ -186,7 +205,17 @@ void RadioLibInterface::timerCallback(void *p1, uint32_t p2)
|
||||
|
||||
// We use without overwrite, so that if there is already an interrupt pending to be handled, that gets handle properly (the
|
||||
// ISR handler will restart our timer)
|
||||
#ifndef USE_HW_TIMER
|
||||
t->notify(TRANSMIT_DELAY_COMPLETED, eSetValueWithoutOverwrite);
|
||||
#else
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
instance->notifyFromISR(&xHigherPriorityTaskWoken, TRANSMIT_DELAY_COMPLETED, eSetValueWithoutOverwrite);
|
||||
|
||||
/* Force a context switch if xHigherPriorityTaskWoken is now set to pdTRUE.
|
||||
The macro used to do this is dependent on the port and may be called
|
||||
portEND_SWITCHING_ISR. */
|
||||
YIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||
@@ -194,8 +223,15 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!timerRunning && !txQueue.isEmpty()) {
|
||||
timerRunning = true;
|
||||
uint32_t delay = withDelay ? 0 : random(50, 200); // See documentation for loop() wrt these values
|
||||
scheduleCallback(timerCallback, this, 0, delay);
|
||||
uint32_t delay =
|
||||
!withDelay ? 0 : random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC); // See documentation for loop() wrt these values
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
#ifdef USE_HW_TIMER
|
||||
bool okay = scheduleHWCallback(timerCallback, this, 0, delay);
|
||||
#else
|
||||
bool okay = scheduleOSCallback(timerCallback, this, 0, delay);
|
||||
#endif
|
||||
assert(okay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +281,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
const PacketHeader *h = (PacketHeader *)radiobuf;
|
||||
uint8_t ourAddr = nodeDB.getNodeNum();
|
||||
|
||||
rxGood++;
|
||||
if (h->to != 255 && h->to != ourAddr) {
|
||||
DEBUG_MSG("ignoring packet not sent to us\n");
|
||||
} else {
|
||||
@@ -264,7 +301,6 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
} else {
|
||||
// parsing was successful, queue for our recipient
|
||||
mp->has_payload = true;
|
||||
rxGood++;
|
||||
DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id);
|
||||
|
||||
deliverToReceiver(mp);
|
||||
@@ -277,6 +313,9 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
/** start an immediate transmit */
|
||||
void RadioLibInterface::startSend(MeshPacket *txp)
|
||||
{
|
||||
DEBUG_MSG("Starting low level send from=0x%x, id=%u!\n", txp->from, txp->id);
|
||||
setStandby(); // Cancel any already in process receives
|
||||
|
||||
size_t numbytes = beginSending(txp);
|
||||
|
||||
int res = iface->startTransmit(radiobuf, numbytes);
|
||||
|
||||
Reference in New Issue
Block a user