Skip to content

Commit 12bbc19

Browse files
authored
Rework clear_status status to support newer STM32 devices, drop Python 3.7 and 3.8 support (#10)
* Add `_dfuse_download_with_retry` to only clear status on retry * Update CI workflows to test against Python 3.9, 3.11, and 3.12 * Update minimum required version of Python to 3.9 * Switch from `pkg_resources` to `importlib_metadata` for reading package version
1 parent eaae91d commit 12bbc19

File tree

8 files changed

+51
-16
lines changed

8 files changed

+51
-16
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
matrix:
1414
os: [ ubuntu-latest, macos-latest ]
15-
python-version: [ 3.7, 3.8, 3.9 ]
15+
python-version: [ 3.9, 3.11, 3.12 ]
1616
steps:
1717
- uses: actions/checkout@v2
1818
- name: Setup Python ${{ matrix.python-version }}

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.7.13
1+
3.12.2

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.0.0] - 2024-10-21
9+
10+
- Drop support for Python 3.7 and 3.8.
11+
- Migrate from `pkg_resources` to `importlib_metadata`.
12+
- Rework `_dfuse_download` slightly: Instead of always clearing the status
13+
before starting the download, only do it if a pipe error is detected. In newer
14+
STM32 devices, clearing the status seems to make the first download fail.
15+
816
## [1.0.2] - 2022-08-15
917

1018
- Ignore all `USBError` exceptions when exiting DFU mode.

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ VENV_PYTHON := $(VENV_DIR)/bin/python
44
$(VENV_DIR):
55
@echo "Setting up virtual environment and pre-commit hooks..."
66
@python -m venv $@
7-
@$(VENV_PYTHON) -m pip install --upgrade --quiet pip -i https://pypi.python.org/simple
8-
@$(VENV_PYTHON) -m pip install --upgrade --quiet --editable ".[dev]" -i https://pypi.python.org/simple
7+
@$(VENV_PYTHON) -m pip install --upgrade --quiet pip setuptools
8+
@$(VENV_PYTHON) -m pip install --upgrade --quiet --editable ".[dev]"
99
@$(VENV_PYTHON) -m pre_commit install --install-hooks
1010
@echo "Setup complete."
1111

pyfu_usb/__init__.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,6 @@ def _dfuse_download(
8989
xfer_size: Transfer size to use when downloading.
9090
start_address: Start address of data in device memory.
9191
"""
92-
# Clear status, possibly leftover from previous transaction
93-
dfu.clear_status(dev, interface)
94-
9592
for segment_num, segment in enumerate(
9693
descriptor.get_memory_layout(dev, interface)
9794
):
@@ -108,7 +105,8 @@ def _dfuse_download(
108105
dfuse.page_erase(dev, interface, page_addr)
109106

110107
# Download data
111-
with Progress() as progress:
108+
progress = Progress()
109+
with progress:
112110
task = _make_progress_bar(progress, len(data))
113111

114112
bytes_downloaded = 0
@@ -141,6 +139,33 @@ def _dfuse_download(
141139
logger.warning("Ignoring USB error when exiting DFU: %s", err)
142140

143141

142+
def _dfuse_download_with_retry(
143+
dev: usb.core.Device,
144+
interface: int,
145+
data: bytes,
146+
xfer_size: int,
147+
start_address: int,
148+
) -> None:
149+
"""Download data to DfuSe device, with a retry to clear any leftover status.
150+
151+
Args:
152+
dev: USB device in DFU mode.
153+
interface: USB device interface.
154+
data: Binary data to download.
155+
xfer_size: Transfer size to use when downloading.
156+
start_address: Start address of data in device memory.
157+
"""
158+
try:
159+
_dfuse_download(dev, interface, data, xfer_size, start_address)
160+
except usb.core.USBError as err:
161+
if "pipe error" in str(err).lower():
162+
logger.debug("Clearing status before DfuSe download")
163+
dfu.clear_status(dev, interface)
164+
_dfuse_download(dev, interface, data, xfer_size, start_address)
165+
else:
166+
raise err
167+
168+
144169
def _dfu_download(
145170
dev: usb.core.Device, interface: int, data: bytes, xfer_size: int
146171
) -> None:
@@ -153,7 +178,8 @@ def _dfu_download(
153178
xfer_size: Transfer size to use when downloading.
154179
"""
155180
# Download data
156-
with Progress() as progress:
181+
progress = Progress()
182+
with progress:
157183
task = _make_progress_bar(progress, len(data))
158184

159185
transaction = 0
@@ -270,7 +296,7 @@ def download(
270296
if dfu_desc.bcdDFUVersion == dfuse.DFUSE_VERSION_NUMBER:
271297
if address is None:
272298
raise ValueError("Must provide address for DfuSe")
273-
_dfuse_download(
299+
_dfuse_download_with_retry(
274300
dev, interface, data, dfu_desc.wTransferSize, address
275301
)
276302
else:

pyfu_usb/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import logging
66
import sys
77

8-
import pkg_resources
8+
import importlib_metadata
99
import usb
1010
from rich.logging import RichHandler
1111

@@ -99,7 +99,7 @@ def cli(args: argparse.Namespace) -> int:
9999

100100
# Get pyfu-usb verion
101101
if args.version:
102-
logger.info(pkg_resources.require("pyfu_usb")[0].version)
102+
logger.info(importlib_metadata.version("pyfu_usb"))
103103
return 0
104104

105105
# Parse VID/PID if provided

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ strict = true
66
ignore_missing_imports = true
77

88
[tool.pylint.MASTER]
9-
disable = "W0511"
9+
disable = "W0511,R0917,C0209"
1010

1111
[tool.pylint.FORMAT]
1212
max-line-length = 80

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,18 @@ def long_description():
1818
name="pyfu-usb",
1919
author="Block, Inc.",
2020
license="MIT",
21-
version="1.0.2",
21+
version="2.0.0",
2222
description="Python USB firmware update library.",
2323
long_description=long_description(),
2424
long_description_content_type="text/markdown",
2525
url="https://github.com/square/pyfu-usb",
2626
packages=setuptools.find_packages(),
27-
python_requires=">=3.7",
27+
python_requires=">=3.9",
2828
package_data={
2929
"pyfu_usb": ["py.typed"],
3030
},
3131
install_requires=[
32+
"importlib-metadata",
3233
"pyusb>=1.0.2",
3334
"rich>=12.2",
3435
],
@@ -37,7 +38,7 @@ def long_description():
3738
"black~=22.3.0",
3839
"mypy==0.942",
3940
"types-setuptools~=57.4.14",
40-
"pylint~=2.7.0",
41+
"pylint~=3.3.1",
4142
"pre-commit~=2.18.1",
4243
"wheel~=0.37.1",
4344
"twine~=4.0.0",

0 commit comments

Comments
 (0)