1# Copyright (c) 2018 Foundries.io 2# Copyright (c) 2019 Nordic Semiconductor ASA. 3# Copyright (c) 2020-2021 Gerson Fernando Budke <nandojve@gmail.com> 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import argparse 8import os 9import platform 10from unittest.mock import patch, call 11 12import pytest 13 14from runners.bossac import BossacBinaryRunner 15from conftest import RC_KERNEL_BIN 16 17if platform.system() != 'Linux': 18 pytest.skip("skipping Linux-only bossac tests", allow_module_level=True) 19 20TEST_BOSSAC_PORT = 'test-bossac-serial' 21TEST_BOSSAC_SPEED = '1200' 22TEST_OFFSET = 1234 23TEST_FLASH_ADDRESS = 5678 24TEST_BOARD_NAME = "my_board" 25 26EXPECTED_COMMANDS = [ 27 ['stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '115200', 28 'ospeed', '115200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', 29 'eof', '255'], 30 ['bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', 31 '-b', RC_KERNEL_BIN], 32] 33 34EXPECTED_COMMANDS_WITH_SPEED = [ 35 ['stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', TEST_BOSSAC_SPEED, 36 'ospeed', TEST_BOSSAC_SPEED, 'cs8', '-cstopb', 'ignpar', 'eol', '255', 37 'eof', '255'], 38 ['bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', 39 '-b', RC_KERNEL_BIN], 40] 41 42EXPECTED_COMMANDS_WITH_OFFSET = [ 43 ['stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '115200', 44 'ospeed', '115200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', 45 'eof', '255'], 46 ['bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', 47 '-b', RC_KERNEL_BIN, '-o', str(TEST_OFFSET)], 48] 49 50EXPECTED_COMMANDS_WITH_FLASH_ADDRESS = [ 51 [ 52 'stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '115200', 53 'ospeed', '115200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', 54 'eof', '255' 55 ], 56 [ 57 'bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', 58 '-b', RC_KERNEL_BIN, '-o', str(TEST_FLASH_ADDRESS), 59 ], 60] 61 62EXPECTED_COMMANDS_WITH_EXTENDED = [ 63 [ 64 'stty', '-F', TEST_BOSSAC_PORT, 'raw', 'ispeed', '1200', 65 'ospeed', '1200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', 66 'eof', '255' 67 ], 68 [ 69 'bossac', '-p', TEST_BOSSAC_PORT, '-R', '-e', '-w', '-v', 70 '-b', RC_KERNEL_BIN, '-o', str(TEST_FLASH_ADDRESS), 71 ], 72] 73 74# SAM-BA ROM without offset 75# No code partition Kconfig 76# No zephyr,code-partition (defined on DT) 77DOTCONFIG_STD = f''' 78CONFIG_BOARD="{TEST_BOARD_NAME}" 79CONFIG_FLASH_LOAD_OFFSET=0x162e 80''' 81 82# SAM-BA ROM/FLASH with offset 83DOTCONFIG_COND1 = f''' 84CONFIG_BOARD="{TEST_BOARD_NAME}" 85CONFIG_USE_DT_CODE_PARTITION=y 86CONFIG_HAS_FLASH_LOAD_OFFSET=y 87CONFIG_FLASH_LOAD_OFFSET=0x162e 88''' 89 90# SAM-BA ROM/FLASH without offset 91# No code partition Kconfig 92DOTCONFIG_COND2 = f''' 93CONFIG_BOARD="{TEST_BOARD_NAME}" 94CONFIG_HAS_FLASH_LOAD_OFFSET=y 95CONFIG_FLASH_LOAD_OFFSET=0x162e 96''' 97 98# SAM-BA Extended Arduino with offset 99DOTCONFIG_COND3 = f''' 100CONFIG_BOARD="{TEST_BOARD_NAME}" 101CONFIG_USE_DT_CODE_PARTITION=y 102CONFIG_BOOTLOADER_BOSSA_ARDUINO=y 103CONFIG_HAS_FLASH_LOAD_OFFSET=y 104CONFIG_FLASH_LOAD_OFFSET=0x162e 105''' 106 107# SAM-BA Extended Adafruit with offset 108DOTCONFIG_COND4 = f''' 109CONFIG_BOARD="{TEST_BOARD_NAME}" 110CONFIG_USE_DT_CODE_PARTITION=y 111CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y 112CONFIG_HAS_FLASH_LOAD_OFFSET=y 113CONFIG_FLASH_LOAD_OFFSET=0x162e 114''' 115 116# SAM-BA omit offset 117DOTCONFIG_COND5 = f''' 118CONFIG_BOARD="{TEST_BOARD_NAME}" 119CONFIG_USE_DT_CODE_PARTITION=y 120CONFIG_HAS_FLASH_LOAD_OFFSET=y 121CONFIG_FLASH_LOAD_OFFSET=0x0 122''' 123 124# SAM-BA Legacy Mode 125DOTCONFIG_COND6 = f''' 126CONFIG_BOARD="{TEST_BOARD_NAME}" 127CONFIG_USE_DT_CODE_PARTITION=y 128CONFIG_BOOTLOADER_BOSSA_LEGACY=y 129CONFIG_HAS_FLASH_LOAD_OFFSET=y 130CONFIG_FLASH_LOAD_OFFSET=0x162e 131''' 132 133def adjust_runner_config(runner_config, tmpdir, dotconfig): 134 # Adjust a RunnerConfig object, 'runner_config', by 135 # replacing its build directory with 'tmpdir' after writing 136 # the contents of 'dotconfig' to tmpdir/zephyr/.config. 137 138 zephyr = tmpdir / 'zephyr' 139 zephyr.mkdir() 140 with open(zephyr / '.config', 'w') as f: 141 f.write(dotconfig) 142 return runner_config._replace(build_dir=os.fspath(tmpdir)) 143 144def require_patch(program): 145 assert program in ['bossac', 'stty'] 146 147os_path_isfile = os.path.isfile 148 149def os_path_isfile_patch(filename): 150 if filename == RC_KERNEL_BIN: 151 return True 152 return os_path_isfile(filename) 153 154@patch('runners.bossac.BossacBinaryRunner.supports', 155 return_value=False) 156@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 157 return_value=None) 158@patch('runners.core.ZephyrBinaryRunner.require', 159 side_effect=require_patch) 160@patch('runners.core.ZephyrBinaryRunner.check_call') 161def test_bossac_init(cc, req, get_cod_par, sup, runner_config, tmpdir): 162 """ 163 Test commands using a runner created by constructor. 164 165 Requirements: 166 Any SDK 167 168 Configuration: 169 ROM bootloader 170 CONFIG_USE_DT_CODE_PARTITION=n 171 without zephyr,code-partition 172 173 Input: 174 none 175 176 Output: 177 no --offset 178 """ 179 runner_config = adjust_runner_config(runner_config, tmpdir, DOTCONFIG_STD) 180 runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) 181 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 182 runner.run('flash') 183 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS] 184 185 186@patch('runners.bossac.BossacBinaryRunner.supports', 187 return_value=False) 188@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 189 return_value=None) 190@patch('runners.core.ZephyrBinaryRunner.require', 191 side_effect=require_patch) 192@patch('runners.core.ZephyrBinaryRunner.check_call') 193def test_bossac_create(cc, req, get_cod_par, sup, runner_config, tmpdir): 194 """ 195 Test commands using a runner created from command line parameters. 196 197 Requirements: 198 Any SDK 199 200 Configuration: 201 ROM bootloader 202 CONFIG_USE_DT_CODE_PARTITION=n 203 without zephyr,code-partition 204 205 Input: 206 --bossac-port 207 208 Output: 209 no --offset 210 """ 211 args = ['--bossac-port', str(TEST_BOSSAC_PORT)] 212 parser = argparse.ArgumentParser() 213 BossacBinaryRunner.add_parser(parser) 214 arg_namespace = parser.parse_args(args) 215 runner_config = adjust_runner_config(runner_config, tmpdir, DOTCONFIG_STD) 216 runner = BossacBinaryRunner.create(runner_config, arg_namespace) 217 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 218 runner.run('flash') 219 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS] 220 221 222@patch('runners.bossac.BossacBinaryRunner.supports', 223 return_value=False) 224@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 225 return_value=None) 226@patch('runners.core.ZephyrBinaryRunner.require', 227 side_effect=require_patch) 228@patch('runners.core.ZephyrBinaryRunner.check_call') 229def test_bossac_create_with_speed(cc, req, get_cod_par, sup, runner_config, tmpdir): 230 """ 231 Test commands using a runner created from command line parameters. 232 233 Requirements: 234 Any SDK 235 236 Configuration: 237 ROM bootloader 238 CONFIG_USE_DT_CODE_PARTITION=n 239 without zephyr,code-partition 240 241 Input: 242 --bossac-port 243 --speed 244 245 Output: 246 no --offset 247 """ 248 args = ['--bossac-port', str(TEST_BOSSAC_PORT), 249 '--speed', str(TEST_BOSSAC_SPEED)] 250 parser = argparse.ArgumentParser() 251 BossacBinaryRunner.add_parser(parser) 252 arg_namespace = parser.parse_args(args) 253 runner_config = adjust_runner_config(runner_config, tmpdir, DOTCONFIG_STD) 254 runner = BossacBinaryRunner.create(runner_config, arg_namespace) 255 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 256 runner.run('flash') 257 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_SPEED] 258 259 260@patch('runners.bossac.BossacBinaryRunner.supports', 261 return_value=True) 262@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 263 return_value=True) 264@patch('runners.core.ZephyrBinaryRunner.require', 265 side_effect=require_patch) 266@patch('runners.core.ZephyrBinaryRunner.check_call') 267def test_bossac_create_with_flash_address(cc, req, get_cod_par, sup, 268 runner_config, tmpdir): 269 """ 270 Test command with offset parameter 271 272 Requirements: 273 SDK >= 0.12.0 274 275 Configuration: 276 Any bootloader 277 CONFIG_USE_DT_CODE_PARTITION=y 278 with zephyr,code-partition 279 280 Input: 281 --bossac-port 282 283 Output: 284 --offset 285 """ 286 args = [ 287 '--bossac-port', 288 str(TEST_BOSSAC_PORT), 289 ] 290 parser = argparse.ArgumentParser() 291 BossacBinaryRunner.add_parser(parser) 292 arg_namespace = parser.parse_args(args) 293 runner_config = adjust_runner_config(runner_config, tmpdir, 294 DOTCONFIG_COND1) 295 runner = BossacBinaryRunner.create(runner_config, arg_namespace) 296 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 297 runner.run('flash') 298 assert cc.call_args_list == [ 299 call(x) for x in EXPECTED_COMMANDS_WITH_FLASH_ADDRESS 300 ] 301 302 303@patch('runners.bossac.BossacBinaryRunner.supports', 304 return_value=False) 305@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 306 return_value=True) 307@patch('runners.core.ZephyrBinaryRunner.require', 308 side_effect=require_patch) 309@patch('runners.core.ZephyrBinaryRunner.check_call') 310def test_bossac_create_with_omit_address(cc, req, bcfg_ini, sup, 311 runner_config, tmpdir): 312 """ 313 Test command that will omit offset because CONFIG_FLASH_LOAD_OFFSET is 0. 314 This case is valid for ROM bootloaders that define image start at 0 and 315 define flash partitions, to use the storage capabilities, for instance. 316 317 Requirements: 318 Any SDK 319 320 Configuration: 321 ROM bootloader 322 CONFIG_USE_DT_CODE_PARTITION=y 323 with zephyr,code-partition 324 325 Input: 326 --bossac-port 327 328 Output: 329 no --offset 330 """ 331 runner_config = adjust_runner_config(runner_config, tmpdir, 332 DOTCONFIG_COND5) 333 runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) 334 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 335 runner.run('flash') 336 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS] 337 338 339@patch('runners.bossac.BossacBinaryRunner.supports', 340 return_value=True) 341@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 342 return_value=True) 343@patch('runners.core.ZephyrBinaryRunner.require', 344 side_effect=require_patch) 345@patch('runners.core.ZephyrBinaryRunner.check_call') 346def test_bossac_create_with_arduino(cc, req, get_cod_par, sup, 347 runner_config, tmpdir): 348 """ 349 Test SAM-BA extended protocol with Arduino variation 350 351 Requirements: 352 SDK >= 0.12.0 353 354 Configuration: 355 Extended bootloader 356 CONFIG_USE_DT_CODE_PARTITION=y 357 CONFIG_BOOTLOADER_BOSSA_ARDUINO=y 358 with zephyr,code-partition 359 360 Input: 361 --bossac-port 362 363 Output: 364 --offset 365 """ 366 runner_config = adjust_runner_config(runner_config, tmpdir, 367 DOTCONFIG_COND3) 368 runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) 369 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 370 runner.run('flash') 371 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_EXTENDED] 372 373@patch('runners.bossac.BossacBinaryRunner.supports', 374 return_value=True) 375@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 376 return_value=True) 377@patch('runners.core.ZephyrBinaryRunner.require', 378 side_effect=require_patch) 379@patch('runners.core.ZephyrBinaryRunner.check_call') 380def test_bossac_create_with_adafruit(cc, req, get_cod_par, sup, 381 runner_config, tmpdir): 382 """ 383 Test SAM-BA extended protocol with Adafruit UF2 variation 384 385 Requirements: 386 SDK >= 0.12.0 387 388 Configuration: 389 Extended bootloader 390 CONFIG_USE_DT_CODE_PARTITION=y 391 CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y 392 with zephyr,code-partition 393 394 Input: 395 --bossac-port 396 397 Output: 398 --offset 399 """ 400 runner_config = adjust_runner_config(runner_config, tmpdir, 401 DOTCONFIG_COND4) 402 runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) 403 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 404 runner.run('flash') 405 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS_WITH_EXTENDED] 406 407 408@patch('runners.bossac.BossacBinaryRunner.supports', 409 return_value=True) 410@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 411 return_value=True) 412@patch('runners.core.ZephyrBinaryRunner.require', 413 side_effect=require_patch) 414@patch('runners.core.ZephyrBinaryRunner.check_call') 415def test_bossac_create_with_legacy(cc, req, get_cod_par, sup, 416 runner_config, tmpdir): 417 """ 418 Test SAM-BA legacy protocol 419 420 Requirements: 421 Any SDK 422 423 Configuration: 424 Extended bootloader 425 CONFIG_USE_DT_CODE_PARTITION=y 426 CONFIG_BOOTLOADER_BOSSA_LEGACY=y 427 with zephyr,code-partition 428 429 Input: 430 --bossac-port 431 432 Output: 433 no --offset 434 """ 435 runner_config = adjust_runner_config(runner_config, tmpdir, 436 DOTCONFIG_COND6) 437 runner = BossacBinaryRunner(runner_config, port=TEST_BOSSAC_PORT) 438 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 439 runner.run('flash') 440 assert cc.call_args_list == [call(x) for x in EXPECTED_COMMANDS] 441 442 443@patch('runners.bossac.BossacBinaryRunner.supports', 444 return_value=False) 445@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 446 return_value=True) 447@patch('runners.core.ZephyrBinaryRunner.require', 448 side_effect=require_patch) 449@patch('runners.core.ZephyrBinaryRunner.check_call') 450def test_bossac_create_with_oldsdk(cc, req, get_cod_par, sup, 451 runner_config, tmpdir): 452 """ 453 Test old SDK and ask user to upgrade 454 455 Requirements: 456 SDK <= 0.12.0 457 458 Configuration: 459 Any bootloader 460 CONFIG_USE_DT_CODE_PARTITION=y 461 with zephyr,code-partition 462 463 Input: 464 465 Output: 466 Abort 467 """ 468 runner_config = adjust_runner_config(runner_config, tmpdir, 469 DOTCONFIG_COND1) 470 runner = BossacBinaryRunner(runner_config) 471 with pytest.raises(RuntimeError) as rinfo: 472 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 473 runner.run('flash') 474 assert str(rinfo.value) == "This version of BOSSA does not support the" \ 475 " --offset flag. Please upgrade to a newer" \ 476 " Zephyr SDK version >= 0.12.0." 477 478 479@patch('runners.bossac.BossacBinaryRunner.supports', 480 return_value=False) 481@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 482 return_value=None) 483@patch('runners.core.ZephyrBinaryRunner.require', 484 side_effect=require_patch) 485@patch('runners.core.ZephyrBinaryRunner.check_call') 486def test_bossac_create_error_missing_dt_info(cc, req, get_cod_par, sup, 487 runner_config, tmpdir): 488 """ 489 Test SAM-BA offset wrong configuration. No chosen code partition. 490 491 Requirements: 492 Any SDK 493 494 Configuration: 495 Any bootloader 496 CONFIG_USE_DT_CODE_PARTITION=y 497 with zephyr,code-partition (missing) 498 499 Input: 500 501 Output: 502 Abort 503 """ 504 runner_config = adjust_runner_config(runner_config, tmpdir, 505 DOTCONFIG_COND1) 506 runner = BossacBinaryRunner(runner_config) 507 with pytest.raises(RuntimeError) as rinfo: 508 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 509 runner.run('flash') 510 assert str(rinfo.value) == "The device tree zephyr,code-partition" \ 511 " chosen node must be defined." 512 513 514@patch('runners.bossac.BossacBinaryRunner.supports', 515 return_value=False) 516@patch('runners.bossac.BossacBinaryRunner.get_chosen_code_partition_node', 517 return_value=True) 518@patch('runners.core.ZephyrBinaryRunner.require', 519 side_effect=require_patch) 520@patch('runners.core.ZephyrBinaryRunner.check_call') 521def test_bossac_create_error_missing_kconfig(cc, req, get_cod_par, sup, 522 runner_config, tmpdir): 523 """ 524 Test SAM-BA offset wrong configuration. No CONFIG_USE_DT_CODE_PARTITION 525 Kconfig definition. 526 527 Requirements: 528 Any SDK 529 530 Configuration: 531 Any bootloader 532 CONFIG_USE_DT_CODE_PARTITION=y (missing) 533 with zephyr,code-partition 534 535 Input: 536 537 Output: 538 Abort 539 """ 540 runner_config = adjust_runner_config(runner_config, tmpdir, 541 DOTCONFIG_COND2) 542 runner = BossacBinaryRunner(runner_config) 543 with pytest.raises(RuntimeError) as rinfo: 544 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 545 runner.run('flash') 546 assert str(rinfo.value) == \ 547 "There is no CONFIG_USE_DT_CODE_PARTITION Kconfig defined at " \ 548 + TEST_BOARD_NAME + "_defconfig file.\n This means that" \ 549 " zephyr,code-partition device tree node should not be defined." \ 550 " Check Zephyr SAM-BA documentation." 551