Add V1 protocol discovery and upgrade support
This commit is contained in:
1 parent
63a32aaf02
commit
d50be29246
5 files changed
+240
-6
No files matched your search
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""V1 工厂 TCP 命令客户端;发送任何命令都必须显式使用 --execute。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
|
||||
MAX_DATA = 16 * 1024 * 1024
|
||||
|
||||
|
||||
def receive_exact(sock: socket.socket, length: int) -> bytes:
|
||||
chunks = bytearray()
|
||||
while len(chunks) < length:
|
||||
part = sock.recv(length - len(chunks))
|
||||
if not part:
|
||||
raise ConnectionError("peer closed before complete V1 frame arrived")
|
||||
chunks.extend(part)
|
||||
return bytes(chunks)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("host", help="device IP selected from discovery results")
|
||||
parser.add_argument("command", help="V1 CMD, decimal or 0x-prefixed")
|
||||
parser.add_argument("--data", default="", help="UTF-8 JSON/text payload (omit for empty Data)")
|
||||
parser.add_argument("--timeout", type=float, default=8.0)
|
||||
parser.add_argument("--execute", action="store_true", help="actually send the command")
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
command = int(args.command, 0)
|
||||
payload = args.data.encode("utf-8")
|
||||
if not 0 <= command <= 0xFFFFFFFF:
|
||||
raise ValueError("CMD must fit uint32")
|
||||
if len(payload) > MAX_DATA:
|
||||
raise ValueError("request Data exceeds 16 MiB limit")
|
||||
if args.data:
|
||||
json.loads(args.data) # V1 factory command payloads are documented JSON.
|
||||
if not args.execute:
|
||||
print(json.dumps({"preflight_only": True, "host": args.host, "port": 4941,
|
||||
"command": "0x%08X" % command, "data_bytes": len(payload),
|
||||
"message": "No network connection opened; add --execute to send."}, ensure_ascii=False))
|
||||
return 0
|
||||
request = struct.pack("!II", command, len(payload)) + payload
|
||||
with socket.create_connection((args.host, 4941), timeout=args.timeout) as sock:
|
||||
sock.settimeout(args.timeout)
|
||||
sock.sendall(request)
|
||||
header = receive_exact(sock, 8)
|
||||
response_command, response_length = struct.unpack("!II", header)
|
||||
if response_length > MAX_DATA:
|
||||
raise ValueError("response Data exceeds 16 MiB limit")
|
||||
response = receive_exact(sock, response_length)
|
||||
result = {"request_command": "0x%08X" % command,
|
||||
"response_command": "0x%08X" % response_command,
|
||||
"response_length": response_length,
|
||||
"response_data": response.decode("utf-8", errors="replace")}
|
||||
print(json.dumps(result, ensure_ascii=False))
|
||||
if response_command != command:
|
||||
return 2
|
||||
return 0
|
||||
except (OSError, ValueError, ConnectionError, json.JSONDecodeError) as exc:
|
||||
print("V1 command error: %s" % exc, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user