pyocd / pyocd/pyOCD

Flashing a device occasionally crashes pyOCD when multiple devices are connected

Open
#711 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.5k
Forks
560
Avg merge
1h 41m
Merged PRs (30d)
3

Description

OS: MacOS 10.12.16
pyOCD: 0.21.0
Devices: nRF51-DK, F042k6, Disco-L475, Nucleo-F446, etc.

When multiple devices are connected, the uid switch needs to be provided in order to target the correct device during a flash operation. e.g.:

./pyocd flash --uid 1100021844203120324C46383230353138303035B9C7DFD8 --target nrf51 --erase=chip "/Users/bob/Mbed Programs/mbed-os-example-blinky-tes/BUILD/NRF51_DK/ARMC6/mbed-os-example-blinky.hex"

This can often fail with the following error:

0000140:ERROR:__main__:uncaught exception: 'utf16' codec can't decode byte 0x6c in position 30: truncated data
Traceback (most recent call last):
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/__main__.py", line 304, in run
    self._commands[self._args.cmd]()
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/__main__.py", line 369, in do_flash
    **convert_session_options(self._args.options))
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/core/helpers.py", line 141, in session_with_chosen_probe
    allProbes = ConnectHelper.get_all_connected_probes(blocking=blocking, unique_id=board_id)
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/core/helpers.py", line 78, in get_all_connected_probes
    allProbes = DebugProbeAggregator.get_all_connected_probes(unique_id=unique_id)
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/aggregator.py", line 32, in get_all_connected_probes
    probes += cls.get_all_connected_probes()
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/cmsis_dap_probe.py", line 73, in get_all_connected_probes
    return [cls(dev) for dev in DAPAccess.get_connected_devices()]
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/pydapaccess/dap_access_cmsis_dap.py", line 449, in get_connected_devices
    all_interfaces = _get_interfaces()
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/pydapaccess/dap_access_cmsis_dap.py", line 56, in _get_interfaces
    interfaces += INTERFACE[USB_BACKEND_V2].get_all_connected_interfaces()
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/pydapaccess/interface/pyusb_v2_backend.py", line 178, in get_all_connected_interfaces
    for board in all_devices:
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/usb/core.py", line 1249, in device_iter
    if _interop._all(tests) and (custom_match is None or custom_match(d)):
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/pydapaccess/interface/pyusb_v2_backend.py", line 274, in __call__
    cmsis_dap_interface = usb.util.find_descriptor(config, custom_match=match_cmsis_dap_interface_name)
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/usb/util.py", line 190, in find_descriptor
    return _interop._next(desc_iter(**args))
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/usb/_interop.py", line 66, in _next
    return next(iter)
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/usb/util.py", line 183, in desc_iter
    if _interop._all(tests) and (custom_match is None or custom_match(d)):
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/pyocd/probe/pydapaccess/interface/pyusb_v2_backend.py", line 256, in match_cmsis_dap_interface_name
    interface_name = usb.util.get_string(desc.device, desc.iInterface)
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/site-packages/usb/util.py", line 330, in get_string
    return buf[2:buf[0]].tostring().decode('utf-16-le')
  File "/Users/robmor01/mbed-studio-tools/python/lib/python2.7/encodings/utf_16_le.py", line 16, in decode
    return codecs.utf_16_le_decode(input, errors, True)
UnicodeDecodeError: 'utf16' codec can't decode byte 0x6c in position 30: truncated data

When this happens, the device is left in an odd state and can only be recovered by flashing without the uid switch (and other devices disconnected so it becomes the default) or by using mass storage device flash.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the flash command with multiple connected devices, then start at pyocd/probe/pydapaccess/interface/pyusb_v2_backend.py and follow get_connected_devices() through the USB descriptor lookup shown in the traceback. Use the reported UnicodeDecodeError as the failure signal; done means selecting a device by uid no longer crashes and the targeted device can be flashed.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, python
Domain
devtools, embedded-iot
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.