From 0d6729b9eb84394d3e0b5680fbb5fccc97f5a097 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Mon, 2 Oct 2023 19:31:23 +0200 Subject: [PATCH] Initial version of NextHopRouter --- src/main.cpp | 3 + src/mesh/FloodingRouter.cpp | 2 +- src/mesh/NextHopRouter.cpp | 106 ++++++++++++++++++ src/mesh/NextHopRouter.h | 49 ++++++++ src/mesh/NodeDB.cpp | 10 ++ src/mesh/NodeDB.h | 3 +- src/mesh/RadioInterface.cpp | 4 +- src/mesh/RadioInterface.h | 8 +- src/mesh/RadioLibInterface.cpp | 2 + src/mesh/ReliableRouter.cpp | 26 +++-- src/mesh/ReliableRouter.h | 6 +- src/mesh/Router.cpp | 2 + src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/config.pb.h | 10 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 16 ++- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 26 +++-- src/modules/NeighborInfoModule.cpp | 63 ++++++++++- src/modules/NeighborInfoModule.h | 9 +- src/modules/TraceRouteModule.h | 3 +- 20 files changed, 316 insertions(+), 36 deletions(-) create mode 100644 src/mesh/NextHopRouter.cpp create mode 100644 src/mesh/NextHopRouter.h diff --git a/src/main.cpp b/src/main.cpp index a4caad3fd..d2a91a47b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -561,6 +561,9 @@ void setup() } nodeStatus->observe(&nodeDB.newStatus); + config.lora.next_hop_routing = true; // FIXME - remove this before merging + LOG_INFO("USING NEXT-HOP ROUTING\n"); + service.init(); // Now that the mesh service is created, create any modules diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index d27d47e87..d0061ed8a 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -71,4 +71,4 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } // handle the packet as normal Router::sniffReceived(p, c); -} \ No newline at end of file +} diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp new file mode 100644 index 000000000..9cacda5fc --- /dev/null +++ b/src/mesh/NextHopRouter.cpp @@ -0,0 +1,106 @@ +#include "NextHopRouter.h" + +NextHopRouter::NextHopRouter() {} + +/** + * Send a packet + */ +ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) +{ + // Add any messages _we_ send to the seen message list (so we will ignore all retransmissions we see) + wasSeenRecently(p); // FIXME, move this to a sniffSent method + + p->next_hop = getNextHop(p->to, p->current_relayer); // set the next hop + LOG_DEBUG("Setting next hop for packet with dest %x to %x\n", p->to, p->next_hop); + + return Router::send(p); +} + +bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) +{ + if (wasSeenRecently(p)) { // Note: this will also add a recent packet record + if (p->next_hop == getNodeNum()) { + LOG_DEBUG("Ignoring incoming msg, because we've already seen it.\n"); + } else { + LOG_DEBUG("Ignoring incoming msg, because we've already seen it and cancel any outgoing packets.\n"); + Router::cancelSending(p->from, p->id); + } + return true; + } + + return Router::shouldFilterReceived(p); +} + +void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) +{ + bool isAck = + ((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK + if (isAck) { + // Update next-hop of this successful transmission to current relayer, but ONLY if "from" is not 0 or ourselves (means + // implicit ACK or someone is relaying our ACK) + if (p->from != 0 && p->from != getNodeNum()) { + if (p->current_relayer) { + meshtastic_NodeInfoLite *sentTo = nodeDB.getMeshNode(p->from); + if (sentTo) { + LOG_DEBUG("Update next hop of %x to %x based on received ACK.\n", p->from, p->current_relayer); + sentTo->next_hop = p->current_relayer; + } + } + } + } + + if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { + if ((p->to != getNodeNum()) && (getFrom(p) != getNodeNum())) { + if (p->next_hop == getNodeNum()) { + meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it + LOG_INFO("Relaying received next-hop message coming from %x\n", p->current_relayer); + + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + // If it is a traceRoute request, update the route that it went via me + if (traceRouteModule && traceRouteModule->wantPacket(tosend)) + traceRouteModule->updateRoute(tosend); + // If it is a neighborInfo packet, update last_sent_by_id + if (neighborInfoModule && neighborInfoModule->wantPacket(tosend)) + neighborInfoModule->updateLastSentById(tosend); + } + + tosend->hop_limit--; // bump down the hop count + NextHopRouter::send(tosend); + } else if (p->next_hop == 0) { + // No preference for next hop, use FloodingRouter + LOG_DEBUG("No preference for next hop, using FloodingRouter\n"); + FloodingRouter::sniffReceived(p, c); + } else if (p->to == NODENUM_BROADCAST) { + // TODO how to handle broadcast messages? + LOG_DEBUG("TODO: Broadcast next-hop message\n"); + FloodingRouter::sniffReceived(p, c); + } + } + } else { + LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n"); + } + // handle the packet as normal + Router::sniffReceived(p, c); +} + +/** + * Get the next hop for a destination, given the current relayer + * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) + */ +uint32_t NextHopRouter::getNextHop(NodeNum to, NodeNum current_relayer) +{ + meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(to); + if (node) { + // We are careful not to return the current relayer as the next hop + if (node->next_hop != current_relayer) { + LOG_DEBUG("Next hop for %x is %x\n", to, node->next_hop); + return node->next_hop; + } else { + LOG_WARN("Next hop for %x is %x, which is the same as current relayer; setting as no preference\n", to, + node->next_hop); + return 0; + } + } else { + return 0; + } +} \ No newline at end of file diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h new file mode 100644 index 000000000..2746886f4 --- /dev/null +++ b/src/mesh/NextHopRouter.h @@ -0,0 +1,49 @@ +#pragma once + +#include "FloodingRouter.h" + +/* + Router which only relays if it is the next hop for a packet. + The next hop is set by the current relayer of a packet, which bases this on information from either the NeighborInfoModule, or a + previous successful delivery via flooding. It is only used for DMs and not used for broadcasts. Using the NeighborInfoModule, it + can derive the next hop of neighbors and that of neighbors of neighbors. For others, it has no information in the beginning, + which results into falling back to the FloodingRouter. Upon successful delivery via flooding, it updates the next hop of the + recipient to the node that last relayed the ACK to us. When the ReliableRouter is doing retransmissions, at the last retry, it + will reset the next hop, in order to fall back to the FloodingRouter. +*/ +class NextHopRouter : public FloodingRouter +{ + public: + /** + * Constructor + * + */ + NextHopRouter(); + + /** + * Send a packet + * @return an error code + */ + virtual ErrorCode send(meshtastic_MeshPacket *p) override; + + protected: + /** + * Should this incoming filter be dropped? + * + * Called immediately on reception, before any further processing. + * @return true to abandon the packet + */ + virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override; + + /** + * Look for packets we need to relay + */ + virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; + + private: + /** + * Get the next hop for a destination, given the current relayer + * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) + */ + uint32_t getNextHop(NodeNum to, NodeNum current_relayer); +}; \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d7fd84fb7..cfa42c4d9 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -814,6 +814,16 @@ meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n) return NULL; } +// Find a node in the database that matches the last byte, return 0 if not found +NodeNum NodeDB::findMatchingNodeNum(uint8_t last_byte) +{ + for (int i = 0; i < *numMeshNodes; i++) + if ((uint8_t)(meshNodes[i].num & 0xFF) == last_byte) + return meshNodes[i].num; + + return 0; +} + /// Find a node in our DB, create an empty NodeInfo if missing meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) { diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index f906acd58..52523b7a6 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -129,6 +129,7 @@ class NodeDB } meshtastic_NodeInfoLite *getMeshNode(NodeNum n); + NodeNum findMatchingNodeNum(uint8_t last_byte); size_t getNumMeshNodes() { return *numMeshNodes; } private: @@ -242,4 +243,4 @@ extern uint32_t error_address; #define Module_Config_size \ (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \ ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \ - ModuleConfig_TelemetryConfig_size + ModuleConfig_size) + ModuleConfig_TelemetryConfig_size + ModuleConfig_size) \ No newline at end of file diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 0d2238396..3f8fadd2a 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -538,6 +538,8 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) p->hop_limit = HOP_RELIABLE; } h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0); + h->next_hop = (p->next_hop & 0xFF); // set last byte of next_hop + h->current_relayer = (p->current_relayer & 0xFF); // set last byte of current_relayer // if the sender nodenum is zero, that means uninitialized assert(h->from); @@ -546,4 +548,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} +} \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 9c5d66293..450d60709 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -31,6 +31,12 @@ typedef struct { /** The channel hash - used as a hint for the decoder to limit which channels we consider */ uint8_t channel; + + // Last byte of the NodeNum of the next-hop for this packet + uint8_t next_hop; + + // Last byte of the NodeNum of the current relayer of this packet + uint8_t current_relayer; } PacketHeader; /** @@ -223,4 +229,4 @@ class RadioInterface }; /// Debug printing for packets -void printPacket(const char *prefix, const meshtastic_MeshPacket *p); +void printPacket(const char *prefix, const meshtastic_MeshPacket *p); \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 4f0c52e67..fedc475ad 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -362,6 +362,8 @@ void RadioLibInterface::handleReceiveInterrupt() assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK; mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK); + mp->next_hop = nodeDB.findMatchingNodeNum(h->next_hop); + mp->current_relayer = nodeDB.findMatchingNodeNum(h->current_relayer); addReceiveMetadata(mp); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 946a669cc..d4310b873 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -33,7 +33,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) } } - return FloodingRouter::send(p); + return config.lora.next_hop_routing ? NextHopRouter::send(p) : FloodingRouter::send(p); } bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) @@ -71,11 +71,11 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) i->second.nextTxMsec += iface->getPacketTime(p); } - /* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE) + /* Resend implicit ACKs for repeated packets (current relayer is the same as original transmitter) * this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again. * Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and * flooding this ACK back to the original sender already adds redundancy. */ - if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) { + if (wasSeenRecently(p, false) && p->current_relayer == p->from && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) { // retransmission on broadcast has hop_limit still equal to HOP_RELIABLE LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n"); meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); @@ -83,7 +83,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) Router::send(tosend); } - return FloodingRouter::shouldFilterReceived(p); + return config.lora.next_hop_routing ? NextHopRouter::shouldFilterReceived(p) : FloodingRouter::shouldFilterReceived(p); } /** @@ -133,7 +133,7 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } // handle the packet as normal - FloodingRouter::sniffReceived(p, c); + config.lora.next_hop_routing ? NextHopRouter::sniffReceived(p, c) : FloodingRouter::sniffReceived(p, c); } #define NUM_RETRANSMISSIONS 3 @@ -222,9 +222,21 @@ int32_t ReliableRouter::doRetransmissions() LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, p.packet->id, p.numRetransmissions); + if (config.lora.next_hop_routing && p.numRetransmissions == 1) { + // Last retransmission, reset next_hop (fallback to FloodingRouter) + p.packet->next_hop = 0; + // Also reset it in the nodeDB + meshtastic_NodeInfoLite *sentTo = nodeDB.getMeshNode(p.packet->to); + if (sentTo) { + LOG_DEBUG("Resetting next hop for packet with dest %x\n", p.packet->to); + sentTo->next_hop = 0; + } + } + // Note: we call the superclass version because we don't want to have our version of send() add a new // retransmission record - FloodingRouter::send(packetPool.allocCopy(*p.packet)); + config.lora.next_hop_routing ? NextHopRouter::send(packetPool.allocCopy(*p.packet)) + : FloodingRouter::send(packetPool.allocCopy(*p.packet)); // Queue again --p.numRetransmissions; @@ -251,4 +263,4 @@ void ReliableRouter::setNextTx(PendingPacket *pending) LOG_DEBUG("Setting next retransmission in %u msecs: ", d); printPacket("", pending->packet); setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time -} +} \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 259da7249..c5ceff73b 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -1,6 +1,6 @@ #pragma once -#include "FloodingRouter.h" +#include "NextHopRouter.h" #include /** @@ -51,7 +51,7 @@ class GlobalPacketIdHashFunction /** * This is a mixin that extends Router with the ability to do (one hop only) reliable message sends. */ -class ReliableRouter : public FloodingRouter +class ReliableRouter : public NextHopRouter { private: std::unordered_map pending; @@ -120,4 +120,4 @@ class ReliableRouter : public FloodingRouter int32_t doRetransmissions(); void setNextTx(PendingPacket *pending); -}; +}; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 03aa57351..888818c85 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -240,6 +240,8 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) // the lora we need to make sure we have replaced it with our local address p->from = getFrom(p); + p->current_relayer = getNodeNum(); // set the current relayer to us + // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index b66af0ebd..65093506f 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -54,7 +54,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; #define meshtastic_ChannelSet_fields &meshtastic_ChannelSet_msg /* Maximum encoded size of messages (where known) */ -#define meshtastic_ChannelSet_size 591 +#define meshtastic_ChannelSet_size 593 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 2a811140f..22a837242 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -438,6 +438,8 @@ typedef struct _meshtastic_Config_LoRaConfig { Please respect your local laws and regulations. If you are a HAM, make sure you enable HAM mode and turn off encryption. */ float override_frequency; + /* If the NeighborInfo Module is enabled, use its information for next hop-based routing */ + bool next_hop_routing; /* For testing it is useful sometimes to force a node to never listen to particular other nodes (simulating radio out of range). All nodenums listed in ignore_incoming will have packets they send dropped on receive (by router.cpp) */ @@ -545,7 +547,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0} -#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} +#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0} @@ -554,7 +556,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0} -#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} +#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -624,6 +626,7 @@ extern "C" { #define meshtastic_Config_LoRaConfig_override_duty_cycle_tag 12 #define meshtastic_Config_LoRaConfig_sx126x_rx_boosted_gain_tag 13 #define meshtastic_Config_LoRaConfig_override_frequency_tag 14 +#define meshtastic_Config_LoRaConfig_next_hop_routing_tag 15 #define meshtastic_Config_LoRaConfig_ignore_incoming_tag 103 #define meshtastic_Config_BluetoothConfig_enabled_tag 1 #define meshtastic_Config_BluetoothConfig_mode_tag 2 @@ -747,6 +750,7 @@ X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \ X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \ X(a, STATIC, SINGULAR, BOOL, sx126x_rx_boosted_gain, 13) \ X(a, STATIC, SINGULAR, FLOAT, override_frequency, 14) \ +X(a, STATIC, SINGULAR, BOOL, next_hop_routing, 15) \ X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) #define meshtastic_Config_LoRaConfig_CALLBACK NULL #define meshtastic_Config_LoRaConfig_DEFAULT NULL @@ -783,7 +787,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define meshtastic_Config_BluetoothConfig_size 10 #define meshtastic_Config_DeviceConfig_size 32 #define meshtastic_Config_DisplayConfig_size 28 -#define meshtastic_Config_LoRaConfig_size 77 +#define meshtastic_Config_LoRaConfig_size 79 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 195 #define meshtastic_Config_PositionConfig_size 60 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index c554074a2..2d6269888 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -65,6 +65,8 @@ typedef struct _meshtastic_NodeInfoLite { meshtastic_DeviceMetrics device_metrics; /* local channel index we heard that node on. Only populated if its not the default channel. */ uint8_t channel; + /* Node number of the node to use as a next hop in order to reach this node. */ + uint32_t next_hop; } meshtastic_NodeInfoLite; /* The on-disk saved channels */ @@ -175,13 +177,13 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}, 0, {meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default}} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_User_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_User_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0} #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_OEMStore_init_default {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default} #define meshtastic_NodeRemoteHardwarePin_init_default {0, false, meshtastic_RemoteHardwarePin_init_default} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}, 0, {meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero}} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} #define meshtastic_OEMStore_init_zero {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero} @@ -200,6 +202,7 @@ extern "C" { #define meshtastic_NodeInfoLite_last_heard_tag 5 #define meshtastic_NodeInfoLite_device_metrics_tag 6 #define meshtastic_NodeInfoLite_channel_tag 7 +#define meshtastic_NodeInfoLite_next_hop_tag 8 #define meshtastic_ChannelFile_channels_tag 1 #define meshtastic_ChannelFile_version_tag 2 #define meshtastic_OEMStore_oem_icon_width_tag 1 @@ -252,7 +255,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \ X(a, STATIC, SINGULAR, FLOAT, snr, 4) \ X(a, STATIC, SINGULAR, FIXED32, last_heard, 5) \ X(a, STATIC, OPTIONAL, MESSAGE, device_metrics, 6) \ -X(a, STATIC, SINGULAR, UINT32, channel, 7) +X(a, STATIC, SINGULAR, UINT32, channel, 7) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 8) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_User @@ -313,10 +317,10 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_ChannelFile_size 638 -#define meshtastic_DeviceState_size 16854 -#define meshtastic_NodeInfoLite_size 151 +#define meshtastic_DeviceState_size 17490 +#define meshtastic_NodeInfoLite_size 157 #define meshtastic_NodeRemoteHardwarePin_size 29 -#define meshtastic_OEMStore_size 3218 +#define meshtastic_OEMStore_size 3220 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index f672d865c..44c49d047 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -174,7 +174,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; #define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg /* Maximum encoded size of messages (where known) */ -#define meshtastic_LocalConfig_size 463 +#define meshtastic_LocalConfig_size 465 #define meshtastic_LocalModuleConfig_size 609 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index c32f55aab..110c2217d 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -563,6 +563,12 @@ typedef struct _meshtastic_MeshPacket { int32_t rx_rssi; /* Describe if this message is delayed */ meshtastic_MeshPacket_Delayed delayed; + /* Node number of the node that should be used as the next hop in routing. + Only the last byte is sent in the packet header. */ + uint32_t next_hop; + /* Node number of the node that is currently relaying this packet. + Only the last byte is sent in the packet header. */ + uint32_t current_relayer; } meshtastic_MeshPacket; /* The bluetooth to device link: @@ -686,7 +692,7 @@ typedef struct _meshtastic_Neighbor { uint32_t node_id; /* SNR of last heard message */ float snr; - /* Reception time (in secs since 1970) of last message that was last sent by this ID. + /* Reception time of last message that was sent by this ID. Note: this is for local storage only and will not be sent out over the mesh. */ uint32_t last_rx_time; /* Broadcast interval of this neighbor (in seconds). @@ -858,7 +864,7 @@ extern "C" { #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN} +#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0} #define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -876,7 +882,7 @@ extern "C" { #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN} +#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0} #define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -954,6 +960,8 @@ extern "C" { #define meshtastic_MeshPacket_priority_tag 11 #define meshtastic_MeshPacket_rx_rssi_tag 12 #define meshtastic_MeshPacket_delayed_tag 13 +#define meshtastic_MeshPacket_next_hop_tag 14 +#define meshtastic_MeshPacket_current_relayer_tag 15 #define meshtastic_NodeInfo_num_tag 1 #define meshtastic_NodeInfo_user_tag 2 #define meshtastic_NodeInfo_position_tag 3 @@ -1108,7 +1116,9 @@ X(a, STATIC, SINGULAR, UINT32, hop_limit, 9) \ X(a, STATIC, SINGULAR, BOOL, want_ack, 10) \ X(a, STATIC, SINGULAR, UENUM, priority, 11) \ X(a, STATIC, SINGULAR, INT32, rx_rssi, 12) \ -X(a, STATIC, SINGULAR, UENUM, delayed, 13) +X(a, STATIC, SINGULAR, UENUM, delayed, 13) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 14) \ +X(a, STATIC, SINGULAR, UINT32, current_relayer, 15) #define meshtastic_MeshPacket_CALLBACK NULL #define meshtastic_MeshPacket_DEFAULT NULL #define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data @@ -1209,7 +1219,7 @@ X(a, STATIC, REPEATED, MESSAGE, neighbors, 4) #define meshtastic_Neighbor_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, node_id, 1) \ X(a, STATIC, SINGULAR, FLOAT, snr, 2) \ -X(a, STATIC, SINGULAR, FIXED32, last_rx_time, 3) \ +X(a, STATIC, SINGULAR, UINT32, last_rx_time, 3) \ X(a, STATIC, SINGULAR, UINT32, node_broadcast_interval_secs, 4) #define meshtastic_Neighbor_CALLBACK NULL #define meshtastic_Neighbor_DEFAULT NULL @@ -1273,11 +1283,11 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg; #define meshtastic_DeviceMetadata_size 46 #define meshtastic_FromRadio_size 510 #define meshtastic_LogRecord_size 81 -#define meshtastic_MeshPacket_size 321 +#define meshtastic_MeshPacket_size 333 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 18 -#define meshtastic_NeighborInfo_size 258 -#define meshtastic_Neighbor_size 22 +#define meshtastic_NeighborInfo_size 268 +#define meshtastic_Neighbor_size 23 #define meshtastic_NodeInfo_size 261 #define meshtastic_Position_size 137 #define meshtastic_QueueStatus_size 23 diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index cf2276f0e..09e7dd5cb 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -156,6 +156,17 @@ size_t NeighborInfoModule::cleanUpNeighbors() // Update the neighbor list for (uint i = 0; i < indices_to_remove.size(); i++) { int index = indices_to_remove[i]; + + if (config.lora.next_hop_routing) { + // Clear all next hops of nodes that had this neighbor as next hop + for (unsigned int j = 0; j < nodeDB.getNumMeshNodes(); j++) { + meshtastic_NodeInfoLite *node = nodeDB.getMeshNodeByIndex(j); + if (node->next_hop == neighbors[index].node_id) { + node->next_hop = 0; + } + } + } + LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id); for (int j = index; j < num_neighbors - 1; j++) { neighbors[j] = neighbors[j + 1]; @@ -205,6 +216,8 @@ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, if (enabled) { printNeighborInfo("RECEIVED", np); updateNeighbors(mp, np); + if (config.lora.next_hop_routing) + updateNextHops(np); } // Allow others to handle this packet return false; @@ -229,6 +242,54 @@ void NeighborInfoModule::updateLastSentById(meshtastic_MeshPacket *p) pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_NeighborInfo_msg, updated); } +/* Update the next hop for nodes in the database. + * Based on our own neighbors, and the neighbors of our neighbors. + */ +void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) +{ + LOG_DEBUG("Updating next hops based on received NeighborInfo packet\n"); + meshtastic_NodeInfoLite *currentNode = nodeDB.getMeshNode(np->node_id); + // Check if the sender of this neighborInfo packet is a neighbor of ourselves + if (currentNode && isANeighbor(np->node_id)) { + currentNode->next_hop = np->node_id; // Set the next hop to the sender of this packet + for (uint8_t i = 0; i < np->neighbors_count; i++) { + if (isANeighbor(np->neighbors[i].node_id)) + continue; // This node is a neighbor of ourselves + + meshtastic_NodeInfoLite *neighborOfCurrentNode = nodeDB.getMeshNode(np->neighbors[i].node_id); + // Update next hop of this node to the sender of this packet, because it is the most recent neighbor + if (neighborOfCurrentNode) + neighborOfCurrentNode->next_hop = currentNode->num; + } + } else if (currentNode) { // Sender is not a neighbor + // Find common neighbors and use the most recent as next hop to this node + meshtastic_NodeInfoLite *currentNextHop = nodeDB.getMeshNode(currentNode->next_hop); + uint32_t maxLastHeard = currentNextHop ? currentNextHop->last_heard : 0; + for (uint8_t i = 0; i < np->neighbors_count; i++) { + meshtastic_NodeInfoLite *neighborOfCurrentNode = nodeDB.getMeshNode(np->neighbors[i].node_id); + if (neighborOfCurrentNode && isANeighbor(neighborOfCurrentNode->num)) { + // This neighbor was heard more recently than the current next hop + if (neighborOfCurrentNode->last_heard > maxLastHeard) { + currentNode->next_hop = neighborOfCurrentNode->num; + maxLastHeard = neighborOfCurrentNode->last_heard; + LOG_DEBUG("More recent node found, so update next_hop of %x to %x\n", currentNode->num, + neighborOfCurrentNode->num); + } + } + } + } +} + +bool NeighborInfoModule::isANeighbor(NodeNum node_id) +{ + for (int i = 0; i < *numNeighbors; i++) { + if (neighbors[i].node_id == node_id) { + return true; + } + } + return false; +} + void NeighborInfoModule::resetNeighbors() { *numNeighbors = 0; @@ -308,4 +369,4 @@ bool NeighborInfoModule::saveProtoForModule() okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState); return okay; -} \ No newline at end of file +} diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index 0e3ec09ca..e848f7ee4 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -20,8 +20,9 @@ class NeighborInfoModule : public ProtobufModule, priva bool saveProtoForModule(); - // Let FloodingRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet + // Let FloodingRouter/NexthopRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet friend class FloodingRouter; + friend class NextHopRouter; protected: // Note: this holds our local info. @@ -70,6 +71,12 @@ class NeighborInfoModule : public ProtobufModule, priva /* update a NeighborInfo packet with our NodeNum as last_sent_by_id */ void updateLastSentById(meshtastic_MeshPacket *p); + /* update the next hop for nodes in the database */ + void updateNextHops(meshtastic_NeighborInfo *np); + + /* check if the given node number is a neighbor of us */ + bool isANeighbor(NodeNum node_id); + void loadProtoForModule(); /* Does our periodic broadcast */ diff --git a/src/modules/TraceRouteModule.h b/src/modules/TraceRouteModule.h index 674846ef1..8e8b64561 100644 --- a/src/modules/TraceRouteModule.h +++ b/src/modules/TraceRouteModule.h @@ -9,8 +9,9 @@ class TraceRouteModule : public ProtobufModule public: TraceRouteModule(); - // Let FloodingRouter call updateRoute upon rebroadcasting a TraceRoute request + // Let FloodingRouter/NextHopRouter call updateRoute upon rebroadcasting a TraceRoute request friend class FloodingRouter; + friend class NextHopRouter; protected: bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_RouteDiscovery *r) override;