diff --git a/app/main.py b/app/main.py index a2df1a3..d9a2d46 100644 --- a/app/main.py +++ b/app/main.py @@ -230,12 +230,19 @@ def _execute_console_command(args: list) -> str: typ = type_names.get(c.get('type', 1), '?') pk_short = pk[:12] opl = c.get('out_path_len', -1) - if opl == -1: - path_str = 'Flood' + if opl > 0: + # Decode path: lower 6 bits = hop count, upper 2 bits = hash_size-1 + hop_count = opl & 0x3F + hash_size = (opl >> 6) + 1 + raw = c.get('out_path', '') + meaningful = raw[:hop_count * hash_size * 2] + chunk = hash_size * 2 + hops = [meaningful[i:i+chunk].upper() for i in range(0, len(meaningful), chunk)] + path_str = '→'.join(hops) if hops else f'len:{opl}' elif opl == 0: - path_str = '0 hop' + path_str = 'Direct' else: - path_str = c.get('out_path', f'len:{opl}') + path_str = 'Flood' lines.append(f" {name:30} {typ:4} {pk_short} {path_str}") return f"Contacts ({len(lines)}) on device:\n" + "\n".join(lines) diff --git a/app/routes/api.py b/app/routes/api.py index bf1a013..b2831e4 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -2376,17 +2376,23 @@ def get_contacts_detailed_api(): for public_key, details in contacts_detailed.items(): # Compute path display string + # out_path_len encodes hop count (lower 6 bits) and hash_size (upper 2 bits) + # In MeshCore V1: hash_size=1 byte per hop, so each hop = 2 hex chars out_path_len = details.get('out_path_len', -1) - out_path = details.get('out_path', '') - if out_path: - # out_path present = known route (even if out_path_len says -1) - path_or_mode = out_path - elif out_path_len == -1: - path_or_mode = 'Flood' + out_path_raw = details.get('out_path', '') + if out_path_len > 0 and out_path_raw: + hop_count = out_path_len & 0x3F + hash_size = (out_path_len >> 6) + 1 # 1, 2, or 3 bytes per hop + # Truncate to meaningful bytes (firmware buffer may have trailing garbage) + meaningful_hex = out_path_raw[:hop_count * hash_size * 2] + # Format as HEX→HEX→HEX (each hop is hash_size*2 hex chars) + chunk = hash_size * 2 + hops = [meaningful_hex[i:i+chunk].upper() for i in range(0, len(meaningful_hex), chunk)] + path_or_mode = '→'.join(hops) if hops else out_path_raw elif out_path_len == 0: - path_or_mode = '0 hop' + path_or_mode = 'Direct' else: - path_or_mode = f'Path len: {out_path_len}' + path_or_mode = 'Flood' contact = { # All original fields from contact_info diff --git a/app/static/js/contacts.js b/app/static/js/contacts.js index 6ab30e6..c9a4fe7 100644 --- a/app/static/js/contacts.js +++ b/app/static/js/contacts.js @@ -2148,15 +2148,14 @@ function createExistingContactCard(contact, index) { pathDiv = document.createElement('div'); pathDiv.className = 'text-muted small'; const mode = contact.path_or_mode || 'Flood'; - const pathLen = contact.out_path_len; if (mode === 'Flood') { pathDiv.innerHTML = ' Flood'; - } else if (mode === '0 hop') { - pathDiv.innerHTML = ' Direct (0 hop)'; + } else if (mode === 'Direct') { + pathDiv.innerHTML = ' Direct'; } else { - // mode is hex path string, show hops count + path - const hops = pathLen >= 0 ? pathLen : '?'; - pathDiv.innerHTML = ` Path: ${mode} (${hops} hops)`; + // mode is formatted path like "E7→DE→54→54→D8" + const hopCount = mode.split('→').length; + pathDiv.innerHTML = ` ${mode} (${hopCount} hops)`; } }