From 01f08f99b1d307d0e8406309ae5da2122031b3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 23 Nov 2021 19:13:34 +0300 Subject: [PATCH] Scripts: add serial number support to cube programmer api, update usage. (#839) --- scripts/flash.py | 20 ++++++++---- scripts/flipper/cube.py | 36 ++++++++++++++------- scripts/ob.py | 24 +++++++++----- scripts/otp.py | 69 +++++++++++++++++++++++------------------ 4 files changed, 92 insertions(+), 57 deletions(-) diff --git a/scripts/flash.py b/scripts/flash.py index be65b1dc..170d4311 100755 --- a/scripts/flash.py +++ b/scripts/flash.py @@ -16,6 +16,7 @@ class Main(App): self.subparsers = self.parser.add_subparsers(help="sub-command help") # Wipe self.parser_wipe = self.subparsers.add_parser("wipe", help="Wipe MCU Flash") + self._addArgsSWD(self.parser_wipe) self.parser_wipe.set_defaults(func=self.wipe) # Core 1 boot self.parser_core1bootloader = self.subparsers.add_parser( @@ -78,10 +79,17 @@ class Main(App): parser.add_argument( "--port", type=str, help="Port to connect: swd or usb1", default="swd" ) + parser.add_argument("--serial", type=str, help="ST-Link Serial Number") + + def _getCubeParams(self): + return { + "port": self.args.port, + "serial": self.args.serial, + } def wipe(self): self.logger.info(f"Wiping flash") - cp = CubeProgrammer("swd") + cp = CubeProgrammer(self._getCubeParams()) self.logger.info(f"Setting RDP to 0xBB") cp.setOptionBytes({"RDP": ("0xBB", "rw")}) self.logger.info(f"Verifying RDP") @@ -99,7 +107,7 @@ class Main(App): def core1bootloader(self): self.logger.info(f"Flashing bootloader") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08000000", self.args.bootloader) self.logger.info(f"Complete") cp.resetTarget() @@ -107,7 +115,7 @@ class Main(App): def core1firmware(self): self.logger.info(f"Flashing firmware") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08008000", self.args.firmware) self.logger.info(f"Complete") cp.resetTarget() @@ -115,7 +123,7 @@ class Main(App): def core1(self): self.logger.info(f"Flashing bootloader") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x08000000", self.args.bootloader) self.logger.info(f"Flashing firmware") cp.flashBin("0x08008000", self.args.firmware) @@ -130,7 +138,7 @@ class Main(App): ) return 1 self.logger.info(f"Flashing Firmware Update Service") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashCore2(self.args.fus_address, self.args.fus) self.logger.info(f"Complete") return 0 @@ -139,7 +147,7 @@ class Main(App): if int(self.args.radio_address, 16) > 0x080E0000: self.logger.error(f"I KNOW WHAT YOU DID LAST SUMMER") return 1 - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) self.logger.info(f"Removing Current Radio Stack") cp.deleteCore2RadioStack() self.logger.info(f"Flashing Radio Stack") diff --git a/scripts/flipper/cube.py b/scripts/flipper/cube.py index 16238217..38aa54a8 100644 --- a/scripts/flipper/cube.py +++ b/scripts/flipper/cube.py @@ -5,23 +5,35 @@ import subprocess class CubeProgrammer: """STM32 Cube Programmer cli wrapper""" - def __init__(self, port, params=[]): - self.port = port - self.params = params + def __init__(self, config={}): + assert isinstance(config, dict) + # Params base + self.params = [] + # Connect params + connect = [] + if "port" in config and config["port"]: + connect.append(f"port={config['port']}") + else: + connect.append(f"port=swd") + if "serial" in config and config["serial"]: + connect.append(f"sn={config['serial']}") + self.params.append("-c " + " ".join(connect)) + # Other params + if "params" in config: + self.params += config["params"] # logging self.logger = logging.getLogger() def _execute(self, args): try: - output = subprocess.check_output( - [ - "STM32_Programmer_CLI", - "-q", - f"-c port={self.port}", - *self.params, - *args, - ] - ) + params = [ + "STM32_Programmer_CLI", + "-q", + *self.params, + *args, + ] + self.logger.debug(f"_execute: {params}") + output = subprocess.check_output(params) except subprocess.CalledProcessError as e: if e.output: print("Process output:\n", e.output.decode()) diff --git a/scripts/ob.py b/scripts/ob.py index 903bfd56..17de08fd 100755 --- a/scripts/ob.py +++ b/scripts/ob.py @@ -16,19 +16,27 @@ class Main(App): self.parser_check = self.subparsers.add_parser( "check", help="Check Option Bytes" ) - self.parser_check.add_argument( - "--port", type=str, help="Port to connect: swd or usb1", default="swd" - ) + self._addArgsSWD(self.parser_check) self.parser_check.set_defaults(func=self.check) # Set command self.parser_set = self.subparsers.add_parser("set", help="Set Option Bytes") - self.parser_set.add_argument( - "--port", type=str, help="Port to connect: swd or usb1", default="swd" - ) + self._addArgsSWD(self.parser_set) self.parser_set.set_defaults(func=self.set) # OB self.ob = {} + def _addArgsSWD(self, parser): + parser.add_argument( + "--port", type=str, help="Port to connect: swd or usb1", default="swd" + ) + parser.add_argument("--serial", type=str, help="ST-Link Serial Number") + + def _getCubeParams(self): + return { + "port": self.args.port, + "serial": self.args.serial, + } + def before(self): self.logger.info(f"Loading Option Bytes data") file_path = os.path.join(os.path.dirname(sys.argv[0]), "ob.data") @@ -39,7 +47,7 @@ class Main(App): def check(self): self.logger.info(f"Checking Option Bytes") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) if cp.checkOptionBytes(self.ob): self.logger.info(f"OB Check OK") return 0 @@ -49,7 +57,7 @@ class Main(App): def set(self): self.logger.info(f"Setting Option Bytes") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) if cp.setOptionBytes(self.ob): self.logger.info(f"OB Set OK") return 0 diff --git a/scripts/otp.py b/scripts/otp.py index edad4b07..54714961 100755 --- a/scripts/otp.py +++ b/scripts/otp.py @@ -44,59 +44,66 @@ class Main(App): self.parser_generate_all = self.subparsers.add_parser( "generate", help="Generate OTP binary" ) - self._add_first_args(self.parser_generate_all) - self._add_second_args(self.parser_generate_all) + self._addFirstArgs(self.parser_generate_all) + self._addSecondArgs(self.parser_generate_all) self.parser_generate_all.add_argument("file", help="Output file") self.parser_generate_all.set_defaults(func=self.generate_all) # Flash First self.parser_flash_first = self.subparsers.add_parser( "flash_first", help="Flash first block of OTP to device" ) - self._add_swd_args(self.parser_flash_first) - self._add_first_args(self.parser_flash_first) + self._addArgsSWD(self.parser_flash_first) + self._addFirstArgs(self.parser_flash_first) self.parser_flash_first.set_defaults(func=self.flash_first) # Flash Second self.parser_flash_second = self.subparsers.add_parser( "flash_second", help="Flash second block of OTP to device" ) - self._add_swd_args(self.parser_flash_second) - self._add_second_args(self.parser_flash_second) + self._addArgsSWD(self.parser_flash_second) + self._addSecondArgs(self.parser_flash_second) self.parser_flash_second.set_defaults(func=self.flash_second) # Flash All self.parser_flash_all = self.subparsers.add_parser( "flash_all", help="Flash OTP to device" ) - self._add_swd_args(self.parser_flash_all) - self._add_first_args(self.parser_flash_all) - self._add_second_args(self.parser_flash_all) + self._addArgsSWD(self.parser_flash_all) + self._addFirstArgs(self.parser_flash_all) + self._addSecondArgs(self.parser_flash_all) self.parser_flash_all.set_defaults(func=self.flash_all) # logging self.logger = logging.getLogger() self.timestamp = datetime.datetime.now().timestamp() - def _add_swd_args(self, parser): + def _addArgsSWD(self, parser): parser.add_argument( "--port", type=str, help="Port to connect: swd or usb1", default="swd" ) + parser.add_argument("--serial", type=str, help="ST-Link Serial Number") - def _add_first_args(self, parser): + def _getCubeParams(self): + return { + "port": self.args.port, + "serial": self.args.serial, + } + + def _addFirstArgs(self, parser): parser.add_argument("--version", type=int, help="Version", required=True) parser.add_argument("--firmware", type=int, help="Firmware", required=True) parser.add_argument("--body", type=int, help="Body", required=True) parser.add_argument("--connect", type=int, help="Connect", required=True) parser.add_argument("--display", type=str, help="Display", required=True) - def _add_second_args(self, parser): + def _addSecondArgs(self, parser): parser.add_argument("--color", type=str, help="Color", required=True) parser.add_argument("--region", type=str, help="Region", required=True) parser.add_argument("--name", type=str, help="Name", required=True) - def _process_first_args(self): + def _processFirstArgs(self): if self.args.display not in OTP_DISPLAYS: self.parser.error(f"Invalid display. Use one of {OTP_DISPLAYS.keys()}") self.args.display = OTP_DISPLAYS[self.args.display] - def _process_second_args(self): + def _processSecondArgs(self): if self.args.color not in OTP_COLORS: self.parser.error(f"Invalid color. Use one of {OTP_COLORS.keys()}") self.args.color = OTP_COLORS[self.args.color] @@ -112,7 +119,7 @@ class Main(App): "Name contains incorrect symbols. Only a-zA-Z0-9 allowed." ) - def _pack_first(self): + def _packFirst(self): return struct.pack( "<" "HBBL" "BBBBBBH", OTP_MAGIC, @@ -128,7 +135,7 @@ class Main(App): OTP_RESERVED, ) - def _pack_second(self): + def _packSecond(self): return struct.pack( "<" "BBHL" "8s", self.args.color, @@ -140,10 +147,10 @@ class Main(App): def generate_all(self): self.logger.info(f"Generating OTP") - self._process_first_args() - self._process_second_args() - open(f"{self.args.file}_first.bin", "wb").write(self._pack_first()) - open(f"{self.args.file}_second.bin", "wb").write(self._pack_second()) + self._processFirstArgs() + self._processSecondArgs() + open(f"{self.args.file}_first.bin", "wb").write(self._packFirst()) + open(f"{self.args.file}_second.bin", "wb").write(self._packSecond()) self.logger.info( f"Generated files: {self.args.file}_first.bin and {self.args.file}_second.bin" ) @@ -153,17 +160,17 @@ class Main(App): def flash_first(self): self.logger.info(f"Flashing first block of OTP") - self._process_first_args() + self._processFirstArgs() filename = f"otp_unknown_first_{self.timestamp}.bin" try: self.logger.info(f"Packing binary data") file = open(filename, "wb") - file.write(self._pack_first()) + file.write(self._packFirst()) file.close() self.logger.info(f"Flashing OTP") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7000", filename) cp.resetTarget() self.logger.info(f"Flashed Successfully") @@ -177,17 +184,17 @@ class Main(App): def flash_second(self): self.logger.info(f"Flashing second block of OTP") - self._process_second_args() + self._processSecondArgs() filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" try: self.logger.info(f"Packing binary data") file = open(filename, "wb") - file.write(self._pack_second()) + file.write(self._packSecond()) file.close() self.logger.info(f"Flashing OTP") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7010", filename) cp.resetTarget() self.logger.info(f"Flashed Successfully") @@ -201,19 +208,19 @@ class Main(App): def flash_all(self): self.logger.info(f"Flashing OTP") - self._process_first_args() - self._process_second_args() + self._processFirstArgs() + self._processSecondArgs() filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" try: self.logger.info(f"Packing binary data") file = open(filename, "wb") - file.write(self._pack_first()) - file.write(self._pack_second()) + file.write(self._packFirst()) + file.write(self._packSecond()) file.close() self.logger.info(f"Flashing OTP") - cp = CubeProgrammer(self.args.port) + cp = CubeProgrammer(self._getCubeParams()) cp.flashBin("0x1FFF7000", filename) cp.resetTarget() self.logger.info(f"Flashed Successfully")