Skip to content

Commit

Permalink
Merge pull request #1077 from flit/bugfix/probe_none_serial
Browse files Browse the repository at this point in the history
CMSIS-DAP: handle pyusb returning None for USB serial number
  • Loading branch information
flit authored Feb 14, 2021
2 parents 7abe4c0 + 7426000 commit 7dccf5c
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 10 deletions.
20 changes: 19 additions & 1 deletion pyocd/probe/pydapaccess/interface/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# pyOCD debugger
# Copyright (c) 2019-2020 Arm Limited
# Copyright (c) 2019-2021 Arm Limited
# Copyright (c) 2021 mentha
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,6 +16,8 @@
# limitations under the License.

import usb.util
from hashlib import sha1
from base64 import b32encode

# USB class codes.
USB_CLASS_COMPOSITE = 0x00
Expand Down Expand Up @@ -106,3 +109,18 @@ def check_ep(interface, ep_index, ep_dir, ep_type):
ep = interface[ep_index]
return (usb.util.endpoint_direction(ep.bEndpointAddress) == ep_dir) \
and (usb.util.endpoint_type(ep.bmAttributes) == ep_type)

def generate_device_unique_id(dev):
"""! @brief Generate a semi-stable unique ID from a pyusb device.
This function is intended to be used in cases where a device does not provide a serial number
string. pyocd still needs a valid unique ID so the device can be selected from amongst multiple
connected devices. The algorithm used here generates an ID that is stable for a given device as
long as it is connected to the same USB port.
@param dev pyusb device object.
@return 16-character string.
"""
s = "{:4x},{:4x},{:s},{:s}".format(dev.idProduct, dev.idVendor, dev.bus, dev.address)
return b32encode(sha1(s.encode()).digest()).decode('ascii')[:16]

12 changes: 8 additions & 4 deletions pyocd/probe/pydapaccess/interface/pyusb_backend.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# pyOCD debugger
# Copyright (c) 2006-2020 Arm Limited
# Copyright (c) 2006-2021 Arm Limited
# Copyright (c) 2020 Patrick Huesmann
# Copyright (c) 2021 mentha
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -28,6 +29,7 @@
filter_device_by_class,
is_known_cmsis_dap_vid_pid,
check_ep,
generate_device_unique_id,
)
from ..dap_access_api import DAPAccessIntf

Expand Down Expand Up @@ -167,9 +169,9 @@ def get_all_connected_interfaces():
new_board = PyUSB()
new_board.vid = board.idVendor
new_board.pid = board.idProduct
new_board.product_name = board.product
new_board.vendor_name = board.manufacturer
new_board.serial_number = board.serial_number
new_board.product_name = board.product or hex(board.idProduct)
new_board.vendor_name = board.manufacturer or hex(board.idVendor)
new_board.serial_number = board.serial_number or generate_device_unique_id(board)
boards.append(new_board)

return boards
Expand Down Expand Up @@ -354,6 +356,8 @@ def __call__(self, dev):
if cmsis_dap_interface is None:
return False
if self._serial is not None:
if self._serial == "" and dev.serial_number is None:
return True
if self._serial != dev.serial_number:
return False
return True
12 changes: 8 additions & 4 deletions pyocd/probe/pydapaccess/interface/pyusb_v2_backend.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# pyOCD debugger
# Copyright (c) 2019-2020 Arm Limited
# Copyright (c) 2019-2021 Arm Limited
# Copyright (c) 2021 mentha
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -27,6 +28,7 @@
filter_device_by_class,
is_known_cmsis_dap_vid_pid,
check_ep,
generate_device_unique_id,
)
from ..dap_access_api import DAPAccessIntf
from ... import common
Expand Down Expand Up @@ -185,9 +187,9 @@ def get_all_connected_interfaces():
new_board = PyUSBv2()
new_board.vid = board.idVendor
new_board.pid = board.idProduct
new_board.product_name = board.product
new_board.vendor_name = board.manufacturer
new_board.serial_number = board.serial_number
new_board.product_name = board.product or hex(board.idProduct)
new_board.vendor_name = board.manufacturer or hex(board.idVendor)
new_board.serial_number = board.serial_number or generate_device_unique_id(board)
boards.append(new_board)

return boards
Expand Down Expand Up @@ -336,6 +338,8 @@ def __call__(self, dev):
return False

if self._serial is not None:
if self._serial == "" and dev.serial_number is None:
return True
if self._serial != dev.serial_number:
return False
return True
2 changes: 1 addition & 1 deletion test/probeserver_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def run(self, board):
try:
result = self.test_function(board.unique_id, self.n)
except Exception as e:
result = GdbTestResult()
result = ProbeserverTestResult()
result.passed = False
print("Exception %s when testing board %s" %
(e, board.unique_id))
Expand Down

0 comments on commit 7dccf5c

Please sign in to comment.