zephyr/scripts/west_commands/runners/spi_burn.py

137 lines
4.2 KiB
Python

# Copyright (c) 2021, Telink Semiconductor
#
# SPDX-License-Identifier: Apache-2.0
import re
import os
import time
import subprocess
from runners.core import ZephyrBinaryRunner, RunnerCaps, BuildConfiguration
class SpiBurnBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for SPI_burn.'''
def __init__(self, cfg, addr, spiburn, iceman, timeout, gdb_port, gdb_ex, erase=False):
super().__init__(cfg)
self.spiburn = spiburn
self.iceman = iceman
self.addr = addr
self.timeout = int(timeout)
self.erase = bool(erase)
self.gdb_port = gdb_port
self.gdb_ex = gdb_ex
@classmethod
def name(cls):
return 'spi_burn'
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash', 'debug'}, erase=True, flash_addr=True)
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--addr', default='0x0',
help='start flash address to write')
parser.add_argument('--timeout', default=10,
help='ICEman connection establishing timeout in seconds')
parser.add_argument('--telink-tools-path', help='path to Telink flash tools')
parser.add_argument('--gdb-port', default='1111', help='Port to connect for gdb-client')
parser.add_argument('--gdb-ex', default='', nargs='?', help='Additional gdb commands to run')
@classmethod
def do_create(cls, cfg, args):
if args.telink_tools_path:
spiburn = f'{args.telink_tools_path}/flash/bin/SPI_burn'
iceman = f'{args.telink_tools_path}/ice/ICEman'
else:
# If telink_tools_path arg is not specified then pass to tools shall be specified in PATH
spiburn = 'SPI_burn'
iceman = 'ICEman'
# Get flash address offset
if args.dt_flash == 'y':
build_conf = BuildConfiguration(cfg.build_dir)
address = hex(cls.get_flash_address(args, build_conf) - build_conf['CONFIG_FLASH_BASE_ADDRESS'])
else:
address = args.addr
return SpiBurnBinaryRunner(cfg, address, spiburn, iceman, args.timeout, args.gdb_port, args.gdb_ex, args.erase)
def do_run(self, command, **kwargs):
self.require(self.spiburn)
# Find path to ICEman with require call
self.iceman_path = self.require(self.iceman)
if command == "flash":
self._flash()
elif command == "debug":
self._debug()
else:
self.logger.error(f'{command} not supported!')
def start_iceman(self):
# Start ICEman as background process
self.ice_process = self.popen_ignore_int(["./ICEman", '-Z', 'v5', '-l', 'aice_sdp.cfg'],
cwd=os.path.dirname(self.iceman_path),
stdout=subprocess.PIPE)
# Wait till it ready or exit by timeout
start = time.time()
while True:
out = self.ice_process.stdout.readline()
if b'ICEman is ready to use.' in out:
break
if time.time() - start > self.timeout:
raise RuntimeError("TIMEOUT: ICEman is not ready")
def stop_iceman(self):
# Kill ICEman subprocess
self.ice_process.terminate()
def _flash(self):
try:
# Start ICEman
self.start_iceman()
# Compose flash command
cmd_flash = [self.spiburn, '--addr', str(self.addr), '--image', self.cfg.bin_file]
if self.erase:
cmd_flash += ["--erase-all"]
# Run SPI burn flash tool
self.check_call(cmd_flash)
finally:
self.stop_iceman()
def _debug(self):
try:
# Start ICEman
self.start_iceman()
# format -ex commands
gdb_ex = re.split("(-ex) ", self.gdb_ex)[1::]
# Compose gdb command
client_cmd = [self.cfg.gdb, self.cfg.elf_file, '-ex', f'target remote :{self.gdb_port}'] + gdb_ex
# Run gdb
self.run_client(client_cmd)
finally:
self.stop_iceman()