feat(e10): run on Windows as well as Linux
Serial access moves behind open_port(), with a termios backend on POSIX and a
Win32 backend reached through ctypes. Deliberately no pyserial: these tools
have to run on locked-down, air-gapped shopfloor machines where installing a
package is a project of its own.
Verified on a real controller from both a Linux laptop and a Windows 11 PC.
Three things that made this harder than it should have been, all now handled:
- CreateFileW returns a HANDLE, which is 64-bit. Without an explicit restype
ctypes truncates it to c_int. The open then appears to succeed and every
read and write silently operates on a bogus handle, which looks exactly
like a dead cable. Every kernel32 call now declares argtypes and restype.
- Defaulting to a fixed COM number was actively harmful. A wrong-but-real
port opens without error and answers nothing, so defaulting to COM3 while
the adapter was on COM4 produced the same silent symptom. Windows now
auto-picks only when exactly one port looks like a USB virtual COM port,
and otherwise refuses and lists what it found.
- COM10 and above need the \\.\ prefix, which is harmless on COM1-9, so it
is always applied.
Adds two diagnostics, because "no response" has too many possible causes to
guess at:
ports every serial port that actually exists. On Windows this reads
SERIALCOMM from the registry, so a port absent here does not exist
now, whatever Device Manager showed last week.
doctor walks the layers - discovery, open, write, read - and reports which
one fails, including a warning when the configured port is an
onboard one while a USB adapter is present.
Port selection is -d, then $E10_PORT, then the safe auto-pick. Friendlier
errors on both platforms for a missing port or a permissions problem.
This commit is contained in:
@@ -302,8 +302,10 @@ def main():
|
||||
help="operator input, in prompt order. repeatable.")
|
||||
parser.add_argument("--no-clear", action="store_true",
|
||||
help="skip the clear-fields pass")
|
||||
parser.add_argument("--e10", metavar="DEVICE",
|
||||
help="also drive a real e10 on this serial device")
|
||||
parser.add_argument("--e10", metavar="DEVICE", nargs="?", const="",
|
||||
help="also drive a real e10. Give a port, or pass the"
|
||||
" flag bare to use $E10_PORT / the platform"
|
||||
" default.")
|
||||
parser.add_argument("--pattern",
|
||||
help="override the pattern name from the ^ line."
|
||||
" Useful when the e10 file is named differently"
|
||||
@@ -383,8 +385,9 @@ def drive_e10(seq, args):
|
||||
e10mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(e10mod)
|
||||
|
||||
print("\n DRIVING THE REAL CONTROLLER on %s" % args.e10)
|
||||
with e10mod.E10(args.e10, timeout=5.0) as dev:
|
||||
port = args.e10 or e10mod.default_port()
|
||||
print("\n DRIVING THE REAL CONTROLLER on %s" % port)
|
||||
with e10mod.E10(port, timeout=5.0) as dev:
|
||||
for label, raw in seq:
|
||||
type_char, data = decode_frame(raw)
|
||||
action, payload = translate(type_char, data)
|
||||
|
||||
Reference in New Issue
Block a user