west: runners: rfp: Add Reneses Flash Programmer runner
Add a basic RFP runner that supports the `flash` command targettting the Renesas Standard Boot Firmware. Signed-off-by: Peter Johanson <peter@peterjohanson.com>
This commit is contained in:
parent
f793aafe88
commit
4399d9e3a2
6 changed files with 405 additions and 0 deletions
5
boards/common/rfp.board.cmake
Normal file
5
boards/common/rfp.board.cmake
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
board_set_flasher_ifnset(rfp)
|
||||
|
||||
board_finalize_runner_args(rfp)
|
|
@ -484,6 +484,25 @@ Check if your SoC is listed in `probe-rs Supported Devices`_.
|
|||
|
||||
.. _stm32cubeprog-flash-host-tools:
|
||||
|
||||
Renesas Flash Programmer (RFP) Host Tools
|
||||
*****************************************
|
||||
|
||||
Renesas provides `Renesas Flash Programmer`_ as an official programming tool for Renesas boards
|
||||
using the Renesas standard boot firmware. It is available as a GUI and CLI.
|
||||
|
||||
For boards configured with the ``rfp`` west runner, the RFP CLI can be easily used to flash Zephyr.
|
||||
|
||||
Supported west commands:
|
||||
|
||||
1. flash
|
||||
|
||||
Once downloaded, if ``rfp-cli`` is not placed somewhere in your system PATH, you can pass the location
|
||||
to ``rfp-cli`` when flashing:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
west flash --rfp-cli ~/Downloads/RFP_CLI_Linux_V31800_x64/linux-x64/rfp-cli
|
||||
|
||||
STM32CubeProgrammer Flash Host Tools
|
||||
************************************
|
||||
|
||||
|
@ -572,6 +591,9 @@ For advanced usage via the GUI or CLI, check out the `STM32CubeProgrammer User M
|
|||
.. _NXP S32 Design Studio for S32 Platform:
|
||||
https://www.nxp.com/design/software/development-software/s32-design-studio-ide/s32-design-studio-for-s32-platform:S32DS-S32PLATFORM
|
||||
|
||||
.. _Renesas Flash Programmer:
|
||||
https://www.renesas.com/en/software-tool/renesas-flash-programmer-programming-gui
|
||||
|
||||
.. _S32 Design Studio for S32 Platform Installation User Guide:
|
||||
https://www.nxp.com/webapp/Download?colCode=S32DSIG
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ _names = [
|
|||
'qemu',
|
||||
'renode',
|
||||
'renode-robot',
|
||||
'rfp',
|
||||
'silabs_commander',
|
||||
'spi_burn',
|
||||
'stm32cubeprogrammer',
|
||||
|
|
120
scripts/west_commands/runners/rfp.py
Normal file
120
scripts/west_commands/runners/rfp.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
# Copyright (c) 2025 Pete Johanson
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# pylint: disable=duplicate-code
|
||||
|
||||
'''Runner for rfp.'''
|
||||
|
||||
import platform
|
||||
import re
|
||||
|
||||
from runners.core import RunnerCaps, ZephyrBinaryRunner
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
DEFAULT_RFP_PORT = None
|
||||
else:
|
||||
DEFAULT_RFP_PORT = '/dev/ttyACM0'
|
||||
|
||||
|
||||
def to_num(number):
|
||||
dev_match = re.search(r"^\d*\+dev", number)
|
||||
dev_version = dev_match is not None
|
||||
|
||||
num_match = re.search(r"^\d*", number)
|
||||
num = int(num_match.group(0))
|
||||
|
||||
if dev_version:
|
||||
num += 1
|
||||
|
||||
return num
|
||||
|
||||
|
||||
class RfpBinaryRunner(ZephyrBinaryRunner):
|
||||
'''Runner front-end for rfp.'''
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
cfg,
|
||||
rfp_cli='rfp-cli',
|
||||
device=None,
|
||||
erase=False,
|
||||
verify=False,
|
||||
port=DEFAULT_RFP_PORT,
|
||||
speed=None,
|
||||
):
|
||||
super().__init__(cfg)
|
||||
|
||||
self.rfp_cmd = [rfp_cli]
|
||||
self.verify = verify
|
||||
self.erase = erase
|
||||
self.port = port
|
||||
self.device = device
|
||||
self.speed = speed
|
||||
|
||||
@classmethod
|
||||
def name(cls):
|
||||
return 'rfp'
|
||||
|
||||
@classmethod
|
||||
def capabilities(cls):
|
||||
return RunnerCaps(commands={'flash'}, erase=True)
|
||||
|
||||
@classmethod
|
||||
def do_add_parser(cls, parser):
|
||||
parser.add_argument(
|
||||
'--rfp-cli', default='rfp-cli', help='path to rfp-cli, default is rfp-cli'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--port',
|
||||
default=DEFAULT_RFP_PORT,
|
||||
help='serial port to use, default is ' + str(DEFAULT_RFP_PORT),
|
||||
)
|
||||
parser.add_argument('--device', help='Specify the device type to pass to rfp-cli')
|
||||
parser.add_argument('--verify', action='store_true', help='if given, verify after flash')
|
||||
parser.add_argument('--speed', help='Specify the serial port speed')
|
||||
|
||||
@classmethod
|
||||
def do_create(cls, cfg, args):
|
||||
return RfpBinaryRunner(
|
||||
cfg,
|
||||
rfp_cli=args.rfp_cli,
|
||||
device=args.device,
|
||||
port=args.port,
|
||||
erase=args.erase,
|
||||
speed=args.speed,
|
||||
verify=args.verify,
|
||||
)
|
||||
|
||||
def do_run(self, command, **kwargs):
|
||||
if command == 'flash':
|
||||
self.do_flash(**kwargs)
|
||||
else:
|
||||
self.logger.error("Unsuppported command")
|
||||
|
||||
def do_flash(self, **kwargs):
|
||||
self.ensure_output('hex')
|
||||
|
||||
hex_name = self.cfg.hex_file
|
||||
|
||||
self.logger.info(f'Flashing file: {hex_name}')
|
||||
|
||||
load_image = ['-run']
|
||||
if self.erase:
|
||||
load_image += ['-erase']
|
||||
else:
|
||||
load_image += ['-noerase']
|
||||
|
||||
if self.verify:
|
||||
load_image += ['-v']
|
||||
|
||||
# Load image
|
||||
load_image += ['-p', '-file', hex_name]
|
||||
|
||||
port = ['-port', self.port]
|
||||
if self.speed:
|
||||
port += ['-s', self.speed]
|
||||
device = ['-device', self.device]
|
||||
|
||||
cmd = self.rfp_cmd + port + device + load_image
|
||||
self.check_call(cmd)
|
|
@ -46,6 +46,7 @@ def test_runner_imports():
|
|||
'qemu',
|
||||
'renode',
|
||||
'renode-robot',
|
||||
'rfp',
|
||||
'silabs_commander',
|
||||
'spi_burn',
|
||||
'stm32cubeprogrammer',
|
||||
|
|
256
scripts/west_commands/tests/test_rfp.py
Normal file
256
scripts/west_commands/tests/test_rfp.py
Normal file
|
@ -0,0 +1,256 @@
|
|||
# Copyright (c) 2025 Pete Johanson
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from unittest.mock import call, patch
|
||||
|
||||
from conftest import RC_KERNEL_HEX
|
||||
from runners.rfp import RfpBinaryRunner
|
||||
|
||||
TEST_RFP_PORT = 'test-rfp-serial'
|
||||
TEST_RFP_PORT_SPEED = '115200'
|
||||
TEST_RFP_DEVICE = 'RA'
|
||||
TEST_RFP_USR_LOCAL_RFP_CLI = '/usr/local/bin/rfp-cli'
|
||||
|
||||
EXPECTED_COMMANDS = [
|
||||
[
|
||||
'rfp-cli',
|
||||
'-port',
|
||||
TEST_RFP_PORT,
|
||||
'-device',
|
||||
TEST_RFP_DEVICE,
|
||||
'-run',
|
||||
'-noerase',
|
||||
'-p',
|
||||
'-file',
|
||||
RC_KERNEL_HEX,
|
||||
],
|
||||
]
|
||||
|
||||
EXPECTED_COMMANDS_WITH_SPEED = [
|
||||
[
|
||||
'rfp-cli',
|
||||
'-port',
|
||||
TEST_RFP_PORT,
|
||||
'-s',
|
||||
TEST_RFP_PORT_SPEED,
|
||||
'-device',
|
||||
TEST_RFP_DEVICE,
|
||||
'-run',
|
||||
'-noerase',
|
||||
'-p',
|
||||
'-file',
|
||||
RC_KERNEL_HEX,
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
EXPECTED_COMMANDS_WITH_ERASE = [
|
||||
[
|
||||
'rfp-cli',
|
||||
'-port',
|
||||
TEST_RFP_PORT,
|
||||
'-device',
|
||||
TEST_RFP_DEVICE,
|
||||
'-run',
|
||||
'-erase',
|
||||
'-p',
|
||||
'-file',
|
||||
RC_KERNEL_HEX,
|
||||
],
|
||||
]
|
||||
|
||||
EXPECTED_COMMANDS_WITH_VERIFY = [
|
||||
[
|
||||
'rfp-cli',
|
||||
'-port',
|
||||
TEST_RFP_PORT,
|
||||
'-device',
|
||||
TEST_RFP_DEVICE,
|
||||
'-run',
|
||||
'-noerase',
|
||||
'-v',
|
||||
'-p',
|
||||
'-file',
|
||||
RC_KERNEL_HEX,
|
||||
],
|
||||
]
|
||||
|
||||
EXPECTED_COMMANDS_WITH_RFP_CLI = [
|
||||
[
|
||||
TEST_RFP_USR_LOCAL_RFP_CLI,
|
||||
'-port',
|
||||
TEST_RFP_PORT,
|
||||
'-device',
|
||||
TEST_RFP_DEVICE,
|
||||
'-run',
|
||||
'-noerase',
|
||||
'-p',
|
||||
'-file',
|
||||
RC_KERNEL_HEX,
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
def require_patch(program):
|
||||
assert program in ['rfp']
|
||||
|
||||
|
||||
os_path_isfile = os.path.isfile
|
||||
|
||||
|
||||
def os_path_isfile_patch(filename):
|
||||
if filename == RC_KERNEL_HEX:
|
||||
return True
|
||||
return os_path_isfile(filename)
|
||||
|
||||
|
||||
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
|
||||
@patch('runners.core.ZephyrBinaryRunner.check_call')
|
||||
def test_rfp_init(cc, req, runner_config, tmpdir):
|
||||
"""
|
||||
Test commands using a runner created by constructor.
|
||||
|
||||
Input:
|
||||
port=A
|
||||
device=B
|
||||
|
||||
Output:
|
||||
-port A
|
||||
-device B
|
||||
"""
|
||||
runner = RfpBinaryRunner(runner_config, port=TEST_RFP_PORT, device=TEST_RFP_DEVICE)
|
||||
with patch('os.path.isfile', side_effect=os_path_isfile_patch):
|
||||
runner.run('flash')
|
||||
assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS]
|
||||
|
||||
|
||||
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
|
||||
@patch('runners.core.ZephyrBinaryRunner.check_call')
|
||||
def test_rfp_create(cc, req, runner_config, tmpdir):
|
||||
"""
|
||||
Test commands using a runner created from command line parameters.
|
||||
|
||||
|
||||
Input:
|
||||
---port A
|
||||
--device B
|
||||
|
||||
Output:
|
||||
-port A
|
||||
-device B
|
||||
"""
|
||||
args = ['--port', str(TEST_RFP_PORT), "--device", str(TEST_RFP_DEVICE)]
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False)
|
||||
RfpBinaryRunner.add_parser(parser)
|
||||
arg_namespace = parser.parse_args(args)
|
||||
runner = RfpBinaryRunner.create(runner_config, arg_namespace)
|
||||
with patch('os.path.isfile', side_effect=os_path_isfile_patch):
|
||||
runner.run('flash')
|
||||
assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS]
|
||||
|
||||
|
||||
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
|
||||
@patch('runners.core.ZephyrBinaryRunner.check_call')
|
||||
def test_rfp_create_with_speed(cc, req, runner_config, tmpdir):
|
||||
"""
|
||||
Test commands using a runner created from command line parameters.
|
||||
|
||||
Input:
|
||||
--port
|
||||
--speed
|
||||
--speed
|
||||
|
||||
Output:
|
||||
-s SPEED
|
||||
"""
|
||||
args = [
|
||||
'--device',
|
||||
str(TEST_RFP_DEVICE),
|
||||
'--port',
|
||||
str(TEST_RFP_PORT),
|
||||
'--speed',
|
||||
str(TEST_RFP_PORT_SPEED),
|
||||
]
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False)
|
||||
RfpBinaryRunner.add_parser(parser)
|
||||
arg_namespace = parser.parse_args(args)
|
||||
runner = RfpBinaryRunner.create(runner_config, arg_namespace)
|
||||
with patch('os.path.isfile', side_effect=os_path_isfile_patch):
|
||||
runner.run('flash')
|
||||
assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_SPEED]
|
||||
|
||||
|
||||
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
|
||||
@patch('runners.core.ZephyrBinaryRunner.check_call')
|
||||
def test_rfp_create_with_erase(cc, req, runner_config, tmpdir):
|
||||
"""
|
||||
Test commands using a runner created from command line parameters.
|
||||
|
||||
Input:
|
||||
--erase
|
||||
|
||||
Output:
|
||||
-erase
|
||||
"""
|
||||
args = ['--device', str(TEST_RFP_DEVICE), '--port', str(TEST_RFP_PORT), '--erase']
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False)
|
||||
RfpBinaryRunner.add_parser(parser)
|
||||
arg_namespace = parser.parse_args(args)
|
||||
runner = RfpBinaryRunner.create(runner_config, arg_namespace)
|
||||
with patch('os.path.isfile', side_effect=os_path_isfile_patch):
|
||||
runner.run('flash')
|
||||
assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_ERASE]
|
||||
|
||||
|
||||
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
|
||||
@patch('runners.core.ZephyrBinaryRunner.check_call')
|
||||
def test_rfp_create_with_verify(cc, req, runner_config, tmpdir):
|
||||
"""
|
||||
Test commands using a runner created from command line parameters.
|
||||
|
||||
Input:
|
||||
--verify
|
||||
|
||||
Output:
|
||||
-v
|
||||
"""
|
||||
args = ['--device', str(TEST_RFP_DEVICE), '--port', str(TEST_RFP_PORT), '--verify']
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False)
|
||||
RfpBinaryRunner.add_parser(parser)
|
||||
arg_namespace = parser.parse_args(args)
|
||||
runner = RfpBinaryRunner.create(runner_config, arg_namespace)
|
||||
with patch('os.path.isfile', side_effect=os_path_isfile_patch):
|
||||
runner.run('flash')
|
||||
assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_VERIFY]
|
||||
|
||||
|
||||
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
|
||||
@patch('runners.core.ZephyrBinaryRunner.check_call')
|
||||
def test_rfp_create_with_rfp_cli(cc, req, runner_config, tmpdir):
|
||||
"""
|
||||
Test commands using a runner created from command line parameters.
|
||||
|
||||
Input:
|
||||
--rfp-cli /usr/local/bin/rfp-cli
|
||||
|
||||
Output:
|
||||
/usr/local/bin/rfp-cli
|
||||
"""
|
||||
args = [
|
||||
'--device',
|
||||
str(TEST_RFP_DEVICE),
|
||||
'--port',
|
||||
str(TEST_RFP_PORT),
|
||||
'--rfp-cli',
|
||||
str(TEST_RFP_USR_LOCAL_RFP_CLI),
|
||||
]
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False)
|
||||
RfpBinaryRunner.add_parser(parser)
|
||||
arg_namespace = parser.parse_args(args)
|
||||
runner = RfpBinaryRunner.create(runner_config, arg_namespace)
|
||||
with patch('os.path.isfile', side_effect=os_path_isfile_patch):
|
||||
runner.run('flash')
|
||||
assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_RFP_CLI]
|
Loading…
Add table
Add a link
Reference in a new issue