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