mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
"""
|
||
Centralized helpers for MeshCore multi-byte path encoding.
|
||
|
||
The path_len wire byte is packed as [hash_mode:2][hop_count:6]:
|
||
- hash_size = (hash_mode) + 1 → 1, 2, or 3 bytes per hop
|
||
- hop_count = lower 6 bits → 0–63 hops
|
||
- wire bytes = hop_count × hash_size
|
||
|
||
Mode 3 (hash_size=4) is reserved and rejected.
|
||
"""
|
||
|
||
|
||
def decode_path_byte(path_byte: int) -> tuple[int, int]:
|
||
"""Decode a packed path byte into (hop_count, hash_size).
|
||
|
||
Returns:
|
||
(hop_count, hash_size) where hash_size is 1, 2, or 3.
|
||
|
||
Raises:
|
||
ValueError: If hash_mode is 3 (reserved).
|
||
"""
|
||
hash_mode = (path_byte >> 6) & 0x03
|
||
if hash_mode == 3:
|
||
raise ValueError(f"Reserved path hash mode 3 (path_byte=0x{path_byte:02X})")
|
||
hop_count = path_byte & 0x3F
|
||
hash_size = hash_mode + 1
|
||
return hop_count, hash_size
|
||
|
||
|
||
def path_wire_len(hop_count: int, hash_size: int) -> int:
|
||
"""Wire byte length of path data."""
|
||
return hop_count * hash_size
|
||
|
||
|
||
def split_path_hex(path_hex: str, hop_count: int) -> list[str]:
|
||
"""Split a hex path string into per-hop chunks using the known hop count.
|
||
|
||
If hop_count is 0 or the hex length doesn't divide evenly, falls back
|
||
to 2-char (1-byte) chunks for backward compatibility.
|
||
"""
|
||
if not path_hex or hop_count <= 0:
|
||
return []
|
||
chars_per_hop = len(path_hex) // hop_count
|
||
if chars_per_hop < 2 or chars_per_hop % 2 != 0 or chars_per_hop * hop_count != len(path_hex):
|
||
# Inconsistent — fall back to legacy 2-char split
|
||
return [path_hex[i : i + 2] for i in range(0, len(path_hex), 2)]
|
||
return [path_hex[i : i + chars_per_hop] for i in range(0, len(path_hex), chars_per_hop)]
|
||
|
||
|
||
def first_hop_hex(path_hex: str, hop_count: int) -> str | None:
|
||
"""Extract the first hop identifier from a path hex string.
|
||
|
||
Returns None for empty/direct paths.
|
||
"""
|
||
hops = split_path_hex(path_hex, hop_count)
|
||
return hops[0] if hops else None
|
||
|
||
|
||
def infer_hash_size(path_hex: str, hop_count: int) -> int:
|
||
"""Derive bytes-per-hop from path hex length and hop count.
|
||
|
||
Returns 1 as default for ambiguous or legacy cases.
|
||
"""
|
||
if hop_count <= 0 or not path_hex:
|
||
return 1
|
||
hex_per_hop = len(path_hex) // hop_count
|
||
byte_per_hop = hex_per_hop // 2
|
||
if byte_per_hop in (1, 2, 3) and hex_per_hop * hop_count == len(path_hex):
|
||
return byte_per_hop
|
||
return 1
|