1# Copyright (c) 2022 Renesas Electronics Corporation 2# 3# SPDX-License-Identifier: Apache-2.0 4 5'''Runner for flashing with ezFlashCLI.''' 6import shlex 7 8from runners.core import RunnerCaps, ZephyrBinaryRunner 9 10DEFAULT_EZFLASHCLI = "ezFlashCLI" 11 12class EzFlashCliBinaryRunner(ZephyrBinaryRunner): 13 '''Runner front-end for ezFlashCLI''' 14 15 def __init__(self, cfg, tool, dev_id=None, tool_opt=None, erase=False, reset=True): 16 super().__init__(cfg) 17 self.bin_ = cfg.bin_file 18 19 self.tool = tool 20 self.dev_id = dev_id 21 self.erase = bool(erase) 22 self.reset = bool(reset) 23 24 self.tool_opt = [] 25 if tool_opt is not None: 26 for opts in [shlex.split(opt) for opt in tool_opt]: 27 self.tool_opt += opts 28 29 @classmethod 30 def name(cls): 31 return 'ezflashcli' 32 33 @classmethod 34 def capabilities(cls): 35 return RunnerCaps(commands={'flash'}, dev_id=True, tool_opt=True, erase=True, reset=True) 36 37 @classmethod 38 def dev_id_help(cls) -> str: 39 return '''Device identifier. Use it to select the J-Link Serial Number 40 of the device connected over USB.''' 41 42 @classmethod 43 def tool_opt_help(cls) -> str: 44 return "Additional options for ezFlashCLI e.g. '--verbose'" 45 46 @classmethod 47 def do_add_parser(cls, parser): 48 parser.add_argument('--tool', default=DEFAULT_EZFLASHCLI, 49 help='ezFlashCLI path, default is ' 50 f'{DEFAULT_EZFLASHCLI}') 51 parser.set_defaults(reset=True) 52 53 @classmethod 54 def do_create(cls, cfg, args): 55 return EzFlashCliBinaryRunner(cfg, tool=args.tool, dev_id=args.dev_id, 56 tool_opt=args.tool_opt, erase=args.erase) 57 58 def needs_product_header(self): 59 # Applications linked to code partition are meant to be run by MCUboot 60 # and do not require product header. Other applications and MCUboot itself 61 # are run by internal bootloader and thus require valid product header. 62 63 is_mcuboot = self.build_conf.getboolean('CONFIG_MCUBOOT') 64 uses_code_partition = self.build_conf.getboolean('CONFIG_USE_DT_CODE_PARTITION') 65 66 return is_mcuboot or not uses_code_partition 67 68 def get_options(self): 69 device_args = [] 70 if self.dev_id is not None: 71 device_args = ['-j', f'{self.dev_id}'] 72 return device_args + self.tool_opt 73 74 def program_bin(self): 75 options = self.get_options() 76 77 if self.erase: 78 self.logger.info("Erasing flash...") 79 self.check_call([self.tool] + options + ["erase_flash"]) 80 81 self.logger.info(f"Flashing {self.bin_}...") 82 if self.needs_product_header(): 83 # Write product header and application image at fixed offset as required 84 # by internal bootloader. 85 self.check_call([self.tool] + options + ["image_flash", self.bin_]) 86 else: 87 load_offset = self.build_conf['CONFIG_FLASH_LOAD_OFFSET'] 88 self.check_call( 89 [self.tool] + options + ["write_flash", f'0x{load_offset:x}', self.bin_] 90 ) 91 92 def reset_device(self): 93 self.logger.info("Resetting...") 94 options = self.get_options() 95 self.check_call([self.tool] + options + ["go"]) 96 97 def do_run(self, command, **kwargs): 98 self.require(self.tool) 99 self.ensure_output('bin') 100 self.program_bin() 101 if self.reset: 102 self.reset_device() 103