summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Rowberg <jeff@rowberg.net>2020-09-30 16:19:27 -0400
committerJeff Rowberg <jeff@rowberg.net>2020-09-30 16:19:27 -0400
commitb3c01bf992c6ba9890de1d2a6e1d80d9ab36db5f (patch)
treec546982c469726f6a658159f5eb94866ebc96dfb
parentd867871e6aa333014a77498b4ac96fdd1d3bf1d8 (diff)
downloadpyserial-git-b3c01bf992c6ba9890de1d2a6e1d80d9ab36db5f.tar.gz
Fix exception for composite serial number search on Windows
-rw-r--r--serial/tools/list_ports_windows.py23
1 files changed, 16 insertions, 7 deletions
diff --git a/serial/tools/list_ports_windows.py b/serial/tools/list_ports_windows.py
index 2c530e8..0b4a5b1 100644
--- a/serial/tools/list_ports_windows.py
+++ b/serial/tools/list_ports_windows.py
@@ -149,7 +149,7 @@ KEY_READ = 0x20019
MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH = 5
-def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0):
+def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0, last_serial_number=None):
""" Get the serial number of the parent of a device.
Args:
@@ -161,7 +161,7 @@ def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0):
# If the traversal depth is beyond the max, abandon attempting to find the serial number.
if depth > MAX_USB_DEVICE_TREE_TRAVERSAL_DEPTH:
- return ''
+ return '' if not last_serial_number else last_serial_number
# Get the parent device instance.
devinst = DWORD()
@@ -173,7 +173,7 @@ def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0):
# If there is no parent available, the child was the root device. We cannot traverse
# further.
if win_error == ERROR_NOT_FOUND:
- return ''
+ return '' if not last_serial_number else last_serial_number
raise ctypes.WinError(win_error)
@@ -194,14 +194,23 @@ def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0):
parentHardwareID_str,
re.I)
- vid = int(m.group(1), 16)
+ # return early if we have no matches (likely malformed serial, traversed too far)
+ if not m:
+ return '' if not last_serial_number else last_serial_number
+
+ vid = None
pid = None
serial_number = None
+ if m.group(1):
+ vid = int(m.group(1), 16)
if m.group(3):
pid = int(m.group(3), 16)
if m.group(7):
serial_number = m.group(7)
+ # store what we found as a fallback for malformed serial values up the chain
+ found_serial_number = serial_number
+
# Check that the USB serial number only contains alpha-numeric characters. It may be a windows
# device ID (ephemeral ID).
if serial_number and not re.match(r'^\w+$', serial_number):
@@ -209,17 +218,17 @@ def get_parent_serial_number(child_devinst, child_vid, child_pid, depth=0):
if not vid or not pid:
# If pid and vid are not available at this device level, continue to the parent.
- return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1)
+ return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1, found_serial_number)
if pid != child_pid or vid != child_vid:
# If the VID or PID has changed, we are no longer looking at the same physical device. The
# serial number is unknown.
- return ''
+ return '' if not last_serial_number else last_serial_number
# In this case, the vid and pid of the parent device are identical to the child. However, if
# there still isn't a serial number available, continue to the next parent.
if not serial_number:
- return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1)
+ return get_parent_serial_number(devinst, child_vid, child_pid, depth + 1, found_serial_number)
# Finally, the VID and PID are identical to the child and a serial number is present, so return
# it.