From 07e95dd94f0978561954a1b17e1fe5d1504d0608 Mon Sep 17 00:00:00 2001 From: Dmytro Yaroshenko <73843436+o-murphy@users.noreply.github.com> Date: Mon, 29 Apr 2024 11:46:23 +0300 Subject: [PATCH] trying to implement main.py --- pydfuutil/__main__.py | 140 ++++++++++++++++++++++++++---------------- pydfuutil/dfu.py | 80 ++++++++++++++---------- 2 files changed, 135 insertions(+), 85 deletions(-) diff --git a/pydfuutil/__main__.py b/pydfuutil/__main__.py index 2e356dd..e98c878 100644 --- a/pydfuutil/__main__.py +++ b/pydfuutil/__main__.py @@ -5,8 +5,10 @@ """ import argparse import errno +import io import re import sys +from enum import IntEnum from typing import Any, Callable import usb.core @@ -16,6 +18,7 @@ MAX_DESC_STR_LEN = 253 VERBOSE = False + # TODO: not implemented yet @@ -465,7 +468,7 @@ def usb_get_any_descriptor(dev: usb.core.Device, # Search through the configuration descriptor list ret = find_descriptor(cbuf, desc_type, desc_index, resbuf, res_len) if ret > 1: - if verbose: + if VERBOSE: print("Found descriptor in complete configuration descriptor list") return ret @@ -517,45 +520,27 @@ def get_cached_extra_descriptor(dev: usb.core.Device, if ret > 1: break - if ret < 2 and verbose: + if ret < 2 and VERBOSE: print("Did not find cached descriptor") return ret -def help_() -> None: - print( - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -v --verbose\t\t\tPrint verbose debug statements\n" - " -l --list\t\t\tList the currently attached DFU capable USB devices\n" - ) - print( - " -e --detach\t\t\tDetach the currently attached DFU capable USB devices\n" - " -d --device vendor:product\tSpecify Vendor/Product ID of DFU device\n" - " -p --path bus-port. ... .port\tSpecify path to DFU device\n" - " -c --cfg config_nr\t\tSpecify the Configuration of DFU device\n" - " -i --intf intf_nr\t\tSpecify the DFU Interface number\n" - " -a --alt alt\t\t\tSpecify the Altsetting of the DFU Interface\n" - "\t\t\t\tby name or by number\n" - ) - print( - " -t --transfer-size\t\tSpecify the number of bytes per USB Transfer\n" - " -U --upload file\t\tRead firmware from device into \n" - " -D --download file\t\tWrite firmware from into device\n" - " -R --reset\t\t\tIssue USB Reset signalling once we're finished\n" - " -s --dfuse-address address\tST DfuSe mode, specify target address for\n" - "\t\t\t\traw file download or upload. Not applicable for\n" - "\t\t\t\tDfuSe file (.dfu) downloads\n" - ) - - VERSION = (f"{__version__}\n\n" f"('Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc.\n')" f"{__copyright__}\n" f"This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n')") +class Mode(IntEnum): + NONE = 0 + VERSION = 1 + LIST = 1 + DETACH = 3 + UPLOAD = 4 + DOWNLOAD = 5 + + def main() -> None: # Todo: implement @@ -565,47 +550,98 @@ def main() -> None: parser = argparse.ArgumentParser(description="Description of your program") # Add arguments - parser.add_argument("-h", "--help", action="store_true", help="Show this help message and exit") + # parser.add_argument("-h", "--help", action="store_true", help="Show this help message and exit") parser.add_argument("-V", "--version", action="version", version=VERSION, - help="Show version information and exit") - parser.add_argument("-v", "--verbose", action="store_true", help="Increase verbosity") - parser.add_argument("-l", "--list", action="store_true", help="List option") - parser.add_argument("-e", "--detach", action="store_true", help="Erase option") - parser.add_argument("-d", "--device", metavar="FILE", help="Download option with argument") - parser.add_argument("-p", "--path", metavar="PATH", help="Path option with argument") - parser.add_argument("-c", "--config", metavar="CONFIG", help="Config option with argument") - parser.add_argument("-i", "--interface", metavar="INTERFACE", help="Interface option with argument") - parser.add_argument("-a", "--altsetting", metavar="ALTSETTING", help="Altsetting option with argument") - parser.add_argument("-t", "--transfer-size", metavar="SIZE", help="Transfer size option with argument") - parser.add_argument("-U", "--vid", metavar="VID", help="VID option with argument") - parser.add_argument("-D", "--pid", metavar="PID", help="PID option with argument") - parser.add_argument("-R", "--reset", action="store_true", help="Reset option") - parser.add_argument("-s", "--serial", metavar="SERIAL", help="Serial option with argument") + help="Print the version number") + parser.add_argument("-v", "--verbose", action="store_true", + help="Print verbose debug statements") + parser.add_argument("-l", "--list", action="store_true", + help="List the currently attached DFU capable USB devices") + parser.add_argument("-e", "--detach", action="store_true", + help="Detach the currently attached DFU capable USB devices") + parser.add_argument("-d", "--device", metavar="VID:PID", + help="Specify Vendor/Product ID of DFU device") + parser.add_argument("-p", "--path", metavar="BUS-PORT", + help="Specify path to DFU device") + parser.add_argument("-c", "--config", metavar="CONFIG_NR", + help="Specify the Configuration of DFU device") + parser.add_argument("-i", "--interface", metavar="INTF_NR", + help="Specify the DFU Interface number") + parser.add_argument("-a", "--altsetting", metavar="ALT", + help="Specify the Altsetting of the DFU Interface") + parser.add_argument("-t", "--transfer-size", metavar="SIZE", + help="Specify the number of bytes per USB Transfer") + parser.add_argument("-U", "--upload", metavar="FILE", + help="Read firmware from device into ") + parser.add_argument("-D", "--download", metavar="FILE", + help="Write firmware from into device") + parser.add_argument("-R", "--reset", action="store_true", + help="Issue USB Reset signalling once we're finished") + parser.add_argument("-s", "--serial", metavar="ADDRESS", + help="ST DfuSe mode, specify target address for raw file download or upload. " + "Not applicable for DfuSe file (.dfu) downloads") # Parse arguments args = parser.parse_args() - if args.h: - help_() - sys.exit(0) - - if args.version: - print(VERSION) + dif: dfu.DfuIf = dfu.DfuIf() + file_name = None if args.verbose: VERBOSE = True if args.list: - mode = MODE_LIST + mode = Mode.LIST if args.detach: - mode = MODE_DETACH + mode = Mode.DETACH if args.device: device_id_filter = args.device if args.path: dif.path = args.path + dif.flags |= dfu.Mode.IFF_PATH + if ret := resolve_device_path(dif): + print(f"unable to parse {args.path}") + sys.exit(2) + if not ret: + print(f"cannot find {args.path}") + sys.exit(1) + + if args.config: + dif.configuration = atoi(args.config) + dif.flags |= dfu.Mode.IFF_CONFIG + + if args.interface: + dif.interface = atoi(args.interface) + dif.flags |= dfu.Mode.IFF_IFACE + + if args.altsetting: + altsetting = int(args.altsetting, 0) + if args.altsetting.isdigit() and altsetting: + dif.altsetting = altsetting + else: + alt_name = args.altsetting + dif.flags |= dfu.Mode.IFF_ALT + + if args.transfer_size: + transfer_size = atoi(args.transfer_size) + + if args.upload: + mode = Mode.UPLOAD + file_name = args.upload + + if args.download: + mode = Mode.DOWNLOAD + file_name = args.download + + if args.reset: + mode = Mode.DOWNLOAD + final_reset = 1 + + if args.serial: + dfuse_options = args.serial if __name__ == '__main__': diff --git a/pydfuutil/dfu.py b/pydfuutil/dfu.py index 5606f06..c9f4002 100644 --- a/pydfuutil/dfu.py +++ b/pydfuutil/dfu.py @@ -4,8 +4,8 @@ """ import inspect -from dataclasses import dataclass -from enum import IntEnum +from dataclasses import dataclass, field +from enum import IntEnum, IntFlag import usb.util from construct import Byte, Struct, BytesInteger, Container @@ -100,7 +100,7 @@ class Command(IntEnum): # /* DFU interface */ -class Mode(IntEnum): +class Mode(IntFlag): """Dfu modes""" IFF_DFU = 0x0001 # /* DFU Mode, (not Runtime) */ IFF_VENDOR = 0x0100 @@ -125,36 +125,50 @@ class DfuIf: # pylint: disable=too-many-instance-attributes """DfuIf structure implementation""" - __slots__ = ( - 'vendor', 'product', 'bcdDevice', - 'configuration', 'interface', - 'altsetting', 'alt_name', - 'bus', 'devnum', - 'path', 'flags', 'count', - 'dev', - ) - - # pylint: disable=too-many-arguments, invalid-name - def __init__(self, vendor: int, product: int, bcdDevice: int, - configuration: int, interface: int, - altsetting: int, alt_name: str, - bus: int, devnum: int, - path: [str, int], flags: int, count: int, - dev: usb.core.Device): - - self.vendor = vendor - self.product = product - self.bcdDevice = bcdDevice - self.configuration = configuration - self.interface = interface - self.altsetting = altsetting - self.alt_name = alt_name # or Bytes() pointer - self.bus = bus - self.devnum = devnum - self.path = path # or Bytes() pointer - self.flags = flags - self.count = count - self.dev = dev + vendor: int = field(default=0, ) + product: int = field(default=0, ) + bcdDevice: int = field(default=0, ) + configuration: int = field(default=0, ) + interface: int = field(default=0, ) + altsetting: int = field(default=0, ) + alt_name: str = field(default="", ) + bus: int = field(default=0, ) + devnum: int = field(default=0, ) + path: [str, int] = field(default="", ) + flags: [Mode, int] = field(default=0, ) + count: int = field(default=0, ) + dev: usb.core.Device = field(default=None) + + # __slots__ = ( + # 'vendor', 'product', 'bcdDevice', + # 'configuration', 'interface', + # 'altsetting', 'alt_name', + # 'bus', 'devnum', + # 'path', 'flags', 'count', + # 'dev', + # ) + + # # pylint: disable=too-many-arguments, invalid-name + # def __init__(self, vendor: int, product: int, bcdDevice: int, + # configuration: int, interface: int, + # altsetting: int, alt_name: str, + # bus: int, devnum: int, + # path: [str, int], flags: int, count: int, + # dev: usb.core.Device): + # + # self.vendor = vendor + # self.product = product + # self.bcdDevice = bcdDevice + # self.configuration = configuration + # self.interface = interface + # self.altsetting = altsetting + # self.alt_name = alt_name # or Bytes() pointer + # self.bus = bus + # self.devnum = devnum + # self.path = path # or Bytes() pointer + # self.flags = flags + # self.count = count + # self.dev = dev def init(timeout: int) -> None: