| # Copyright (c) 2018 Foundries.io |
| # Copyright (c) 2019 Nordic Semiconductor ASA. |
| # Copyright (c) 2020-2021 Gerson Fernando Budke <nandojve@gmail.com> |
| # |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| import argparse |
| import os |
| import platform |
| from unittest.mock import patch, call |
| |
| import pytest |
| |
| from runners.bossac import BossacBinaryRunner |
| from conftest import RC_KERNEL_BIN |
| |
| if platform.system() != 'Linux': |
| pytest.skip("skipping Linux-only bossac tests", allow_module_level=True) |
| |
| TEST_BOSSAC_PORT = 'test-bossac-serial' |
| TEST_BOSSAC_SPEED = '1200' |
| TEST_OFFSET = 1234 |
| TEST_FLASH_ADDRESS = 5678 |
| TEST_BOARD_NAME = "my_board" |
| |
| EXPECTED_COMMANDS = [ |
| ['stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '115200', |
| 'ospeed', '115200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', |
| 'eof', '255'], |
| ['bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', |
| '-b', RC_KERNEL_BIN], |
| ] |
| |
| EXPECTED_COMMANDS_WITH_SPEED = [ |
| ['stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', TEST_BOSSAC_SPEED, |
| 'ospeed', TEST_BOSSAC_SPEED, 'cs8', '-cstopb', 'ignpar', 'eol', '255', |
| 'eof', '255'], |
| ['bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', |
| '-b', RC_KERNEL_BIN], |
| ] |
| |
| EXPECTED_COMMANDS_WITH_OFFSET = [ |
| ['stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '115200', |
| 'ospeed', '115200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', |
| 'eof', '255'], |
| ['bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', |
| '-b', RC_KERNEL_BIN, '-o', str(TEST_OFFSET)], |
| ] |
| |
| EXPECTED_COMMANDS_WITH_FLASH_ADDRESS = [ |
| [ |
| 'stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '115200', |
| 'ospeed', '115200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', |
| 'eof', '255' |
| ], |
| [ |
| 'bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', |
| '-b', RC_KERNEL_BIN, '-o', str(TEST_FLASH_ADDRESS), |
| ], |
| ] |
| |
| EXPECTED_COMMANDS_WITH_EXTENDED = [ |
| [ |
| 'stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '1200', |
| 'ospeed', '1200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', |
| 'eof', '255' |
| ], |
| [ |
| 'bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', |
| '-b', RC_KERNEL_BIN, '-o', str(TEST_FLASH_ADDRESS), |
| ], |
| ] |
| |
| # SAM-BA ROM without offset |
| # No code partition Kconfig |
| # No zephyr,code-partition (defined on DT) |
| DOTCONFIG_STD = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_FLASH_LOAD_OFFSET=0x162e |
| ''' |
| |
| # SAM-BA ROM/FLASH with offset |
| DOTCONFIG_COND1 = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_HAS_FLASH_LOAD_OFFSET=y |
| CONFIG_FLASH_LOAD_OFFSET=0x162e |
| ''' |
| |
| # SAM-BA ROM/FLASH without offset |
| # No code partition Kconfig |
| DOTCONFIG_COND2 = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_HAS_FLASH_LOAD_OFFSET=y |
| CONFIG_FLASH_LOAD_OFFSET=0x162e |
| ''' |
| |
| # SAM-BA Extended Arduino with offset |
| DOTCONFIG_COND3 = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_BOOTLOADER_BOSSA_ARDUINO=y |
| CONFIG_HAS_FLASH_LOAD_OFFSET=y |
| CONFIG_FLASH_LOAD_OFFSET=0x162e |
| ''' |
| |
| # SAM-BA Extended Adafruit with offset |
| DOTCONFIG_COND4 = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y |
| CONFIG_HAS_FLASH_LOAD_OFFSET=y |
| CONFIG_FLASH_LOAD_OFFSET=0x162e |
| ''' |
| |
| # SAM-BA omit offset |
| DOTCONFIG_COND5 = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_HAS_FLASH_LOAD_OFFSET=y |
| CONFIG_FLASH_LOAD_OFFSET=0x0 |
| ''' |
| |
| # SAM-BA Legacy Mode |
| DOTCONFIG_COND6 = f''' |
| CONFIG_BOARD="{TEST_BOARD_NAME}" |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_BOOTLOADER_BOSSA_LEGACY=y |
| CONFIG_HAS_FLASH_LOAD_OFFSET=y |
| CONFIG_FLASH_LOAD_OFFSET=0x162e |
| ''' |
| |
| def adjust_runner_config(runner_config, tmpdir, dotconfig): |
| # Adjust a RunnerConfig object, 'runner_config', by |
| # replacing its build directory with 'tmpdir' after writing |
| # the contents of 'dotconfig' to tmpdir/zephyr/.config. |
| |
| zephyr = tmpdir / 'zephyr' |
| zephyr.mkdir() |
| with open(zephyr / '.config', 'w') as f: |
| f.write(dotconfig) |
| return runner_config._replace(build_dir=os.fspath(tmpdir)) |
| |
| def require_patch(program): |
| assert program in ['bossac', 'stty'] |
| |
| os_path_isfile = os.path.isfile |
| |
| def os_path_isfile_patch(filename): |
| if filename == RC_KERNEL_BIN: |
| return True |
| return os_path_isfile(filename) |
| |
| @patch('runners.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=None) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_init(cc, req, get_cod_par, sup, runner_config, tmpdir): |
| """ |
| Test commands using a runner created by constructor. |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| ROM bootloader |
| CONFIG_USE_DT_CODE_PARTITION=n |
| without zephyr,code-partition |
| |
| Input: |
| none |
| |
| Output: |
| no --offset |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, DOTCONFIG_STD) |
| runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) |
| 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.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=None) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create(cc, req, get_cod_par, sup, runner_config, tmpdir): |
| """ |
| Test commands using a runner created from command line parameters. |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| ROM bootloader |
| CONFIG_USE_DT_CODE_PARTITION=n |
| without zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| |
| Output: |
| no --offset |
| """ |
| args = ['--bossac-port', str(TEST_BOSSAC_PORT)] |
| parser = argparse.ArgumentParser() |
| BossacBinaryRunner.add_parser(parser) |
| arg_namespace = parser.parse_args(args) |
| runner_config = adjust_runner_config(runner_config, tmpdir, DOTCONFIG_STD) |
| runner = BossacBinaryRunner.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.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=None) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_speed(cc, req, get_cod_par, sup, runner_config, tmpdir): |
| """ |
| Test commands using a runner created from command line parameters. |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| ROM bootloader |
| CONFIG_USE_DT_CODE_PARTITION=n |
| without zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| --speed |
| |
| Output: |
| no --offset |
| """ |
| args = ['--bossac-port', str(TEST_BOSSAC_PORT), |
| '--speed', str(TEST_BOSSAC_SPEED)] |
| parser = argparse.ArgumentParser() |
| BossacBinaryRunner.add_parser(parser) |
| arg_namespace = parser.parse_args(args) |
| runner_config = adjust_runner_config(runner_config, tmpdir, DOTCONFIG_STD) |
| runner = BossacBinaryRunner.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.bossac.BossacBinaryRunner.supports', |
| return_value=True) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_flash_address(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test command with offset parameter |
| |
| Requirements: |
| SDK >= 0.12.0 |
| |
| Configuration: |
| Any bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| with zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| |
| Output: |
| --offset |
| """ |
| args = [ |
| '--bossac-port', |
| str(TEST_BOSSAC_PORT), |
| ] |
| parser = argparse.ArgumentParser() |
| BossacBinaryRunner.add_parser(parser) |
| arg_namespace = parser.parse_args(args) |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND1) |
| runner = BossacBinaryRunner.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_FLASH_ADDRESS |
| ] |
| |
| |
| @patch('runners.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_omit_address(cc, req, bcfg_ini, sup, |
| runner_config, tmpdir): |
| """ |
| Test command that will omit offset because CONFIG_FLASH_LOAD_OFFSET is 0. |
| This case is valid for ROM bootloaders that define image start at 0 and |
| define flash partitions, to use the storage capabilities, for instance. |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| ROM bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| with zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| |
| Output: |
| no --offset |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND5) |
| runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) |
| 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.bossac.BossacBinaryRunner.supports', |
| return_value=True) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_arduino(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test SAM-BA extended protocol with Arduino variation |
| |
| Requirements: |
| SDK >= 0.12.0 |
| |
| Configuration: |
| Extended bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_BOOTLOADER_BOSSA_ARDUINO=y |
| with zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| |
| Output: |
| --offset |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND3) |
| runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) |
| 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_EXTENDED] |
| |
| @patch('runners.bossac.BossacBinaryRunner.supports', |
| return_value=True) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_adafruit(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test SAM-BA extended protocol with Adafruit UF2 variation |
| |
| Requirements: |
| SDK >= 0.12.0 |
| |
| Configuration: |
| Extended bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y |
| with zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| |
| Output: |
| --offset |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND4) |
| runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) |
| 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_EXTENDED] |
| |
| |
| @patch('runners.bossac.BossacBinaryRunner.supports', |
| return_value=True) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_legacy(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test SAM-BA legacy protocol |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| Extended bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| CONFIG_BOOTLOADER_BOSSA_LEGACY=y |
| with zephyr,code-partition |
| |
| Input: |
| --bossac-port |
| |
| Output: |
| no --offset |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND6) |
| runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) |
| 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.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_with_oldsdk(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test old SDK and ask user to upgrade |
| |
| Requirements: |
| SDK <= 0.12.0 |
| |
| Configuration: |
| Any bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| with zephyr,code-partition |
| |
| Input: |
| |
| Output: |
| Abort |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND1) |
| runner = BossacBinaryRunner(runner_config) |
| with pytest.raises(RuntimeError) as rinfo: |
| with patch('os.path.isfile', side_effect=os_path_isfile_patch): |
| runner.run('flash') |
| assert str(rinfo.value) == "This version of BOSSA does not support the" \ |
| " --offset flag. Please upgrade to a newer" \ |
| " Zephyr SDK version >= 0.12.0." |
| |
| |
| @patch('runners.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=None) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_error_missing_dt_info(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test SAM-BA offset wrong configuration. No chosen code partition. |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| Any bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y |
| with zephyr,code-partition (missing) |
| |
| Input: |
| |
| Output: |
| Abort |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND1) |
| runner = BossacBinaryRunner(runner_config) |
| with pytest.raises(RuntimeError) as rinfo: |
| with patch('os.path.isfile', side_effect=os_path_isfile_patch): |
| runner.run('flash') |
| assert str(rinfo.value) == "The device tree zephyr,code-partition" \ |
| " chosen node must be defined." |
| |
| |
| @patch('runners.bossac.BossacBinaryRunner.supports', |
| return_value=False) |
| @patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', |
| return_value=True) |
| @patch('runners.core.ZephyrBinaryRunner.require', |
| side_effect=require_patch) |
| @patch('runners.core.ZephyrBinaryRunner.check_call') |
| def test_bossac_create_error_missing_kconfig(cc, req, get_cod_par, sup, |
| runner_config, tmpdir): |
| """ |
| Test SAM-BA offset wrong configuration. No CONFIG_USE_DT_CODE_PARTITION |
| Kconfig definition. |
| |
| Requirements: |
| Any SDK |
| |
| Configuration: |
| Any bootloader |
| CONFIG_USE_DT_CODE_PARTITION=y (missing) |
| with zephyr,code-partition |
| |
| Input: |
| |
| Output: |
| Abort |
| """ |
| runner_config = adjust_runner_config(runner_config, tmpdir, |
| DOTCONFIG_COND2) |
| runner = BossacBinaryRunner(runner_config) |
| with pytest.raises(RuntimeError) as rinfo: |
| with patch('os.path.isfile', side_effect=os_path_isfile_patch): |
| runner.run('flash') |
| assert str(rinfo.value) == \ |
| "There is no CONFIG_USE_DT_CODE_PARTITION Kconfig defined at " \ |
| + TEST_BOARD_NAME + "_defconfig file.\n This means that" \ |
| " zephyr,code-partition device tree node should not be defined." \ |
| " Check Zephyr SAM-BA documentation." |