From 9dd88281afb4bd7da721ee72b03fe5ba4fdf7d32 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 21 May 2020 16:34:16 -0700 Subject: [PATCH] reliable broadcast now works --- src/mesh/MeshService.cpp | 2 +- src/mesh/ReliableRouter.cpp | 11 ++++-- src/mesh/ReliableRouter.h | 2 +- src/mesh/Router.cpp | 68 ++++++++++++++++++++----------------- src/mesh/Router.h | 13 ++++--- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index ee2905ad4a..540ca7cb13 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -247,7 +247,7 @@ void MeshService::sendToMesh(MeshPacket *p) } // Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it - if (router.send(p) != ERRNO_OK) { + if (router.sendLocal(p) != ERRNO_OK) { DEBUG_MSG("No radio was able to send packet, discarding...\n"); releaseToPool(p); } diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 78c6b93a0c..0500f27991 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -12,6 +12,11 @@ ErrorCode ReliableRouter::send(MeshPacket *p) { if (p->want_ack) { + // If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our + // message will rebroadcast + if (p->to == NODENUM_BROADCAST && p->hop_limit == 0) + p->hop_limit = 1; + auto copy = packetPool.allocCopy(*p); startRetransmission(copy); } @@ -42,7 +47,7 @@ void ReliableRouter::handleReceived(MeshPacket *p) // If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for // the original sending process. if (stopRetransmission(p->from, p->id)) { - DEBUG_MSG("Someone is retransmitting for us, generate implicit ack"); + DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); sendAckNak(true, p->from, p->id); } } else if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (for now) @@ -79,10 +84,10 @@ void ReliableRouter::handleReceived(MeshPacket *p) */ void ReliableRouter::sendAckNak(bool isAck, NodeNum to, PacketId idFrom) { - DEBUG_MSG("Sending an ack=%d,to=%d,idFrom=%d\n", isAck, to, idFrom); auto p = allocForSending(); p->hop_limit = 0; // Assume just immediate neighbors for now p->to = to; + DEBUG_MSG("Sending an ack=0x%x,to=0x%x,idFrom=%d,id=%d\n", isAck, to, idFrom, p->id); if (isAck) { p->decoded.ack.success_id = idFrom; @@ -92,7 +97,7 @@ void ReliableRouter::sendAckNak(bool isAck, NodeNum to, PacketId idFrom) p->decoded.which_ack = SubPacket_fail_id_tag; } - send(p); + sendLocal(p); // we sometimes send directly to the local node } #define NUM_RETRANSMISSIONS 3 diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index e63806af55..7030793aec 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -48,7 +48,7 @@ struct PendingPacket { PendingPacket() {} PendingPacket(MeshPacket *p); - void setNextTx() { nextTxMsec = millis() + random(30 * 1000, 22 * 1000); } + void setNextTx() { nextTxMsec = millis() + random(20 * 1000, 22 * 1000); } }; class GlobalPacketIdHashFunction diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 428f19fee0..0ef7b8333f 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -77,6 +77,16 @@ MeshPacket *Router::allocForSending() return p; } +ErrorCode Router::sendLocal(MeshPacket *p) +{ + if (p->to == nodeDB.getNodeNum()) { + DEBUG_MSG("Enqueuing internal message for the receive queue\n"); + fromRadioQueue.enqueue(p); + return ERRNO_OK; + } else + return send(p); +} + /** * Send a packet on a suitable interface. This routine will * later free() the packet to pool. This routine is not allowed to stall. @@ -84,44 +94,39 @@ MeshPacket *Router::allocForSending() */ ErrorCode Router::send(MeshPacket *p) { - // If this packet was destined only to apps on our node, don't send it out into the network - if (p->to == nodeDB.getNodeNum()) { - DEBUG_MSG("Dropping locally processed message\n"); - packetPool.release(p); - return ERRNO_OK; - } else { - // Never set the want_ack flag on broadcast packets sent over the air. - if (p->to == NODENUM_BROADCAST) - p->want_ack = false; + assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal - // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) + // Never set the want_ack flag on broadcast packets sent over the air. + if (p->to == NODENUM_BROADCAST) + p->want_ack = false; - assert(p->which_payload == MeshPacket_encrypted_tag || - p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now + // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) - // First convert from protobufs to raw bytes - if (p->which_payload == MeshPacket_decoded_tag) { - static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union + assert(p->which_payload == MeshPacket_encrypted_tag || + p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now - size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded); + // First convert from protobufs to raw bytes + if (p->which_payload == MeshPacket_decoded_tag) { + static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union - assert(numbytes <= MAX_RHPACKETLEN); - crypto->encrypt(p->from, p->id, numbytes, bytes); + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded); - // Copy back into the packet and set the variant type - memcpy(p->encrypted.bytes, bytes, numbytes); - p->encrypted.size = numbytes; - p->which_payload = MeshPacket_encrypted_tag; - } + assert(numbytes <= MAX_RHPACKETLEN); + crypto->encrypt(p->from, p->id, numbytes, bytes); - if (iface) { - // DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - return iface->send(p); - } else { - DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - packetPool.release(p); - return ERRNO_NO_INTERFACES; - } + // Copy back into the packet and set the variant type + memcpy(p->encrypted.bytes, bytes, numbytes); + p->encrypted.size = numbytes; + p->which_payload = MeshPacket_encrypted_tag; + } + + if (iface) { + // DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); + return iface->send(p); + } else { + DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); + packetPool.release(p); + return ERRNO_NO_INTERFACES; } } @@ -132,7 +137,6 @@ ErrorCode Router::send(MeshPacket *p) void Router::sniffReceived(const MeshPacket *p) { DEBUG_MSG("FIXME-update-db Sniffing packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - } bool Router::perhapsDecode(MeshPacket *p) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 0f06ce3e9e..8c811667e0 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -47,11 +47,9 @@ class Router virtual void loop(); /** - * Send a packet on a suitable interface. This routine will - * later free() the packet to pool. This routine is not allowed to stall. - * If the txmit queue is full it might return an error + * Works like send, but if we are sending to the local node, we directly put the message in the receive queue */ - virtual ErrorCode send(MeshPacket *p); + ErrorCode sendLocal(MeshPacket *p); /// Allocate and return a meshpacket which defaults as send to broadcast from the current node. MeshPacket *allocForSending(); @@ -61,6 +59,13 @@ class Router NodeNum getNodeNum(); protected: + /** + * Send a packet on a suitable interface. This routine will + * later free() the packet to pool. This routine is not allowed to stall. + * If the txmit queue is full it might return an error + */ + virtual ErrorCode send(MeshPacket *p); + /** * Called from loop() * Handle any packet that is received by an interface on this node.