Skip to content

Commit 5dd3dcc

Browse files
feat(esptool): allow picking UART by VID/PID/Name
Enable user to specify USB VID, USB PID, or port name to filter the com port list before checking for ESP chips. Implements espressif#987
1 parent 3731e11 commit 5dd3dcc

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

docs/en/esptool/advanced-options.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,21 @@ An example of this is available in the :ref:`merge_bin <merge-bin>` command desc
117117
.. note:: PowerShell users
118118

119119
Because of `splatting <https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting?view=powershell-7.3>`__ in PowerShell (method of passing a collection of parameter values to a command as a unit) there is a need to add quotes around @filename.txt ("@filename.txt") to be correctly resolved.
120+
121+
Filtering serial ports
122+
----------------------
123+
.. _filtering_serial_ports:
124+
125+
``--port-filter <FilterType>=<FilterValue>`` allows limiting ports that will be tried. This can be useful when esptool is run on a system
126+
with many serial ports. There are a few different types that can be combined. A port must match all specified FilterTypes, and must match
127+
at least one FilterValue for each specified FilterType to be considered. Example filter configurations:
128+
129+
.. list::
130+
131+
* ``--port-filter vid=0x303A`` matches ports with the Espressif USB VID.
132+
* ``--port-filter vid=0x303A --port-filter vid=0x0403`` matches Espressif and FTDI ports by VID.
133+
* ``--port-filter vid=0x303A --port-filter pid=0x0002`` matches Espressif ESP32-S2 in USB-OTG mode by VID and PID.
134+
* ``--port-filter vid=0x303A --port-filter pid=0x1001`` matches Espressif USB-Serial/JTAG unit used by multiple chips by VID and PID.
135+
* ``--port-filter name=ttyUSB`` matches ports where the port name contains the specified text.
136+
137+
See also the `Espressif USB customer-allocated PID repository <https://github.com/espressif/usb-pids>`_

esptool/__init__.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ def main(argv=None, esp=None):
123123
default=os.environ.get("ESPTOOL_BAUD", ESPLoader.ESP_ROM_BAUD),
124124
)
125125

126+
parser.add_argument(
127+
"--port-filter",
128+
action="append",
129+
help="Serial port device filter, can be vid=NUMBER, pid=NUMBER, name=SUBSTRING",
130+
type=str,
131+
default=[],
132+
)
133+
126134
parser.add_argument(
127135
"--before",
128136
help="What to do before connecting to the chip",
@@ -690,6 +698,23 @@ def add_spi_flash_subparsers(
690698

691699
StubFlasher.set_preferred_stub_subdir(args.stub_version)
692700

701+
# Parse filter arguments into separate lists
702+
args.filterVids = []
703+
args.filterPids = []
704+
args.filterNames = []
705+
for f in args.port_filter:
706+
kvp = f.split("=")
707+
if len(kvp) != 2:
708+
raise FatalError("Option --port-filter argument must consist of key=value")
709+
if kvp[0] == "vid":
710+
args.filterVids.append(arg_auto_int(kvp[1]))
711+
elif kvp[0] == "pid":
712+
args.filterPids.append(arg_auto_int(kvp[1]))
713+
elif kvp[0] == "name":
714+
args.filterNames.append(kvp[1])
715+
else:
716+
raise FatalError("Option --port-filter argument key not recognized")
717+
693718
# operation function can take 1 arg (args), 2 args (esp, arg)
694719
# or be a member function of the ESPLoader class.
695720

@@ -725,7 +750,7 @@ def add_spi_flash_subparsers(
725750
initial_baud = args.baud
726751

727752
if args.port is None:
728-
ser_list = get_port_list()
753+
ser_list = get_port_list(args.filterVids, args.filterPids, args.filterNames)
729754
print("Found %d serial ports" % len(ser_list))
730755
else:
731756
ser_list = [args.port]
@@ -1010,21 +1035,29 @@ def arg_auto_chunk_size(string: str) -> int:
10101035
return num
10111036

10121037

1013-
def get_port_list():
1038+
def get_port_list(vids=[], pids=[], names=[]):
10141039
if list_ports is None:
10151040
raise FatalError(
10161041
"Listing all serial ports is currently not available. "
10171042
"Please try to specify the port when running esptool.py or update "
10181043
"the pyserial package to the latest version"
10191044
)
1020-
port_list = sorted(ports.device for ports in list_ports.comports())
1021-
if sys.platform == "darwin":
1022-
port_list = [
1023-
port
1024-
for port in port_list
1025-
if not port.endswith(("Bluetooth-Incoming-Port", "wlan-debug"))
1026-
]
1027-
return port_list
1045+
ports = []
1046+
for port in list_ports.comports():
1047+
if sys.platform == "darwin" and port.device.endswith(
1048+
("Bluetooth-Incoming-Port", "wlan-debug")
1049+
):
1050+
continue
1051+
if vids and (port.vid is None or port.vid not in vids):
1052+
continue
1053+
if pids and (port.pid is None or port.pid not in pids):
1054+
continue
1055+
if names and (
1056+
port.name is None or all(name not in port.name for name in names)
1057+
):
1058+
continue
1059+
ports.append(port.device)
1060+
return sorted(ports)
10281061

10291062

10301063
def expand_file_arguments(argv):

0 commit comments

Comments
 (0)