Keep native Espressif USB boot control lines released in host tests

This commit is contained in:
mikecarper committed 2026-10-26 18:17:30 -07:00
1 parent ec4aba8a1c
commit 2369a3d28c
3 files changed
+18 -11

No files matched your search

+3
View File
@@ -45,6 +45,9 @@ commands normally. A detected USB disconnect/reset also ends the session.
UART-to-USB adapters without a disconnect signal may require RETURN.
If the radio2 settings change mid-session, USB stays quarantined until RETURN
or disconnect, so leftover binary bytes cannot become CLI commands.
For Espressif USB-Serial/JTAG (`303A:1001`), open the host port with DTR and
RTS deasserted; those lines control boot/reset selection. Other USB CDC
devices, including nRF52/TinyUSB, retain their normal DTR handling.
ESP32 also supports `set kiss.transport tcp`. Enable station WiFi separately
and connect to its address on TCP **5004**. The service accepts one client,
+4 -2
View File
@@ -16,11 +16,13 @@ _run_sequences = itertools.count(secrets.randbelow(0x3fffffff) + 1)
def configure_session(port):
# Native Espressif/Seeed/Adafruit USB and CP2102/CH340 bridges differ in DTR semantics.
# DTR keeps the native session active; on a bridge it can drive BOOT/GPIO0.
# ESP32-C3/S3 USB Serial/JTAG (303A:1001) maps asserted DTR to IO0.
# Leave it released across a firmware reboot. TinyUSB/nRF52 CDC still
# needs DTR; UART bridges can also drive BOOT/GPIO0 and keep it released.
port.rts = False
device = os.path.realpath(str(port.port)).casefold()
port.dtr = any(info.vid in (0x303A, 0x2886, 0x239A)
and (info.vid, getattr(info, "pid", None)) != (0x303A, 0x1001)
and os.path.realpath(str(info.device)).casefold() == device
for info in list_ports.comports())
+11 -9
View File
@@ -98,14 +98,15 @@ class ResultReaderTests(unittest.TestCase):
master, slave = os.openpty()
try:
device = os.ttyname(slave)
for vid, expected in ((0x10C4, False), (0x1A86, False),
(0x303A, True), (0x2886, True), (0x239A, True)):
with self.subTest(vid=vid):
for vid, pid, expected in ((0x10C4, 0xEA60, False), (0x1A86, 0x7523, False),
(0x303A, 0x1001, False), (0x303A, 0x4001, True),
(0x2886, 0x8045, True), (0x239A, 0x8029, True)):
with self.subTest(vid=vid, pid=pid):
port = PosixModemSerial()
port.port = device
try:
with patch("profile_switch.list_ports.comports", return_value=[
SimpleNamespace(device=device, vid=vid)]):
SimpleNamespace(device=device, vid=vid, pid=pid)]):
open_session(port)
self.assertFalse(port.has_reset_transition(), port.modem_edges)
self.assertEqual(port.modem_lines, {"dtr": expected, "rts": False})
@@ -170,11 +171,12 @@ class ResultReaderTests(unittest.TestCase):
self.assertTrue(result["transport_recovered"])
def test_native_usb_and_bridge_have_distinct_control_lines(self):
for vid, expected in ((0x303A, True), (0x2886, True), (0x239A, True),
(0x1A86, False), (0x10C4, False), (None, False)):
for vid, pid, expected in ((0x303A, 0x1001, False), (0x303A, 0x4001, True),
(0x2886, 0x8045, True), (0x239A, 0x8029, True),
(0x1A86, 0x7523, False), (0x10C4, 0xEA60, False), (None, None, False)):
port = SessionPort("test")
with patch("profile_switch.list_ports.comports", return_value=[
SimpleNamespace(device="TEST", vid=vid),
SimpleNamespace(device="TEST", vid=vid, pid=pid),
SimpleNamespace(device="different", vid=0x303A)]):
configure_session(port)
self.assertFalse(port.is_open)
@@ -196,9 +198,9 @@ class ResultReaderTests(unittest.TestCase):
bridge_id = by_id / "usb-Silicon_Labs_CP2102-if00-port0"
native_id.symlink_to(native)
bridge_id.symlink_to(bridge)
inventory = [SimpleNamespace(device=str(native), vid=0x303A),
inventory = [SimpleNamespace(device=str(native), vid=0x303A, pid=0x1001),
SimpleNamespace(device=str(bridge), vid=0x10C4)]
for device, expected in ((native_id, True), (bridge_id, False)):
for device, expected in ((native_id, False), (bridge_id, False)):
with self.subTest(device=device.name):
port = SessionPort(str(device))
with patch("profile_switch.list_ports.comports", return_value=inventory):