zephyr/scripts/west_commands/runners/stm32flash.py
Martí Bolívar f8e8e9229d runners: enforce RunnerCaps via create() indirection
Require all implementations to provide a do_create(), a new
ZephyrBinaryRunner abstract class method, and make create() itself
concrete.

This allows us to enforce common conventions related to individual
runner capabilities as each runner provides to the core via
RunnerCaps.

For now, just enforce that:

- common options related to capabilities are always added, so runners
  can't reuse them for different ends

- common options provided for runners which don't support them emit
  sensible error messages that should be easy to diagnose and support

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-06-25 12:14:25 +02:00

150 lines
5.5 KiB
Python

# Copyright (c) 2019 Thomas Kupper <thomas.kupper@gmail.com>
#
# SPDX-License-Identifier: Apache-2.0
'''Runner for flashing with stm32flash.'''
from os import path
import platform
from runners.core import ZephyrBinaryRunner, RunnerCaps
DEFAULT_DEVICE = '/dev/ttyUSB0'
if platform.system() == 'Darwin':
DEFAULT_DEVICE = '/dev/tty.SLAB_USBtoUART'
class Stm32flashBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for stm32flash.'''
def __init__(self, cfg, device, action='write', baud=57600,
force_binary=False, start_addr=0, exec_addr=None,
serial_mode='8e1', reset=False, verify=False):
super().__init__(cfg)
self.device = device
self.action = action
self.baud = baud
self.force_binary = force_binary
self.start_addr = start_addr
self.exec_addr = exec_addr
self.serial_mode = serial_mode
self.reset = reset
self.verify = verify
@classmethod
def name(cls):
return 'stm32flash'
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash'})
@classmethod
def do_add_parser(cls, parser):
# required argument(s)
# none for now
# optional argument(s)
parser.add_argument('--device', default=DEFAULT_DEVICE, required=False,
help='serial port to flash, default \'' + DEFAULT_DEVICE + '\'')
parser.add_argument('--action', default='write', required=False,
choices=['erase', 'info', 'start', 'write'],
help='erase / get device info / start execution / write flash')
parser.add_argument('--baud-rate', default='57600', required=False,
choices=['1200', '1800', '2400', '4800', '9600', '19200',
'38400', '57600', '115200', '230400', '256000', '460800',
'500000', '576000', '921600', '1000000', '1500000', '2000000'],
help='serial baud rate, default \'57600\'')
parser.add_argument('--force-binary', required=False, action='store_true',
help='force the binary parser')
parser.add_argument('--start-addr', default=0, required=False,
help='specify start address for write operation, default \'0\'')
parser.add_argument('--execution-addr', default=None, required=False,
help='start execution at specified address, default \'0\' \
which means start of flash')
parser.add_argument('--serial-mode', default='8e1', required=False,
help='serial port mode, default \'8e1\'')
parser.add_argument('--reset', default=False, required=False, action='store_true',
help='reset device at exit, default False')
parser.add_argument('--verify', default=False, required=False, action='store_true',
help='verify writes, default False')
@classmethod
def do_create(cls, cfg, args):
return Stm32flashBinaryRunner(cfg, device=args.device, action=args.action,
baud=args.baud_rate, force_binary=args.force_binary,
start_addr=args.start_addr, exec_addr=args.execution_addr,
serial_mode=args.serial_mode, reset=args.reset, verify=args.verify)
def do_run(self, command, **kwargs):
self.require('stm32flash')
bin_name = self.cfg.bin_file
bin_size = path.getsize(bin_name)
cmd_flash = ['stm32flash', '-b', self.baud,
'-m', self.serial_mode]
action = self.action.lower()
if action == 'info':
# show device information and exit
msg_text = "get device info from {}".format(self.device)
elif action == 'erase':
# erase flash
#size_aligned = (int(bin_size) >> 12) + 1 << 12
size_aligned = (int(bin_size) & 0xfffff000) + 4096
msg_text = "erase {} bit starting at {}".format(size_aligned, self.start_addr)
cmd_flash.extend([
'-S', str(self.start_addr) + ":" + str(size_aligned), '-o'])
elif action == 'start':
# start execution
msg_text = "start code execution at {}".format(self.exec_addr)
if self.exec_addr:
if self.exec_addr == 0 or self.exec_addr.lower() == '0x0':
msg_text += " (flash start)"
else:
self.exec_addr = 0
cmd_flash.extend([
'-g', str(self.exec_addr)])
elif action == 'write':
# flash binary file
msg_text = "write {} bytes starting at {}".format(bin_size, self.start_addr)
cmd_flash.extend([
'-S', str(self.start_addr) + ":" + str(bin_size),
'-w', bin_name])
if self.exec_addr:
cmd_flash.extend(['-g', self.exec_addr])
if self.force_binary:
cmd_flash.extend(['-f'])
if self.reset:
cmd_flash.extend(['-R'])
if self.verify:
cmd_flash.extend(['-v'])
else:
msg_text = "invalid action \'{}\' passed!".format(action)
self.logger.error('Invalid action \'{}\' passed!'.format(action))
return -1
cmd_flash.extend([self.device])
self.logger.info("Board: " + msg_text)
self.check_call(cmd_flash)
self.logger.info('Board: finished \'{}\' .'.format(action))