diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 1f0621f9a..f32f865db 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -187,6 +187,8 @@ typedef enum _meshtastic_HardwareModel { /* RadioMaster 900 Bandit, https://www.radiomasterrc.com/products/bandit-expresslrs-rf-module SSD1306 OLED and No GPS */ meshtastic_HardwareModel_RADIOMASTER_900_BANDIT = 74, + /* Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. */ + meshtastic_HardwareModel_ME25LS01_4Y10TD = 75, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -502,11 +504,20 @@ typedef struct _meshtastic_User { meshtastic_User_public_key_t public_key; } meshtastic_User; -/* A message used in our Dynamic Source Routing protocol (RFC 4728 based) */ +/* A message used in a traceroute */ typedef struct _meshtastic_RouteDiscovery { - /* The list of nodenums this packet has visited so far */ + /* The list of nodenums this packet has visited so far to the destination. */ pb_size_t route_count; uint32_t route[8]; + /* The list of SNRs (in dB, scaled by 4) in the route towards the destination. */ + pb_size_t snr_towards_count; + int8_t snr_towards[8]; + /* The list of nodenums the packet has visited on the way back from the destination. */ + pb_size_t route_back_count; + uint32_t route_back[8]; + /* The list of SNRs (in dB, scaled by 4) in the route back from the destination. */ + pb_size_t snr_back_count; + int8_t snr_back[8]; } meshtastic_RouteDiscovery; /* A Routing control Data packet handled by the routing module */ @@ -1054,7 +1065,7 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_Position_init_default {false, 0, false, 0, false, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, false, 0, false, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}} #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} @@ -1079,7 +1090,7 @@ extern "C" { #define meshtastic_ChunkedPayloadResponse_init_default {0, 0, {0}} #define meshtastic_Position_init_zero {false, 0, false, 0, false, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, false, 0, false, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}} #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} @@ -1136,6 +1147,9 @@ extern "C" { #define meshtastic_User_role_tag 7 #define meshtastic_User_public_key_tag 8 #define meshtastic_RouteDiscovery_route_tag 1 +#define meshtastic_RouteDiscovery_snr_towards_tag 2 +#define meshtastic_RouteDiscovery_route_back_tag 3 +#define meshtastic_RouteDiscovery_snr_back_tag 4 #define meshtastic_Routing_route_request_tag 1 #define meshtastic_Routing_route_reply_tag 2 #define meshtastic_Routing_error_reason_tag 3 @@ -1298,7 +1312,10 @@ X(a, STATIC, SINGULAR, BYTES, public_key, 8) #define meshtastic_User_DEFAULT NULL #define meshtastic_RouteDiscovery_FIELDLIST(X, a) \ -X(a, STATIC, REPEATED, FIXED32, route, 1) +X(a, STATIC, REPEATED, FIXED32, route, 1) \ +X(a, STATIC, REPEATED, INT32, snr_towards, 2) \ +X(a, STATIC, REPEATED, FIXED32, route_back, 3) \ +X(a, STATIC, REPEATED, INT32, snr_back, 4) #define meshtastic_RouteDiscovery_CALLBACK NULL #define meshtastic_RouteDiscovery_DEFAULT NULL @@ -1612,8 +1629,8 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_NodeRemoteHardwarePin_size 29 #define meshtastic_Position_size 144 #define meshtastic_QueueStatus_size 23 -#define meshtastic_RouteDiscovery_size 40 -#define meshtastic_Routing_size 42 +#define meshtastic_RouteDiscovery_size 256 +#define meshtastic_Routing_size 259 #define meshtastic_ToRadio_size 504 #define meshtastic_User_size 113 #define meshtastic_Waypoint_size 165 diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 7fd57fe00..2e1985660 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -341,7 +341,7 @@ typedef struct _meshtastic_ModuleConfig_CannedMessageConfig { /* Enable/disable CannedMessageModule. */ bool enabled; /* Input event origin accepted by the canned message module. - Can be e.g. "rotEnc1", "upDownEnc1" or keyword "_any" */ + Can be e.g. "rotEnc1", "upDownEnc1", "scanAndSelect", "cardkb", "serialkb", or keyword "_any" */ char allow_input_source[16]; /* CannedMessageModule also sends a bell character with the messages. ExternalNotificationModule can benefit from this feature. */ diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 6cc82352a..b9e537ddf 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -113,7 +113,7 @@ typedef enum _meshtastic_PortNum { ENCODING: Protobuf (?) */ meshtastic_PortNum_SIMULATOR_APP = 69, /* Provides a traceroute functionality to show the route a packet towards - a certain destination would take on the mesh. + a certain destination would take on the mesh. Contains a RouteDiscovery message as payload. ENCODING: Protobuf */ meshtastic_PortNum_TRACEROUTE_APP = 70, /* Aggregates edge info for the network by sending out a list of each node's neighbors diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp index f390aafcd..dd3d0b4f9 100644 --- a/src/modules/TraceRouteModule.cpp +++ b/src/modules/TraceRouteModule.cpp @@ -5,71 +5,141 @@ TraceRouteModule *traceRouteModule; bool TraceRouteModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_RouteDiscovery *r) { - // Only handle a response - if (mp.decoded.request_id) { - printRoute(r, mp.to, mp.from); - } - + // We only alter the packet in alterReceivedProtobuf() return false; // let it be handled by RoutingModule } void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r) { auto &incoming = p.decoded; - // Only append IDs for the request (one way) - if (!incoming.request_id) { - // Insert unknown hops if necessary - insertUnknownHops(p, r); - // Don't add ourselves if we are the destination (the reply will have our NodeNum already) - if (p.to != nodeDB->getNodeNum()) { - appendMyID(r); - printRoute(r, p.from, NODENUM_BROADCAST); - } - // Set updated route to the payload of the to be flooded packet - p.decoded.payload.size = - pb_encode_to_bytes(p.decoded.payload.bytes, sizeof(p.decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, r); - } + // Insert unknown hops if necessary + insertUnknownHops(p, r, !incoming.request_id); + + // Append ID and SNR. For the last hop (p.to == nodeDB->getNodeNum()), we only need to append the SNR + appendMyIDandSNR(r, p.rx_snr, !incoming.request_id, p.to == nodeDB->getNodeNum()); + if (!incoming.request_id) + printRoute(r, p.from, p.to, true); + else + printRoute(r, p.to, p.from, false); + + // Set updated route to the payload of the to be flooded packet + p.decoded.payload.size = + pb_encode_to_bytes(p.decoded.payload.bytes, sizeof(p.decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, r); } -void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r) +void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r, bool isTowardsDestination) { + pb_size_t *route_count; + uint32_t *route; + pb_size_t *snr_count; + int8_t *snr_list; + + // Pick the correct route array and SNR list + if (isTowardsDestination) { + route_count = &r->route_count; + route = r->route; + snr_count = &r->snr_towards_count; + snr_list = r->snr_towards; + } else { + route_count = &r->route_back_count; + route = r->route_back; + snr_count = &r->snr_back_count; + snr_list = r->snr_back; + } + // Only insert unknown hops if hop_start is valid if (p.hop_start != 0 && p.hop_limit <= p.hop_start) { uint8_t hopsTaken = p.hop_start - p.hop_limit; - int8_t diff = hopsTaken - r->route_count; + int8_t diff = hopsTaken - *route_count; for (uint8_t i = 0; i < diff; i++) { - if (r->route_count < sizeof(r->route) / sizeof(r->route[0])) { - r->route[r->route_count] = NODENUM_BROADCAST; // This will represent an unknown hop - r->route_count += 1; + if (*route_count < sizeof(*route) / sizeof(route[0])) { + route[*route_count] = NODENUM_BROADCAST; // This will represent an unknown hop + *route_count += 1; + } + } + // Add unknown SNR values if necessary + diff = *route_count - *snr_count; + for (uint8_t i = 0; i < diff; i++) { + if (*snr_count < sizeof(*snr_list) / sizeof(snr_list[0])) { + snr_list[*snr_count] = INT8_MIN; // This will represent an unknown SNR + *snr_count += 1; } } } } -void TraceRouteModule::appendMyID(meshtastic_RouteDiscovery *updated) +void TraceRouteModule::appendMyIDandSNR(meshtastic_RouteDiscovery *updated, float snr, bool isTowardsDestination, bool SNRonly) { + pb_size_t *route_count; + uint32_t *route; + pb_size_t *snr_count; + int8_t *snr_list; + + // Pick the correct route array and SNR list + if (isTowardsDestination) { + route_count = &updated->route_count; + route = updated->route; + snr_count = &updated->snr_towards_count; + snr_list = updated->snr_towards; + } else { + route_count = &updated->route_back_count; + route = updated->route_back; + snr_count = &updated->snr_back_count; + snr_list = updated->snr_back; + } + + if (*snr_count < sizeof(*snr_list) / sizeof(snr_list[0])) { + snr_list[*snr_count] = (int8_t)(snr * 4); // Convert SNR to 1 byte + *snr_count += 1; + } + if (SNRonly) + return; + // Length of route array can normally not be exceeded due to the max. hop_limit of 7 - if (updated->route_count < sizeof(updated->route) / sizeof(updated->route[0])) { - updated->route[updated->route_count] = myNodeInfo.my_node_num; - updated->route_count += 1; + if (*route_count < sizeof(*route) / sizeof(route[0])) { + route[*route_count] = myNodeInfo.my_node_num; + *route_count += 1; } else { LOG_WARN("Route exceeded maximum hop limit, are you bridging networks?\n"); } } -void TraceRouteModule::printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, uint32_t dest) +void TraceRouteModule::printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, uint32_t dest, bool isTowardsDestination) { #ifdef DEBUG_PORT LOG_INFO("Route traced:\n"); LOG_INFO("0x%x --> ", origin); for (uint8_t i = 0; i < r->route_count; i++) { - LOG_INFO("0x%x --> ", r->route[i]); + if (i < r->snr_towards_count && r->snr_towards[i] != INT8_MIN) + LOG_INFO("0x%x (%.2fdB) --> ", r->route[i], (float)r->snr_towards[i] / 4); + else + LOG_INFO("0x%x (?dB) --> ", r->route[i]); } - if (dest != NODENUM_BROADCAST) - LOG_INFO("0x%x\n", dest); - else + // If we are the destination, or it has already reached the destination, print it + if (dest == nodeDB->getNodeNum() || !isTowardsDestination) { + if (r->snr_towards_count > 0 && r->snr_towards[r->snr_towards_count - 1] != INT8_MIN) + LOG_INFO("0x%x (%.2fdB)\n", dest, (float)r->snr_towards[r->snr_towards_count - 1] / 4); + else + LOG_INFO("0x%x (?dB)\n", dest); + } else LOG_INFO("...\n"); + + // If there's a route back (or we are the destination as then the route is complete), print it + if (r->route_back_count > 0 || origin == nodeDB->getNodeNum()) { + if (r->snr_towards_count > 0 && origin == nodeDB->getNodeNum()) + LOG_INFO("(%.2fdB) 0x%x <-- ", (float)r->snr_back[r->snr_back_count - 1] / 4, origin); + else + LOG_INFO("..."); + + for (int8_t i = r->route_back_count - 1; i >= 0; i--) { + if (i < r->snr_back_count && r->snr_back[i] != INT8_MIN) + LOG_INFO("(%.2fdB) 0x%x <-- ", (float)r->snr_back[i] / 4, r->route_back[i]); + else + LOG_INFO("(?dB) 0x%x <-- ", r->route_back[i]); + } + LOG_INFO("0x%x\n", dest); + } #endif } @@ -86,8 +156,6 @@ meshtastic_MeshPacket *TraceRouteModule::allocReply() pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_RouteDiscovery_msg, &scratch); updated = &scratch; - printRoute(updated, req.from, req.to); - // Create a MeshPacket with this payload and set it as the reply meshtastic_MeshPacket *reply = allocDataProtobuf(*updated); diff --git a/src/modules/TraceRouteModule.h b/src/modules/TraceRouteModule.h index 18a5ac0cb..fe69300de 100644 --- a/src/modules/TraceRouteModule.h +++ b/src/modules/TraceRouteModule.h @@ -20,15 +20,15 @@ class TraceRouteModule : public ProtobufModule private: // Call to add unknown hops (e.g. when a node couldn't decrypt it) to the route based on hopStart and current hopLimit - void insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r); + void insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r, bool isTowardsDestination); // Call to add your ID to the route array of a RouteDiscovery message - void appendMyID(meshtastic_RouteDiscovery *r); + void appendMyIDandSNR(meshtastic_RouteDiscovery *r, float snr, bool isTowardsDestination, bool SNRonly); /* Call to print the route array of a RouteDiscovery message. Set origin to where the request came from. Set dest to the ID of its destination, or NODENUM_BROADCAST if it has not yet arrived there. */ - void printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, uint32_t dest); + void printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, uint32_t dest, bool isTowardsDestination); }; extern TraceRouteModule *traceRouteModule; \ No newline at end of file