65 lines
2.2 KiB
Python
Executable File
65 lines
2.2 KiB
Python
Executable File
#!/home/noise/.local/share/uv/tools/powermon/bin/python
|
|
"""One-shot diagnostic: autodetect the currently-plugged FTDI, then
|
|
run 3 tests and print results.
|
|
|
|
1. Passive listen 10 s @ 9600 baud.
|
|
2. Passive listen 10 s @ 19200 baud.
|
|
3. Active probe: send canonical 7E 01 01 00 FE 0D at 9600, wait 2 s.
|
|
|
|
Usage: port-probe <label>
|
|
"""
|
|
import glob, sys, time, serial
|
|
|
|
def autodetect():
|
|
hits = sorted(glob.glob("/dev/serial/by-id/usb-FTDI_*"))
|
|
return hits[0] if hits else None
|
|
|
|
def passive(port, baud, seconds):
|
|
with serial.Serial(port, baud, bytesize=8, parity="N", stopbits=1, timeout=0.25) as p:
|
|
p.reset_input_buffer()
|
|
deadline = time.monotonic() + seconds
|
|
buf = bytearray()
|
|
while time.monotonic() < deadline:
|
|
chunk = p.read(512)
|
|
if chunk: buf.extend(chunk)
|
|
return bytes(buf)
|
|
|
|
def probe(port, baud):
|
|
frame = bytes([0x7E, 0x01, 0x01, 0x00, 0xFE, 0x0D])
|
|
with serial.Serial(port, baud, bytesize=8, parity="N", stopbits=1, timeout=0.25) as p:
|
|
p.reset_input_buffer()
|
|
p.write(frame)
|
|
deadline = time.monotonic() + 2.0
|
|
buf = bytearray()
|
|
while time.monotonic() < deadline:
|
|
chunk = p.read(512)
|
|
if chunk: buf.extend(chunk)
|
|
return bytes(buf)
|
|
|
|
def modbus_q_count(buf):
|
|
return sum(1 for i in range(len(buf) - 7)
|
|
if buf[i+1] == 0x03 and buf[i+2] == 0 and buf[i+3] == 0 and buf[i+5] == 0x2f)
|
|
|
|
def main():
|
|
label = sys.argv[1] if len(sys.argv) > 1 else "test"
|
|
port = autodetect()
|
|
if port is None:
|
|
print("ERROR: no FTDI adapter visible at /dev/serial/by-id/usb-FTDI_*")
|
|
sys.exit(2)
|
|
print(f"=== {label} ===")
|
|
print(f"adapter: {port}")
|
|
for baud in (9600, 19200):
|
|
buf = passive(port, baud, 10)
|
|
print(f"\npassive @ {baud:>5}: {len(buf):4d} bytes ({len(buf)/10:4.1f} B/s)"
|
|
f" 7E={buf.count(0x7E)} 0D={buf.count(0x0D)}"
|
|
+ (f" mb_queries≈{modbus_q_count(buf)}" if baud == 19200 else ""))
|
|
if buf:
|
|
print(f" first 80: {bytes(buf[:80]).hex(' ')}")
|
|
buf = probe(port, 9600)
|
|
print(f"\n7E probe @ 9600: reply {len(buf)} bytes")
|
|
if buf:
|
|
print(f" hex: {bytes(buf).hex(' ')}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|