diff --git a/pyocd/flash/file_programmer.py b/pyocd/flash/file_programmer.py index 195e02dd6..c4d0046ca 100755 --- a/pyocd/flash/file_programmer.py +++ b/pyocd/flash/file_programmer.py @@ -15,9 +15,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import os import logging import itertools +import bincopy from elftools.elf.elffile import ELFFile from intelhex import IntelHex import errno @@ -57,6 +59,7 @@ class FileProgrammer(object): - Binary (.bin) - Intel Hex (.hex) - ELF (.elf or .axf) + - Motorola S-record (.srec) """ def __init__(self, session: "Session", @@ -99,10 +102,11 @@ def __init__(self, self._loader = None self._format_handlers: Dict[str, Callable[..., None]] = { - 'axf': self._program_elf, - 'bin': self._program_bin, - 'elf': self._program_elf, - 'hex': self._program_hex, + 'axf': self._program_elf, + 'bin': self._program_bin, + 'elf': self._program_elf, + 'hex': self._program_hex, + 'srec': self._program_srec, } def program(self, file_or_path: Union[str, IO[bytes]], file_format: Optional[str] = None, **kwargs: Any): @@ -160,8 +164,8 @@ def program(self, file_or_path: Union[str, IO[bytes]], file_format: Optional[str # Open the file if a path was provided. if is_path: mode = 'rb' - if file_format == 'hex': - # hex file must be read as plain text file + if file_format == 'hex' or file_format == 'srec': + # hex and srec files must be read as plain text file mode = 'r' assert isinstance(file_or_path, str) file_obj = open(file_or_path, mode) @@ -177,6 +181,14 @@ def program(self, file_or_path: Union[str, IO[bytes]], file_format: Optional[str if is_path and file_obj is not None: file_obj.close() + def _program_srec(self, file_obj: IO[bytes], **kwargs: Any) -> None: + """@brief SREC file format loader""" + assert self._loader + + bf = bincopy.BinFile() + bf.add_srec(file_obj.read()) + self._program_hex(io.StringIO(bf.as_ihex()), **kwargs) + def _program_bin(self, file_obj: IO[bytes], **kwargs: Any) -> None: """@brief Binary file format loader""" assert self._loader diff --git a/pyocd/subcommands/load_cmd.py b/pyocd/subcommands/load_cmd.py index 29f7b2ef2..acfd0852a 100644 --- a/pyocd/subcommands/load_cmd.py +++ b/pyocd/subcommands/load_cmd.py @@ -34,7 +34,7 @@ class LoadSubcommand(SubcommandBase): NAMES = ['load', 'flash'] HELP = "Load one or more images into target device memory." - EPILOG = "Supported file formats are: binary, Intel hex, and ELF32." + EPILOG = "Supported file formats are: binary (.bin), ELF32/AXF (.elf and .axf), Intel hex (.hex), and Motorola S-record (.srec)." DEFAULT_LOG_LEVEL = logging.WARNING ## @brief Valid erase mode options. @@ -57,7 +57,7 @@ def get_args(cls) -> List[argparse.ArgumentParser]: "Only allowed if a single binary file is being loaded.") parser_options.add_argument("--trust-crc", action="store_true", help="Use only the CRC of each page to determine if it already has the same data.") - parser_options.add_argument("--format", choices=("bin", "hex", "elf"), + parser_options.add_argument("--format", choices=("axf", "bin", "elf", "hex", "srec"), help="File format. Default is to use the file's extension. If multiple files are provided, then " "all must be of this type.") parser_options.add_argument("--skip", metavar="BYTES", default=0, type=int_base_0, diff --git a/setup.cfg b/setup.cfg index d27543a50..8874b008a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,7 @@ python_requires = >=3.7.0 # importlib_resources is used instead of stdlib importlib.resources because we # want the selectable entry_points API, which is not present until Python 3.10. install_requires = + bincopy>=20.0,<21.0 capstone>=4.0,<5.0 cmsis-pack-manager>=0.5.2,<1.0 colorama<1.0