mirror of
https://github.com/meshcore-dev/meshcore_py.git
synced 2026-04-20 22:13:49 +00:00
multibyte trace support
This commit is contained in:
parent
32907bb5c1
commit
dd6d6350d9
2 changed files with 63 additions and 41 deletions
|
|
@ -181,7 +181,7 @@ class MessagingCommands(CommandHandlerBase):
|
||||||
self,
|
self,
|
||||||
auth_code: int = 0,
|
auth_code: int = 0,
|
||||||
tag: Optional[int] = None,
|
tag: Optional[int] = None,
|
||||||
flags: int = 0,
|
flags = None,
|
||||||
path: Optional[Union[str, bytes, bytearray]] = None,
|
path: Optional[Union[str, bytes, bytearray]] = None,
|
||||||
) -> Event:
|
) -> Event:
|
||||||
"""
|
"""
|
||||||
|
|
@ -190,7 +190,8 @@ class MessagingCommands(CommandHandlerBase):
|
||||||
Args:
|
Args:
|
||||||
auth_code: 32-bit authentication code (default: 0)
|
auth_code: 32-bit authentication code (default: 0)
|
||||||
tag: 32-bit integer to identify this trace (default: random)
|
tag: 32-bit integer to identify this trace (default: random)
|
||||||
flags: 8-bit flags field (default: 0)
|
flags: 8-bit flags field (default: None)
|
||||||
|
lower two bytes set the path hash size (1 << s) => 1, 2, 4 bytes
|
||||||
path: Optional string with comma-separated hex values representing repeater pubkeys (e.g. "23,5f,3a")
|
path: Optional string with comma-separated hex values representing repeater pubkeys (e.g. "23,5f,3a")
|
||||||
or a bytes/bytearray object with the raw path data
|
or a bytes/bytearray object with the raw path data
|
||||||
|
|
||||||
|
|
@ -203,39 +204,62 @@ class MessagingCommands(CommandHandlerBase):
|
||||||
if auth_code is None:
|
if auth_code is None:
|
||||||
auth_code = random.randint(1, 0xFFFFFFFF)
|
auth_code = random.randint(1, 0xFFFFFFFF)
|
||||||
|
|
||||||
logger.debug(
|
path_hash_len = 1 # default
|
||||||
f"Sending trace: tag={tag}, auth={auth_code}, flags={flags}, path={path}"
|
if flags is None:
|
||||||
)
|
if isinstance(path, str): # get flags from path string
|
||||||
|
path_hash_len = int(len(path.split(",")[0]) / 2)
|
||||||
|
if path_hash_len == 1 :
|
||||||
|
flags = 0
|
||||||
|
elif path_hash_len == 2 :
|
||||||
|
flags = 1
|
||||||
|
elif path_hash_len == 4 :
|
||||||
|
flags = 2
|
||||||
|
elif path_hash_len == 8 :
|
||||||
|
flags = 3
|
||||||
|
else :
|
||||||
|
logger.error(f"Invalid path format: {e}")
|
||||||
|
return Event(EventType.ERROR, {"reason": "invalid_path_format"})
|
||||||
|
else:
|
||||||
|
flags = 0
|
||||||
|
else:
|
||||||
|
path_hash_len = 1 << (flags & 3)
|
||||||
|
|
||||||
|
# Process path if provided
|
||||||
|
path_bytes = bytearray()
|
||||||
|
if path:
|
||||||
|
if isinstance(path, str):
|
||||||
|
# Convert comma-separated hex values to bytes
|
||||||
|
try:
|
||||||
|
for hex_val in path.split(","):
|
||||||
|
hex_val = hex_val.strip()
|
||||||
|
if hex_val == "":
|
||||||
|
break
|
||||||
|
elif len(hex_val) != path_hash_len * 2 :
|
||||||
|
raise(ValueError())
|
||||||
|
path_bytes.extend(bytes.fromhex(hex_val))
|
||||||
|
except ValueError as e:
|
||||||
|
logger.error(f"Invalid path format: {e}")
|
||||||
|
return Event(EventType.ERROR, {"reason": "invalid_path_format"})
|
||||||
|
elif isinstance(path, (bytes, bytearray)):
|
||||||
|
path_bytes = path
|
||||||
|
else:
|
||||||
|
logger.error(f"Unsupported path type: {type(path)}")
|
||||||
|
return Event(EventType.ERROR, {"reason": "unsupported_path_type"})
|
||||||
|
|
||||||
# Prepare the command packet: CMD(1) + tag(4) + auth_code(4) + flags(1) + [path]
|
# Prepare the command packet: CMD(1) + tag(4) + auth_code(4) + flags(1) + [path]
|
||||||
cmd_data = bytearray([36]) # CMD_SEND_TRACE_PATH
|
cmd_data = bytearray([36]) # CMD_SEND_TRACE_PATH
|
||||||
cmd_data.extend(tag.to_bytes(4, "little"))
|
cmd_data.extend(tag.to_bytes(4, "little"))
|
||||||
cmd_data.extend(auth_code.to_bytes(4, "little"))
|
cmd_data.extend(auth_code.to_bytes(4, "little"))
|
||||||
cmd_data.append(flags)
|
cmd_data.append(flags)
|
||||||
|
cmd_data.extend(path_bytes)
|
||||||
|
|
||||||
# Process path if provided
|
logger.debug(
|
||||||
if path:
|
f"Sending trace: tag={tag}, auth={auth_code}, flags={flags}, path={path_bytes.hex()}"
|
||||||
if isinstance(path, str):
|
)
|
||||||
# Convert comma-separated hex values to bytes
|
|
||||||
try:
|
|
||||||
path_bytes = bytearray()
|
|
||||||
for hex_val in path.split(","):
|
|
||||||
hex_val = hex_val.strip()
|
|
||||||
path_bytes.append(int(hex_val, 16))
|
|
||||||
cmd_data.extend(path_bytes)
|
|
||||||
except ValueError as e:
|
|
||||||
logger.error(f"Invalid path format: {e}")
|
|
||||||
return Event(EventType.ERROR, {"reason": "invalid_path_format"})
|
|
||||||
elif isinstance(path, (bytes, bytearray)):
|
|
||||||
cmd_data.extend(path)
|
|
||||||
else:
|
|
||||||
logger.error(f"Unsupported path type: {type(path)}")
|
|
||||||
return Event(EventType.ERROR, {"reason": "unsupported_path_type"})
|
|
||||||
|
|
||||||
return await self.send(cmd_data, [EventType.MSG_SENT, EventType.ERROR])
|
return await self.send(cmd_data, [EventType.MSG_SENT, EventType.ERROR])
|
||||||
|
|
||||||
async def set_flood_scope(self, scope):
|
async def set_flood_scope(self, scope):
|
||||||
|
|
||||||
if scope is None:
|
if scope is None:
|
||||||
logger.debug(f"Resetting scope")
|
logger.debug(f"Resetting scope")
|
||||||
scope_key = b"\0"*16
|
scope_key = b"\0"*16
|
||||||
|
|
|
||||||
|
|
@ -532,10 +532,14 @@ class MessageReader:
|
||||||
# According to the source, format is:
|
# According to the source, format is:
|
||||||
# 0x89, reserved(0), path_len, flags, tag(4), auth(4), path_hashes[], path_snrs[], final_snr
|
# 0x89, reserved(0), path_len, flags, tag(4), auth(4), path_hashes[], path_snrs[], final_snr
|
||||||
|
|
||||||
path_len = data[2]
|
reserved = dbuf.read(1)[0]
|
||||||
flags = data[3]
|
path_len = dbuf.read(1)[0]
|
||||||
tag = int.from_bytes(data[4:8], byteorder="little")
|
flags = dbuf.read(1)[0]
|
||||||
auth_code = int.from_bytes(data[8:12], byteorder="little")
|
tag = int.from_bytes(dbuf.read(4), byteorder="little")
|
||||||
|
auth_code = int.from_bytes(dbuf.read(4), byteorder="little")
|
||||||
|
|
||||||
|
path_hash_len = 1 << (flags&3)
|
||||||
|
path_len = int(path_len / path_hash_len)
|
||||||
|
|
||||||
# Initialize result
|
# Initialize result
|
||||||
res["tag"] = tag
|
res["tag"] = tag
|
||||||
|
|
@ -546,26 +550,20 @@ class MessageReader:
|
||||||
# Process path as array of objects with hash and SNR
|
# Process path as array of objects with hash and SNR
|
||||||
path_nodes = []
|
path_nodes = []
|
||||||
|
|
||||||
if path_len > 0 and len(data) >= 12 + path_len * 2 + 1:
|
if path_len > 0 and len(data) >= 12 + path_len + (path_len * path_hash_len) + 1:
|
||||||
# Extract path with hash and SNR pairs
|
# Extract path with hash and SNR pairs
|
||||||
for i in range(path_len):
|
for i in range(path_len):
|
||||||
node = {
|
node = {
|
||||||
"hash": f"{data[12+i]:02x}",
|
"hash": dbuf.read(path_hash_len).hex(),
|
||||||
# SNR is stored as a signed byte representing SNR * 4
|
|
||||||
"snr": (
|
|
||||||
data[12 + path_len + i]
|
|
||||||
if data[12 + path_len + i] < 128
|
|
||||||
else data[12 + path_len + i] - 256
|
|
||||||
)
|
|
||||||
/ 4.0,
|
|
||||||
}
|
}
|
||||||
path_nodes.append(node)
|
path_nodes.append(node)
|
||||||
|
|
||||||
|
for n in path_nodes:
|
||||||
|
node_snr = int.from_bytes(dbuf.read(1), byteorder="little", signed=True)
|
||||||
|
n["snr"] = node_snr / 4.0
|
||||||
|
|
||||||
# Add the final node (our device) with its SNR
|
# Add the final node (our device) with its SNR
|
||||||
final_snr_byte = data[12 + path_len * 2]
|
final_snr = int.from_bytes(dbuf.read(1), byteorder="little", signed=True) / 4.0
|
||||||
final_snr = (
|
|
||||||
final_snr_byte if final_snr_byte < 128 else final_snr_byte - 256
|
|
||||||
) / 4.0
|
|
||||||
path_nodes.append({"snr": final_snr})
|
path_nodes.append({"snr": final_snr})
|
||||||
|
|
||||||
res["path"] = path_nodes
|
res["path"] = path_nodes
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue