Auto-detect the diag port in efs2.py
Probe each candidate serial port with a DIAG version request and keep the one that answers, interface 0 (-if00-) first, instead of hardcoding ttyUSB0. Use /dev/serial/by-id for stable naming; DIAGPORT overrides. Claude-Session: https://claude.ai/code/session_01Ctisr9uXe4H8XsscZ2exGE
This commit is contained in:
parent
8318606f34
commit
b42dc4c3f1
2 changed files with 58 additions and 9 deletions
|
|
@ -4,9 +4,7 @@
|
|||
Packet layouts and opcodes replicate JohnBel/EfsTools exactly. Used to
|
||||
back up and replace policyman RF-band config on a rooted Sony Xperia 1 VI.
|
||||
"""
|
||||
import sys, os, time, struct, serial
|
||||
|
||||
PORT = os.environ.get("DIAGPORT", "/dev/ttyUSB0")
|
||||
import sys, os, time, struct, glob, serial
|
||||
|
||||
DIAG_SUBSYS = 0x4B
|
||||
SUBSYS_EFS = 19
|
||||
|
|
@ -50,9 +48,57 @@ def hdlc_decode(frame):
|
|||
else: out.append(b)
|
||||
return bytes(out)
|
||||
|
||||
def _responds_to_diag(port, timeout=1.0):
|
||||
"""Return True if port answers a DIAG version request (cmd 0x00)."""
|
||||
try:
|
||||
s = serial.Serial(port, 115200, timeout=0.3)
|
||||
except Exception:
|
||||
return False
|
||||
try:
|
||||
s.reset_input_buffer()
|
||||
s.write(hdlc_encode([0x00]))
|
||||
buf, deadline = bytearray(), time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
b = s.read(1)
|
||||
if not b:
|
||||
continue
|
||||
if b[0] == 0x7E:
|
||||
if buf:
|
||||
dec = hdlc_decode(bytes(buf))
|
||||
buf = bytearray()
|
||||
if len(dec) >= 3 and dec[0] == 0x00 and \
|
||||
fcs16(dec[:-2]) == struct.unpack("<H", dec[-2:])[0]:
|
||||
return True
|
||||
else:
|
||||
buf.append(b[0])
|
||||
return False
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
def find_diag_port():
|
||||
"""Find the DIAG serial port. DIAGPORT wins; otherwise probe candidates,
|
||||
interface 0 (-if00-) first, and return the one that answers DIAG."""
|
||||
env = os.environ.get("DIAGPORT")
|
||||
if env:
|
||||
return env
|
||||
candidates = (sorted(glob.glob("/dev/serial/by-id/*-if00-port0")) +
|
||||
sorted(glob.glob("/dev/serial/by-id/*")) +
|
||||
sorted(glob.glob("/dev/ttyUSB*")))
|
||||
seen = set()
|
||||
for p in candidates:
|
||||
real = os.path.realpath(p)
|
||||
if real in seen:
|
||||
continue
|
||||
seen.add(real)
|
||||
if _responds_to_diag(p):
|
||||
return p
|
||||
raise IOError("no responding DIAG port found; is the phone in diag mode "
|
||||
"(setprop sys.usb.config diag,serial_cdev,rmnet,adb)?")
|
||||
|
||||
class Diag:
|
||||
def __init__(self, port=PORT):
|
||||
self.s = serial.Serial(port, 115200, timeout=0.4)
|
||||
def __init__(self, port=None):
|
||||
self.port = port or find_diag_port()
|
||||
self.s = serial.Serial(self.port, 115200, timeout=0.4)
|
||||
self.s.reset_input_buffer()
|
||||
|
||||
def _read_frame(self, timeout=4.0):
|
||||
|
|
@ -206,6 +252,7 @@ BACKUP = "/tmp/claude-1000/-home-grmrgecko-Downloads-XperiFirm-5-8-1--by-Igor-Ei
|
|||
def main():
|
||||
cmd = sys.argv[1] if len(sys.argv) > 1 else "probe"
|
||||
d = Diag()
|
||||
print("using diag port %s" % d.port)
|
||||
ver = d.hello()
|
||||
print("EFS hello ok, version=%d" % ver)
|
||||
|
||||
|
|
|
|||
|
|
@ -115,12 +115,14 @@ be redone.
|
|||
'setprop sys.usb.config diag,serial_cdev,rmnet,adb'`. Phone re-enumerates
|
||||
as USB `05c6:9091` (adb survives). Bind the serial driver (needs root on
|
||||
the PC): `sudo modprobe option && echo 05c6 9091 | sudo tee
|
||||
/sys/bus/usb-serial/drivers/option1/new_id`. Diag port = `/dev/ttyUSB0`
|
||||
(the one that answers a DIAG version request; ttyUSB1 is silent).
|
||||
/sys/bus/usb-serial/drivers/option1/new_id`. The diag channel is USB
|
||||
interface 0, stable as `/dev/serial/by-id/usb-Sony_XQ-EC72_*-if00-port0`
|
||||
(maps to a ttyUSB whose number is not stable). efs2.py auto-detects it by
|
||||
probing each port with a DIAG version request; set `DIAGPORT` to override.
|
||||
3. Talk EFS2 over DIAG. EfsTools (JohnBel) is the usual tool but its
|
||||
libnserial hits EIO on the option-driver port; the reliable path was a
|
||||
small pyserial EFS2 client (HDLC + FCS-16, subsys 0x4B/EFS 19). Scripts
|
||||
kept at `~/.../scratchpad/efs2.py` (+ `diag_probe.py`). It does:
|
||||
small pyserial EFS2 client (HDLC + FCS-16, subsys 0x4B/EFS 19). Script is
|
||||
`5g-policyman/efs2.py` in this skill. It does:
|
||||
hello → list `/policyman` → **back up** the 3 files → write new ones
|
||||
(unlink then open `O_WRONLY|O_CREAT` perm 0777, 1 KB write chunks) →
|
||||
read back and byte-compare to verify.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue