#!/usr/bin/env python3 import argparse import dataclasses import pathlib PADDING_BYTE: bytes = b"\xff" def main() -> None: args = Arguments.from_cli() print(args) factory_image: bytes = join( bootloader=args.bootloader.read_bytes(), application=args.application.read_bytes(), offset=args.offset, ) args.factory_image.write_bytes(factory_image) def join(bootloader: bytes, application: bytes, offset: int) -> bytes: padding = PADDING_BYTE * (offset - len(bootloader)) return bootloader + padding + application @dataclasses.dataclass class Arguments: bootloader: pathlib.Path offset: int application: pathlib.Path factory_image: pathlib.Path def __post_init__(self) -> None: assert isinstance(self.bootloader, pathlib.Path) assert isinstance(self.offset, int) assert self.offset >= 0 assert isinstance(self.application, pathlib.Path) assert isinstance(self.factory_image, pathlib.Path) def __str__(self) -> str: return f"""{__file__} \\ --bootloader {self.bootloader} \\ --offset 0x{self.offset:X} \\ --application {self.application} \\ --factory_image {self.factory_image}""" @staticmethod def from_cli() -> "Arguments": parser = argparse.ArgumentParser( description="Join bootloader and application firmware to a factory image" ) parser.add_argument( "-b", "--bootloader", required=True, help="path to bootloader firmware" ) default_offset = 0x40000 parser.add_argument( "-o", "--offset", default=default_offset, help=f"offset in bytes between bootloader and application (default: 0x{default_offset:X})", ) parser.add_argument( "-a", "--application", required=True, help="path to application firmware" ) parser.add_argument( "-f", "--factory-image", default=pathlib.Path("factory-image.bin"), help="path to output factory image file", ) args = parser.parse_args() return Arguments( bootloader=pathlib.Path(args.bootloader), offset=int(args.offset), application=pathlib.Path(args.application), factory_image=pathlib.Path(args.factory_image), ) if __name__ == "__main__": main()