1# Copyright (c) 2022 Renesas Electronics Corporation
2#
3# SPDX-License-Identifier: Apache-2.0
4
5'''Runner for flashing with ezFlashCLI.'''
6from runners.core import ZephyrBinaryRunner, RunnerCaps
7
8DEFAULT_EZFLASHCLI = "ezFlashCLI"
9
10class EzFlashCliBinaryRunner(ZephyrBinaryRunner):
11    '''Runner front-end for ezFlashCLI'''
12
13    def __init__(self, cfg, tool, sn, erase=False):
14        super().__init__(cfg)
15        self.bin_ = cfg.bin_file
16
17        self.tool = tool
18        self.sn_arg = ['-j', f'{sn}'] if sn is not None else []
19        self.erase = bool(erase)
20
21    @classmethod
22    def name(cls):
23        return 'ezflashcli'
24
25    @classmethod
26    def capabilities(cls):
27        return RunnerCaps(commands={'flash'}, erase=True)
28
29    @classmethod
30    def do_add_parser(cls, parser):
31        parser.add_argument('--tool', default=DEFAULT_EZFLASHCLI,
32                            help='ezFlashCLI path, default is '
33                                f'{DEFAULT_EZFLASHCLI}')
34        parser.add_argument('--sn', default=None, required=False,
35                            help='J-Link probe serial number')
36
37    @classmethod
38    def do_create(cls, cfg, args):
39        return EzFlashCliBinaryRunner(cfg, tool=args.tool, sn=args.sn,
40                                      erase=args.erase)
41
42    def needs_product_header(self):
43        # Applications linked to code partition are meant to be run by MCUboot
44        # and do not require product header. Other applications and MCUboot itself
45        # are run by internal bootloader and thus require valid product header.
46
47        is_mcuboot = self.build_conf.getboolean('CONFIG_MCUBOOT')
48        uses_code_partition = self.build_conf.getboolean('CONFIG_USE_DT_CODE_PARTITION')
49
50        return is_mcuboot or not uses_code_partition
51
52    def program_bin(self):
53
54        if self.erase:
55            self.logger.info("Erasing flash...")
56            self.check_call([self.tool] + self.sn_arg + ["erase_flash"])
57
58        self.logger.info(f"Flashing {self.bin_}...")
59        if self.needs_product_header():
60            # Write product header and application image at fixed offset as required
61            # by internal bootloader.
62            self.check_call([self.tool] + self.sn_arg + ["image_flash", self.bin_])
63        else:
64            load_offset = self.build_conf['CONFIG_FLASH_LOAD_OFFSET']
65            self.check_call([self.tool] + self.sn_arg + ["write_flash", f'0x{load_offset:x}', self.bin_])
66
67    def reset(self):
68        self.logger.info("Resetting...")
69        self.check_call([self.tool] + self.sn_arg + ["go"])
70
71    def do_run(self, command, **kwargs):
72        self.require(self.tool)
73        self.ensure_output('bin')
74        self.program_bin()
75        self.reset()
76