Skip to content

Commit 6f00312

Browse files
committed
mbed_base: Fix copy_method.check_flash_error
After copying an image to a device using a "copy method" plugin, we attempt to check if any flash errors were encountered. We search for a FAIL.txt file on a Daplink compatible device's USB mass storage, if the file is present, we decide an error has occured and return False. mbedls.detect is used to enumerate all daplink/Mbed devices if a target_id is passed. The target_id often comes from the USB serial ID, which bears no relation to whether the device is Mbed enabled/Daplink compatible or not. If no target_id is given the function returns True without checking for FAIL.TXT at all. This check is not strong enough to cover all cases where a user would potentially not be using an Mbed device. One example where the above check is not fit for purpose: The user has specified the pyocd copy method. pyocd supports devices which are not "Mbed Enabled" or Daplink compatible, but the user must pass a target_id because pyocd requires it. In this case we would waste 2.5s repeatedly checking with mbedls.detect if an Mbed/Daplink device was connected. We could also emit a warning message stating their device was detected but not mounted, advising them to "pass -u to show the device". Unfortunately this information is incorrect, as the "-u" option is an option in mbedls's CLI and not mbedhtrun's CLI. This causes confusion and irritation for the user. It seems the only "Mbed specific" copy methods are actually named "shell" and "default" (however "shell" appears to be the actual default used if no copy method is specified on the command line). So the least intrusive fix is to check if we're using one of the mbedls-compatible copy_methods, and if not, just return True, just like we do when no target_id is given. This fixes the delay and unecessary warning when specifying the pyocd copy method with a non-Mbed device.
1 parent ac6c00b commit 6f00312

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

src/mbed_os_tools/test/host_tests_runner/mbed_base.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,19 @@ def check_flash_error(target_id, disk, initial_remount_count):
123123
self.logger.prn_wrn("Target ID not found: Skipping flash check and retry")
124124
return True
125125

126+
if not copy_method in ["shell", "default"]:
127+
# We're using a "copy method" that may not necessarily require
128+
# an "Mbed Enabled" device. In this case we shouldn't use
129+
# mbedls.detect to attempt to rediscover the mount point, as
130+
# mbedls.detect is only compatible with Mbed Enabled devices.
131+
# It's best just to return `True` and continue here. This will
132+
# avoid the inevitable 2.5s delay caused by us repeatedly
133+
# attempting to enumerate Mbed Enabled devices in the code
134+
# below when none are connected. The user has specified a
135+
# non-Mbed plugin copy method, so we shouldn't delay them by
136+
# trying to check for Mbed Enabled devices.
137+
return True
138+
126139
bad_files = set(['FAIL.TXT'])
127140
# Re-try at max 5 times with 0.5 sec in delay
128141
for i in range(5):

test/test/test_mbed_base.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Copyright (c) 2021, Arm Limited and affiliates.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
import shutil
16+
import mock
17+
import os
18+
import unittest
19+
from tempfile import mkdtemp
20+
21+
from mbed_os_tools.test.host_tests_runner.mbed_base import Mbed
22+
23+
class TemporaryDirectory(object):
24+
def __init__(self):
25+
self.fname = "tempdir"
26+
27+
def __enter__(self):
28+
self.fname = mkdtemp()
29+
return self.fname
30+
31+
def __exit__(self, *args, **kwargs):
32+
shutil.rmtree(self.fname)
33+
34+
@mock.patch("mbed_os_tools.test.host_tests_runner.mbed_base.ht_plugins")
35+
@mock.patch("mbed_os_tools.test.host_tests_runner.mbed_base.detect")
36+
class TestMbed(unittest.TestCase):
37+
def test_skips_discover_mbed_if_non_mbed_copy_method_used(
38+
self, mock_detect, mock_ht_plugins
39+
):
40+
with TemporaryDirectory() as tmpdir:
41+
image_path = os.path.join(tmpdir, "test.elf")
42+
with open(image_path, "w") as f:
43+
f.write("1234")
44+
45+
options = mock.Mock(
46+
copy_method="pyocd",
47+
image_path=image_path,
48+
disk=None,
49+
port="port",
50+
micro="mcu",
51+
target_id="BK99",
52+
polling_timeout=5,
53+
program_cycle_s=None,
54+
json_test_configuration=None,
55+
format="blah",
56+
)
57+
58+
mbed = Mbed(options)
59+
mbed.copy_image()
60+
61+
mock_detect.create().list_mbeds.assert_not_called()
62+
mock_ht_plugins.call_plugin.assert_called_once_with(
63+
"CopyMethod",
64+
options.copy_method,
65+
image_path=options.image_path,
66+
mcu=options.micro,
67+
serial=options.port,
68+
destination_disk=options.disk,
69+
target_id=options.target_id,
70+
pooling_timeout=options.polling_timeout,
71+
format=options.format,
72+
)
73+
74+
def test_discovers_mbed_if_mbed_copy_method_used(
75+
self, mock_detect, mock_ht_plugins
76+
):
77+
with TemporaryDirectory() as tmpdir:
78+
image_path = os.path.join(tmpdir, "test.elf")
79+
with open(image_path, "w") as f:
80+
f.write("1234")
81+
options = mock.Mock(
82+
copy_method="shell",
83+
image_path=image_path,
84+
disk=None,
85+
port="port",
86+
micro="mcu",
87+
target_id="BK99",
88+
polling_timeout=5,
89+
program_cycle_s=None,
90+
json_test_configuration=None,
91+
format="blah",
92+
)
93+
94+
mbed = Mbed(options)
95+
mbed.copy_image()
96+
97+
mock_detect.create().list_mbeds.assert_called()
98+
mock_ht_plugins.call_plugin.assert_called_once_with(
99+
"CopyMethod",
100+
options.copy_method,
101+
image_path=options.image_path,
102+
mcu=options.micro,
103+
serial=options.port,
104+
destination_disk=options.disk,
105+
target_id=options.target_id,
106+
pooling_timeout=options.polling_timeout,
107+
format=options.format,
108+
)
109+
110+
111+
if __name__ == "__main__":
112+
unittest.main()

0 commit comments

Comments
 (0)