1# Copyright (c) 2017 Linaro Limited.
2# Copyright (c) 2019 Intel Corporation
3#
4# SPDX-License-Identifier: Apache-2.0
5
6'''Dediprog (dpcmd) flash only runner for SPI chips.'''
7
8import platform
9import subprocess
10
11from runners.core import ZephyrBinaryRunner, RunnerCaps
12
13DPCMD_EXE = 'dpcmd.exe' if platform.system() == 'Windows' else 'dpcmd'
14DEFAULT_MAX_RETRIES = 3
15
16class DediProgBinaryRunner(ZephyrBinaryRunner):
17    '''Runner front-end for DediProg (dpcmd).'''
18
19    def __init__(self, cfg, spi_image, vcc, retries):
20        super().__init__(cfg)
21        self.spi_image = spi_image
22        self.vcc = vcc
23        self.dpcmd_retries = retries
24
25    @classmethod
26    def name(cls):
27        return 'dediprog'
28
29    @classmethod
30    def capabilities(cls):
31        return RunnerCaps(commands={'flash'})
32
33    @classmethod
34    def do_add_parser(cls, parser):
35        parser.add_argument('--spi-image', required=True,
36                            help='path to SPI image')
37        parser.add_argument('--vcc',
38                            help='VCC (0=3.5V, 1=2.5V, 2=1.8V)')
39        parser.add_argument('--retries', default=5,
40                            help='Number of retries (default 5)')
41
42    @classmethod
43    def do_create(cls, cfg, args):
44        return DediProgBinaryRunner(cfg,
45                                    spi_image=args.spi_image,
46                                    vcc=args.vcc,
47                                    retries=args.retries)
48
49    def do_run(self, command, **kwargs):
50        self.require(DPCMD_EXE)
51        cmd_flash = [DPCMD_EXE, '--auto', self.spi_image]
52
53        if self.vcc:
54            cmd_flash.append('--vcc')
55            cmd_flash.append(self.vcc)
56
57        # Allow to flash images smaller than flash device capacity
58        cmd_flash.append('-x')
59        cmd_flash.append('ff')
60
61        cmd_flash.append('--silent')
62        cmd_flash.append('--verify')
63
64        try:
65            max_retries = int(self.dpcmd_retries)
66        except ValueError:
67            max_retries = DEFAULT_MAX_RETRIES
68
69        retries = 0
70        while retries <= max_retries:
71            try:
72                self.check_call(cmd_flash)
73            except subprocess.CalledProcessError as cpe:
74                retries += 1
75                if retries > max_retries:
76                    raise cpe
77                else:
78                    continue
79
80            break
81