sforkowany z mirror/meshtastic-firmware
bug #503 wip
rodzic
c2e8ac7173
commit
68937d52fe
|
@ -53,6 +53,59 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
|
||||||
// 1kb was too small
|
// 1kb was too small
|
||||||
#define RADIO_STACK_SIZE 4096
|
#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
|
||||||
|
* section 4
|
||||||
|
*
|
||||||
|
* @return num msecs for the packet
|
||||||
|
*/
|
||||||
|
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
float numPayloadSym =
|
||||||
|
8 + max(ceilf(((8 * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * (cr + 4)), 0.0f);
|
||||||
|
float tPayload = numPayloadSym * tSym;
|
||||||
|
float tPacket = tPreamble + tPayload;
|
||||||
|
|
||||||
|
uint32_t msecs = tPacket / 1000;
|
||||||
|
return msecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The delay to use for retransmitting dropped packets */
|
||||||
|
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||||
|
{
|
||||||
|
return random(20 * 1000L, 22 * 1000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
}
|
||||||
|
|
||||||
void printPacket(const char *prefix, const MeshPacket *p)
|
void printPacket(const char *prefix, const MeshPacket *p)
|
||||||
{
|
{
|
||||||
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
|
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
|
||||||
|
|
|
@ -36,7 +36,7 @@ typedef struct {
|
||||||
*
|
*
|
||||||
* This defines the SOLE API for talking to radios (because soon we will have alternate radio implementations)
|
* This defines the SOLE API for talking to radios (because soon we will have alternate radio implementations)
|
||||||
*/
|
*/
|
||||||
class RadioInterface
|
class RadioInterface : public PacketTimes
|
||||||
{
|
{
|
||||||
friend class MeshRadio; // for debugging we let that class touch pool
|
friend class MeshRadio; // for debugging we let that class touch pool
|
||||||
PointerQueue<MeshPacket> *rxDest = NULL;
|
PointerQueue<MeshPacket> *rxDest = NULL;
|
||||||
|
@ -108,6 +108,21 @@ class RadioInterface
|
||||||
/// \return true if initialisation succeeded.
|
/// \return true if initialisation succeeded.
|
||||||
virtual bool reconfigure() = 0;
|
virtual bool reconfigure() = 0;
|
||||||
|
|
||||||
|
/** The delay to use for retransmitting dropped packets */
|
||||||
|
uint32_t getRetransmissionMsec(const MeshPacket *p);
|
||||||
|
|
||||||
|
/** The delay to use when we want to send something but the ether is busy */
|
||||||
|
uint32_t getTxDelayMsec();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 getPacketTime(MeshPacket *p);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int8_t power = 17; // Set by applyModemConfig()
|
int8_t power = 17; // Set by applyModemConfig()
|
||||||
|
|
||||||
|
|
|
@ -158,18 +158,6 @@ bool RadioLibInterface::canSleep()
|
||||||
return res;
|
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.
|
/** radio helper thread callback.
|
||||||
|
|
||||||
|
@ -226,8 +214,7 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||||
{
|
{
|
||||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||||
if (!txQueue.isEmpty()) {
|
if (!txQueue.isEmpty()) {
|
||||||
uint32_t delay =
|
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
|
||||||
!withDelay ? 1 : random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC); // See documentation for loop() wrt these values
|
|
||||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ PendingPacket::PendingPacket(MeshPacket *p)
|
||||||
{
|
{
|
||||||
packet = p;
|
packet = p;
|
||||||
numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send
|
numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send
|
||||||
setNextTx();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key)
|
PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key)
|
||||||
|
@ -151,6 +150,7 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
|
||||||
auto id = GlobalPacketId(p);
|
auto id = GlobalPacketId(p);
|
||||||
auto rec = PendingPacket(p);
|
auto rec = PendingPacket(p);
|
||||||
|
|
||||||
|
setNextTx(&rec);
|
||||||
stopRetransmission(p->from, p->id);
|
stopRetransmission(p->from, p->id);
|
||||||
pending[id] = rec;
|
pending[id] = rec;
|
||||||
|
|
||||||
|
@ -190,10 +190,9 @@ int32_t ReliableRouter::doRetransmissions()
|
||||||
|
|
||||||
// Queue again
|
// Queue again
|
||||||
--p.numRetransmissions;
|
--p.numRetransmissions;
|
||||||
p.setNextTx();
|
setNextTx(&p);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Not yet time
|
// Not yet time
|
||||||
int32_t t = p.nextTxMsec - now;
|
int32_t t = p.nextTxMsec - now;
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,6 @@ struct PendingPacket {
|
||||||
|
|
||||||
PendingPacket() {}
|
PendingPacket() {}
|
||||||
PendingPacket(MeshPacket *p);
|
PendingPacket(MeshPacket *p);
|
||||||
|
|
||||||
void setNextTx() { nextTxMsec = millis() + random(20 * 1000L, 22 * 1000L); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GlobalPacketIdHashFunction
|
class GlobalPacketIdHashFunction
|
||||||
|
@ -130,4 +128,8 @@ class ReliableRouter : public FloodingRouter
|
||||||
* @return the number of msecs until our next retransmission or MAXINT if none scheduled
|
* @return the number of msecs until our next retransmission or MAXINT if none scheduled
|
||||||
*/
|
*/
|
||||||
int32_t doRetransmissions();
|
int32_t doRetransmissions();
|
||||||
|
|
||||||
|
void setNextTx(PendingPacket *pending) {
|
||||||
|
assert(iface);
|
||||||
|
pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,12 +14,13 @@
|
||||||
class Router : protected concurrency::OSThread
|
class Router : protected concurrency::OSThread
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
RadioInterface *iface;
|
|
||||||
|
|
||||||
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
|
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
|
||||||
/// forwarded to the phone.
|
/// forwarded to the phone.
|
||||||
PointerQueue<MeshPacket> fromRadioQueue;
|
PointerQueue<MeshPacket> fromRadioQueue;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RadioInterface *iface = NULL;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Local services that want to see _every_ packet this node receives can observe this.
|
/// Local services that want to see _every_ packet this node receives can observe this.
|
||||||
/// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting
|
/// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting
|
||||||
|
|
Ładowanie…
Reference in New Issue