blob: d91e98a552f6598e2723aad0efbd74ddeff97473 [file] [log] [blame]
# Copyright (c) 2025 Core Devices LLC
# Copyright (c) 2025 SiFli Technologies(Nanjing) Co., Ltd
# SPDX-License-Identifier: Apache-2.0
import argparse
import shlex
import subprocess
from runners.core import RunnerCaps, RunnerConfig, ZephyrBinaryRunner
class SftoolRunner(ZephyrBinaryRunner):
"""Runner front-end for sftool CLI."""
def __init__(
self,
cfg: RunnerConfig,
chip: str,
port: str,
erase: bool,
dt_flash: bool,
tool_opt: list[str],
flash_files: list[str],
) -> None:
super().__init__(cfg)
self._chip = chip
self._port = port
self._erase = erase
self._dt_flash = dt_flash
self._flash_files = flash_files
self._tool_opt: list[str] = []
for opts in [shlex.split(opt) for opt in tool_opt]:
self._tool_opt += opts
@classmethod
def name(cls):
return "sftool"
@classmethod
def capabilities(cls):
return RunnerCaps(commands={"flash"}, erase=True, flash_addr=True, file=True, tool_opt=True)
@classmethod
def do_add_parser(cls, parser):
parser.add_argument(
"--chip",
type=str,
required=True,
help="Target chip, e.g. SF32LB52",
)
parser.add_argument(
"--port",
type=str,
required=True,
help="Serial port device, e.g. /dev/ttyUSB0",
)
parser.add_argument(
"--flash-file",
dest="flash_files",
action="append",
default=[],
help="Additional file@address entries that must be flashed before the Zephyr image",
)
@classmethod
def do_create(cls, cfg: RunnerConfig, args: argparse.Namespace) -> "SftoolRunner":
return SftoolRunner(
cfg,
chip=args.chip,
port=args.port,
erase=args.erase,
dt_flash=args.dt_flash,
tool_opt=args.tool_opt,
flash_files=args.flash_files,
)
def do_run(self, command: str, **kwargs):
sftool = self.require("sftool")
cmd = [sftool, "--chip", self._chip, "--port", self._port]
cmd += self._tool_opt
flash_targets: list[str] = []
flash_targets.extend(self._flash_files)
if self.cfg.file:
flash_targets.append(self.cfg.file)
else:
if self.cfg.bin_file and self._dt_flash:
addr = self.flash_address_from_build_conf(self.build_conf)
flash_targets.append(f"{self.cfg.bin_file}@0x{addr:08x}")
elif self.cfg.hex_file:
flash_targets.append(self.cfg.hex_file)
else:
raise RuntimeError("No file available for flashing")
write_args = ["write_flash"]
if self._erase:
write_args.append("-e")
full_cmd = cmd + write_args + flash_targets
self._log_cmd(full_cmd)
if not self.dry_run:
subprocess.run(full_cmd, check=True)