Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Committer:
Pawel Zarembski
Date:
Tue Apr 07 12:55:42 2020 +0200
Revision:
0:01f31e923fe2
hani: DAPLink with reset workaround

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Pawel Zarembski 0:01f31e923fe2 1 #
Pawel Zarembski 0:01f31e923fe2 2 # DAPLink Interface Firmware
Pawel Zarembski 0:01f31e923fe2 3 # Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
Pawel Zarembski 0:01f31e923fe2 4 # SPDX-License-Identifier: Apache-2.0
Pawel Zarembski 0:01f31e923fe2 5 #
Pawel Zarembski 0:01f31e923fe2 6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
Pawel Zarembski 0:01f31e923fe2 7 # not use this file except in compliance with the License.
Pawel Zarembski 0:01f31e923fe2 8 # You may obtain a copy of the License at
Pawel Zarembski 0:01f31e923fe2 9 #
Pawel Zarembski 0:01f31e923fe2 10 # http://www.apache.org/licenses/LICENSE-2.0
Pawel Zarembski 0:01f31e923fe2 11 #
Pawel Zarembski 0:01f31e923fe2 12 # Unless required by applicable law or agreed to in writing, software
Pawel Zarembski 0:01f31e923fe2 13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
Pawel Zarembski 0:01f31e923fe2 14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Pawel Zarembski 0:01f31e923fe2 15 # See the License for the specific language governing permissions and
Pawel Zarembski 0:01f31e923fe2 16 # limitations under the License.
Pawel Zarembski 0:01f31e923fe2 17 #
Pawel Zarembski 0:01f31e923fe2 18
Pawel Zarembski 0:01f31e923fe2 19 from __future__ import absolute_import
Pawel Zarembski 0:01f31e923fe2 20 from __future__ import division
Pawel Zarembski 0:01f31e923fe2 21 import os
Pawel Zarembski 0:01f31e923fe2 22 import time
Pawel Zarembski 0:01f31e923fe2 23 import shutil
Pawel Zarembski 0:01f31e923fe2 24 import six
Pawel Zarembski 0:01f31e923fe2 25 import info
Pawel Zarembski 0:01f31e923fe2 26 import intelhex
Pawel Zarembski 0:01f31e923fe2 27 from test_info import TestInfo
Pawel Zarembski 0:01f31e923fe2 28
Pawel Zarembski 0:01f31e923fe2 29 from pyocd.core.helpers import ConnectHelper
Pawel Zarembski 0:01f31e923fe2 30 from pyocd.core.memory_map import MemoryType
Pawel Zarembski 0:01f31e923fe2 31
Pawel Zarembski 0:01f31e923fe2 32 def _same(d1, d2):
Pawel Zarembski 0:01f31e923fe2 33 assert type(d1) is bytearray
Pawel Zarembski 0:01f31e923fe2 34 assert type(d2) is bytearray
Pawel Zarembski 0:01f31e923fe2 35 for i in range(min(len(d1), len(d2))):
Pawel Zarembski 0:01f31e923fe2 36 if d1[i] != d2[i]:
Pawel Zarembski 0:01f31e923fe2 37 return False
Pawel Zarembski 0:01f31e923fe2 38 if len(d1) != len(d2):
Pawel Zarembski 0:01f31e923fe2 39 return False
Pawel Zarembski 0:01f31e923fe2 40 return True
Pawel Zarembski 0:01f31e923fe2 41
Pawel Zarembski 0:01f31e923fe2 42 MOCK_DIR_LIST = [
Pawel Zarembski 0:01f31e923fe2 43 "test",
Pawel Zarembski 0:01f31e923fe2 44 "blarg",
Pawel Zarembski 0:01f31e923fe2 45 "very_long_directory_name",
Pawel Zarembski 0:01f31e923fe2 46 "very_long_directory_name/and_subdirectory_name"
Pawel Zarembski 0:01f31e923fe2 47 ]
Pawel Zarembski 0:01f31e923fe2 48
Pawel Zarembski 0:01f31e923fe2 49 MOCK_FILE_LIST = [
Pawel Zarembski 0:01f31e923fe2 50 (".test", "blarg"),
Pawel Zarembski 0:01f31e923fe2 51 ("test/file1", "asdofahweaw"),
Pawel Zarembski 0:01f31e923fe2 52 ("file.jpg", "file contents here")
Pawel Zarembski 0:01f31e923fe2 53 ]
Pawel Zarembski 0:01f31e923fe2 54
Pawel Zarembski 0:01f31e923fe2 55 MOCK_DIR_LIST_AFTER = [
Pawel Zarembski 0:01f31e923fe2 56 "test2",
Pawel Zarembski 0:01f31e923fe2 57 "blarg2",
Pawel Zarembski 0:01f31e923fe2 58 "very_long_directory_name2",
Pawel Zarembski 0:01f31e923fe2 59 "very_long_directory_name2/and_subdirectory_name"
Pawel Zarembski 0:01f31e923fe2 60 ]
Pawel Zarembski 0:01f31e923fe2 61
Pawel Zarembski 0:01f31e923fe2 62 MOCK_FILE_LIST_AFTER = [
Pawel Zarembski 0:01f31e923fe2 63 (".test2", "blarg"),
Pawel Zarembski 0:01f31e923fe2 64 ("test2/file12", "asdofahweaw"),
Pawel Zarembski 0:01f31e923fe2 65 ("file2.jpg", "file contents here")
Pawel Zarembski 0:01f31e923fe2 66 ]
Pawel Zarembski 0:01f31e923fe2 67
Pawel Zarembski 0:01f31e923fe2 68 class MassStorageTester(object):
Pawel Zarembski 0:01f31e923fe2 69
Pawel Zarembski 0:01f31e923fe2 70 RETRY_COUNT = 5
Pawel Zarembski 0:01f31e923fe2 71 DELAY_BEFORE_RETRY_S = 30
Pawel Zarembski 0:01f31e923fe2 72
Pawel Zarembski 0:01f31e923fe2 73 def __init__(self, board, parent_test, test_name):
Pawel Zarembski 0:01f31e923fe2 74 self.board = board
Pawel Zarembski 0:01f31e923fe2 75 self.parent_test = parent_test
Pawel Zarembski 0:01f31e923fe2 76 self.test_name = test_name
Pawel Zarembski 0:01f31e923fe2 77 self._expected_failure_msg = None
Pawel Zarembski 0:01f31e923fe2 78 self._flush_time = 0.1
Pawel Zarembski 0:01f31e923fe2 79 self._load_with_shutils = None
Pawel Zarembski 0:01f31e923fe2 80 self._flush_size = None
Pawel Zarembski 0:01f31e923fe2 81 self._programming_data = None
Pawel Zarembski 0:01f31e923fe2 82 self._mock_file_list = []
Pawel Zarembski 0:01f31e923fe2 83 self._mock_dir_list = []
Pawel Zarembski 0:01f31e923fe2 84 self._mock_file_list_after = []
Pawel Zarembski 0:01f31e923fe2 85 self._mock_dir_list_after = []
Pawel Zarembski 0:01f31e923fe2 86 self._programming_file_name = None
Pawel Zarembski 0:01f31e923fe2 87 self._start = 0
Pawel Zarembski 0:01f31e923fe2 88
Pawel Zarembski 0:01f31e923fe2 89 def set_shutils_copy(self, source_file_name):
Pawel Zarembski 0:01f31e923fe2 90 """
Pawel Zarembski 0:01f31e923fe2 91 Change mode to shutil file copy
Pawel Zarembski 0:01f31e923fe2 92
Pawel Zarembski 0:01f31e923fe2 93 This option cannot be used with set_programming_data.
Pawel Zarembski 0:01f31e923fe2 94 """
Pawel Zarembski 0:01f31e923fe2 95 assert type(source_file_name) is str
Pawel Zarembski 0:01f31e923fe2 96 assert self._load_with_shutils is None
Pawel Zarembski 0:01f31e923fe2 97 self._source_file_name = source_file_name
Pawel Zarembski 0:01f31e923fe2 98 self._load_with_shutils = True
Pawel Zarembski 0:01f31e923fe2 99
Pawel Zarembski 0:01f31e923fe2 100 def set_programming_data(self, data, file_name):
Pawel Zarembski 0:01f31e923fe2 101 """
Pawel Zarembski 0:01f31e923fe2 102 Set data to program over mass storage
Pawel Zarembski 0:01f31e923fe2 103
Pawel Zarembski 0:01f31e923fe2 104 Data should be the conetents of the hex or binary file
Pawel Zarembski 0:01f31e923fe2 105 being loaded. This option cannot be used with set_shutils_copy.
Pawel Zarembski 0:01f31e923fe2 106 """
Pawel Zarembski 0:01f31e923fe2 107 assert type(data) is bytearray
Pawel Zarembski 0:01f31e923fe2 108 assert type(file_name) is str
Pawel Zarembski 0:01f31e923fe2 109 assert(self._load_with_shutils is False or
Pawel Zarembski 0:01f31e923fe2 110 self._load_with_shutils is None)
Pawel Zarembski 0:01f31e923fe2 111 self._load_with_shutils = False
Pawel Zarembski 0:01f31e923fe2 112 self._programming_data = data
Pawel Zarembski 0:01f31e923fe2 113 self._programming_file_name = file_name
Pawel Zarembski 0:01f31e923fe2 114
Pawel Zarembski 0:01f31e923fe2 115 def set_flush_size(self, size):
Pawel Zarembski 0:01f31e923fe2 116 """Set the block size to simulate a flush of"""
Pawel Zarembski 0:01f31e923fe2 117 assert isinstance(size, six.integer_types)
Pawel Zarembski 0:01f31e923fe2 118 self._flush_size = size
Pawel Zarembski 0:01f31e923fe2 119
Pawel Zarembski 0:01f31e923fe2 120 def set_expected_data(self, data, start=0):
Pawel Zarembski 0:01f31e923fe2 121 """Data that should have been written to the device"""
Pawel Zarembski 0:01f31e923fe2 122 assert data is None or type(data) is bytearray
Pawel Zarembski 0:01f31e923fe2 123 self._expected_data = data
Pawel Zarembski 0:01f31e923fe2 124 self._start = start
Pawel Zarembski 0:01f31e923fe2 125
Pawel Zarembski 0:01f31e923fe2 126 def set_expected_failure_msg(self, msg, error_type):
Pawel Zarembski 0:01f31e923fe2 127 """Set the expected failure message as a string"""
Pawel Zarembski 0:01f31e923fe2 128 assert msg is None or type(msg) is str
Pawel Zarembski 0:01f31e923fe2 129 self._expected_failure_msg = msg
Pawel Zarembski 0:01f31e923fe2 130 self._expected_failure_type = error_type
Pawel Zarembski 0:01f31e923fe2 131
Pawel Zarembski 0:01f31e923fe2 132 def add_mock_files(self, file_list):
Pawel Zarembski 0:01f31e923fe2 133 """Add a list of tuples containing a file and contents"""
Pawel Zarembski 0:01f31e923fe2 134 self._mock_file_list.extend(file_list)
Pawel Zarembski 0:01f31e923fe2 135
Pawel Zarembski 0:01f31e923fe2 136 def add_mock_dirs(self, dir_list):
Pawel Zarembski 0:01f31e923fe2 137 """Add a list of directoies"""
Pawel Zarembski 0:01f31e923fe2 138 self._mock_dir_list.extend(dir_list)
Pawel Zarembski 0:01f31e923fe2 139
Pawel Zarembski 0:01f31e923fe2 140 def add_mock_files_after_load(self, file_list):
Pawel Zarembski 0:01f31e923fe2 141 """Add a list of tuples containing a file and contents"""
Pawel Zarembski 0:01f31e923fe2 142 self._mock_file_list_after.extend(file_list)
Pawel Zarembski 0:01f31e923fe2 143
Pawel Zarembski 0:01f31e923fe2 144 def add_mock_dirs_after_load(self, dir_list):
Pawel Zarembski 0:01f31e923fe2 145 """Add a list of directoies"""
Pawel Zarembski 0:01f31e923fe2 146 self._mock_dir_list_after.extend(dir_list)
Pawel Zarembski 0:01f31e923fe2 147
Pawel Zarembski 0:01f31e923fe2 148 def _check_data_correct(self, expected_data, _):
Pawel Zarembski 0:01f31e923fe2 149 """Return True if the actual data written matches the expected"""
Pawel Zarembski 0:01f31e923fe2 150 data_len = len(expected_data)
Pawel Zarembski 0:01f31e923fe2 151 data_loaded = self.board.read_target_memory(self._start, data_len)
Pawel Zarembski 0:01f31e923fe2 152 return _same(expected_data, data_loaded)
Pawel Zarembski 0:01f31e923fe2 153
Pawel Zarembski 0:01f31e923fe2 154 def run(self):
Pawel Zarembski 0:01f31e923fe2 155 for retry_count in range(self.RETRY_COUNT):
Pawel Zarembski 0:01f31e923fe2 156 test_info = TestInfo(self.test_name)
Pawel Zarembski 0:01f31e923fe2 157 if retry_count > 0:
Pawel Zarembski 0:01f31e923fe2 158 test_info.info('Previous attempts %s' % retry_count)
Pawel Zarembski 0:01f31e923fe2 159 try:
Pawel Zarembski 0:01f31e923fe2 160 self._run(test_info)
Pawel Zarembski 0:01f31e923fe2 161 except IOError:
Pawel Zarembski 0:01f31e923fe2 162 time.sleep(self.DELAY_BEFORE_RETRY_S)
Pawel Zarembski 0:01f31e923fe2 163 # Update board info since a remount could have occurred
Pawel Zarembski 0:01f31e923fe2 164 self.board.update_board_info()
Pawel Zarembski 0:01f31e923fe2 165 continue
Pawel Zarembski 0:01f31e923fe2 166 self.parent_test.attach_subtest(test_info)
Pawel Zarembski 0:01f31e923fe2 167 break
Pawel Zarembski 0:01f31e923fe2 168 else:
Pawel Zarembski 0:01f31e923fe2 169 raise Exception("Flashing failed after %i retries" %
Pawel Zarembski 0:01f31e923fe2 170 self.RETRY_COUNT)
Pawel Zarembski 0:01f31e923fe2 171
Pawel Zarembski 0:01f31e923fe2 172 def _run(self, test_info):
Pawel Zarembski 0:01f31e923fe2 173 # Expected data must be set, even if to None
Pawel Zarembski 0:01f31e923fe2 174 assert hasattr(self, '_expected_data')
Pawel Zarembski 0:01f31e923fe2 175
Pawel Zarembski 0:01f31e923fe2 176 # Windows 8/10 workaround
Pawel Zarembski 0:01f31e923fe2 177 # ----
Pawel Zarembski 0:01f31e923fe2 178 # By default Windows 8 and 10 access and write to removable drives
Pawel Zarembski 0:01f31e923fe2 179 # shortly after they are connected. If this occurs at the same time
Pawel Zarembski 0:01f31e923fe2 180 # as a file copy the file could be sent out of order causing DAPLink
Pawel Zarembski 0:01f31e923fe2 181 # programming to terminate early and report an error.
Pawel Zarembski 0:01f31e923fe2 182 #
Pawel Zarembski 0:01f31e923fe2 183 # This causes testing to intermittently fail with errors such as:
Pawel Zarembski 0:01f31e923fe2 184 # - "The transfer timed out."
Pawel Zarembski 0:01f31e923fe2 185 # - "File sent out of order by PC. Target might
Pawel Zarembski 0:01f31e923fe2 186 # not be programmed correctly."
Pawel Zarembski 0:01f31e923fe2 187 #
Pawel Zarembski 0:01f31e923fe2 188 # To prevent Windows from writing to removable drives on connect
Pawel Zarembski 0:01f31e923fe2 189 # drive indexing can be turned off with the following procedure:
Pawel Zarembski 0:01f31e923fe2 190 # - Start the program "gpedit.msc"
Pawel Zarembski 0:01f31e923fe2 191 # - Navigate to "Computer Configuration \ Administrative Templates
Pawel Zarembski 0:01f31e923fe2 192 # \ Windows Components \ Search"
Pawel Zarembski 0:01f31e923fe2 193 # - Enable the policy "Do not allow locations on removable drives
Pawel Zarembski 0:01f31e923fe2 194 # to be added to libraries."
Pawel Zarembski 0:01f31e923fe2 195 #
Pawel Zarembski 0:01f31e923fe2 196 # Rather than requiring all testers of DAPLink make this setting
Pawel Zarembski 0:01f31e923fe2 197 # change the below sleep has been added. This added delay allows
Pawel Zarembski 0:01f31e923fe2 198 # windows to complete the writes it performs shortly after connect.
Pawel Zarembski 0:01f31e923fe2 199 # This allows testing to be performed without interruption.
Pawel Zarembski 0:01f31e923fe2 200 #
Pawel Zarembski 0:01f31e923fe2 201 # Note - if drive indexing is turned off as mentioned above then
Pawel Zarembski 0:01f31e923fe2 202 # this sleep is not needed.
Pawel Zarembski 0:01f31e923fe2 203 time.sleep(2)
Pawel Zarembski 0:01f31e923fe2 204
Pawel Zarembski 0:01f31e923fe2 205 # Copy mock files before test
Pawel Zarembski 0:01f31e923fe2 206 self._mock_file_list = []
Pawel Zarembski 0:01f31e923fe2 207 for dir_name in self._mock_dir_list:
Pawel Zarembski 0:01f31e923fe2 208 dir_path = self.board.get_file_path(dir_name)
Pawel Zarembski 0:01f31e923fe2 209 os.mkdir(dir_path)
Pawel Zarembski 0:01f31e923fe2 210 for file_name, file_contents in self._mock_file_list:
Pawel Zarembski 0:01f31e923fe2 211 file_path = self.board.get_file_path(file_name)
Pawel Zarembski 0:01f31e923fe2 212 with open(file_path, 'wb') as file_handle:
Pawel Zarembski 0:01f31e923fe2 213 file_handle.write(file_contents)
Pawel Zarembski 0:01f31e923fe2 214
Pawel Zarembski 0:01f31e923fe2 215 programming_file_name = None
Pawel Zarembski 0:01f31e923fe2 216 if self._programming_file_name is not None:
Pawel Zarembski 0:01f31e923fe2 217 programming_file_name = \
Pawel Zarembski 0:01f31e923fe2 218 self.board.get_file_path(self._programming_file_name)
Pawel Zarembski 0:01f31e923fe2 219
Pawel Zarembski 0:01f31e923fe2 220 # Write data to the file
Pawel Zarembski 0:01f31e923fe2 221 start = time.time()
Pawel Zarembski 0:01f31e923fe2 222 if self._load_with_shutils:
Pawel Zarembski 0:01f31e923fe2 223 # Copy with shutils
Pawel Zarembski 0:01f31e923fe2 224 shutil.copy(self._source_file_name, self.board.get_mount_point())
Pawel Zarembski 0:01f31e923fe2 225 elif self._flush_size is not None:
Pawel Zarembski 0:01f31e923fe2 226 # Simulate flushes during the file transfer
Pawel Zarembski 0:01f31e923fe2 227 # Note - The file is explicitly opened and closed to more
Pawel Zarembski 0:01f31e923fe2 228 # consistently simulate the undesirable behavior flush can
Pawel Zarembski 0:01f31e923fe2 229 # cause. On Windows flushing a file causes the data to be
Pawel Zarembski 0:01f31e923fe2 230 # written out immediately, but only sometimes causes the
Pawel Zarembski 0:01f31e923fe2 231 # filesize to get updated.
Pawel Zarembski 0:01f31e923fe2 232 size = len(self._programming_data)
Pawel Zarembski 0:01f31e923fe2 233 for addr in range(0, size, self._flush_size):
Pawel Zarembski 0:01f31e923fe2 234 data = self._programming_data[addr:addr + self._flush_size]
Pawel Zarembski 0:01f31e923fe2 235 with open(programming_file_name, 'ab') as file_handle:
Pawel Zarembski 0:01f31e923fe2 236 file_handle.write(data)
Pawel Zarembski 0:01f31e923fe2 237 time.sleep(self._flush_time)
Pawel Zarembski 0:01f31e923fe2 238 else:
Pawel Zarembski 0:01f31e923fe2 239 # Perform a normal copy
Pawel Zarembski 0:01f31e923fe2 240 with open(programming_file_name, 'wb') as load_file:
Pawel Zarembski 0:01f31e923fe2 241 load_file.write(self._programming_data)
Pawel Zarembski 0:01f31e923fe2 242 stop = time.time()
Pawel Zarembski 0:01f31e923fe2 243 diff = stop - start
Pawel Zarembski 0:01f31e923fe2 244 test_info.info('Loading took %ss' % diff)
Pawel Zarembski 0:01f31e923fe2 245 if self._expected_data is not None:
Pawel Zarembski 0:01f31e923fe2 246 test_info.info('Programming rate %sB/s' %
Pawel Zarembski 0:01f31e923fe2 247 (len(self._expected_data) / diff))
Pawel Zarembski 0:01f31e923fe2 248 if self._programming_data is not None:
Pawel Zarembski 0:01f31e923fe2 249 test_info.info('MSD transfer rate %sB/s' %
Pawel Zarembski 0:01f31e923fe2 250 (len(self._programming_data) / diff))
Pawel Zarembski 0:01f31e923fe2 251
Pawel Zarembski 0:01f31e923fe2 252 # Copy mock files after loading
Pawel Zarembski 0:01f31e923fe2 253 self._mock_file_list = []
Pawel Zarembski 0:01f31e923fe2 254 for dir_name in self._mock_dir_list_after:
Pawel Zarembski 0:01f31e923fe2 255 dir_path = self.board.get_file_path(dir_name)
Pawel Zarembski 0:01f31e923fe2 256 os.mkdir(dir_path)
Pawel Zarembski 0:01f31e923fe2 257 for file_name, file_contents in self._mock_file_list_after:
Pawel Zarembski 0:01f31e923fe2 258 file_path = self.board.get_file_path(file_name)
Pawel Zarembski 0:01f31e923fe2 259 with open(file_path, 'w') as file_handle:
Pawel Zarembski 0:01f31e923fe2 260 file_handle.write(file_contents)
Pawel Zarembski 0:01f31e923fe2 261
Pawel Zarembski 0:01f31e923fe2 262 self.board.wait_for_remount(test_info)
Pawel Zarembski 0:01f31e923fe2 263
Pawel Zarembski 0:01f31e923fe2 264 # Verify the disk is still valid
Pawel Zarembski 0:01f31e923fe2 265 self.board.test_fs(test_info)
Pawel Zarembski 0:01f31e923fe2 266
Pawel Zarembski 0:01f31e923fe2 267 # Check various failure cases
Pawel Zarembski 0:01f31e923fe2 268 msg, error_type = self.board.get_failure_message_and_type()
Pawel Zarembski 0:01f31e923fe2 269 failure_expected = self._expected_failure_msg is not None
Pawel Zarembski 0:01f31e923fe2 270 failure_occured = msg is not None
Pawel Zarembski 0:01f31e923fe2 271 if failure_occured and not failure_expected:
Pawel Zarembski 0:01f31e923fe2 272 test_info.failure('Device reported failure: "%s"' % msg.strip())
Pawel Zarembski 0:01f31e923fe2 273 return
Pawel Zarembski 0:01f31e923fe2 274 if failure_expected and not failure_occured:
Pawel Zarembski 0:01f31e923fe2 275 test_info.failure('Failure expected but did not occur')
Pawel Zarembski 0:01f31e923fe2 276 return
Pawel Zarembski 0:01f31e923fe2 277 if failure_expected and failure_occured:
Pawel Zarembski 0:01f31e923fe2 278 if msg == self._expected_failure_msg and error_type == self._expected_failure_type:
Pawel Zarembski 0:01f31e923fe2 279 test_info.info(
Pawel Zarembski 0:01f31e923fe2 280 'Failure as expected: "%s, %s"' %
Pawel Zarembski 0:01f31e923fe2 281 (msg.strip(), error_type.strip()))
Pawel Zarembski 0:01f31e923fe2 282 elif msg != self._expected_failure_msg:
Pawel Zarembski 0:01f31e923fe2 283 test_info.failure('Failure but wrong string: "%s" vs "%s"' %
Pawel Zarembski 0:01f31e923fe2 284 (msg.strip(),
Pawel Zarembski 0:01f31e923fe2 285 self._expected_failure_msg.strip()))
Pawel Zarembski 0:01f31e923fe2 286 else:
Pawel Zarembski 0:01f31e923fe2 287 test_info.failure(
Pawel Zarembski 0:01f31e923fe2 288 'Failure but wrong type: "%s" vs "%s"' %
Pawel Zarembski 0:01f31e923fe2 289 (error_type.strip(), self._expected_failure_type.strip()))
Pawel Zarembski 0:01f31e923fe2 290 return
Pawel Zarembski 0:01f31e923fe2 291
Pawel Zarembski 0:01f31e923fe2 292 # These cases should have been handled above
Pawel Zarembski 0:01f31e923fe2 293 assert not failure_expected
Pawel Zarembski 0:01f31e923fe2 294 assert not failure_occured
Pawel Zarembski 0:01f31e923fe2 295
Pawel Zarembski 0:01f31e923fe2 296 # If there is expected data then compare
Pawel Zarembski 0:01f31e923fe2 297 if self._expected_data:
Pawel Zarembski 0:01f31e923fe2 298 if self._check_data_correct(self._expected_data, test_info):
Pawel Zarembski 0:01f31e923fe2 299 test_info.info("Data matches")
Pawel Zarembski 0:01f31e923fe2 300 else:
Pawel Zarembski 0:01f31e923fe2 301 test_info.failure('Data does not match')
Pawel Zarembski 0:01f31e923fe2 302
Pawel Zarembski 0:01f31e923fe2 303
Pawel Zarembski 0:01f31e923fe2 304 def test_mass_storage(workspace, parent_test):
Pawel Zarembski 0:01f31e923fe2 305 """Test the mass storage endpoint
Pawel Zarembski 0:01f31e923fe2 306
Pawel Zarembski 0:01f31e923fe2 307 Requirements:
Pawel Zarembski 0:01f31e923fe2 308 None
Pawel Zarembski 0:01f31e923fe2 309
Pawel Zarembski 0:01f31e923fe2 310 Positional arguments:
Pawel Zarembski 0:01f31e923fe2 311 filename - A string containing the name of the file to load
Pawel Zarembski 0:01f31e923fe2 312
Pawel Zarembski 0:01f31e923fe2 313 Return:
Pawel Zarembski 0:01f31e923fe2 314 True if the test passed, False otherwise
Pawel Zarembski 0:01f31e923fe2 315 """
Pawel Zarembski 0:01f31e923fe2 316 test_info = parent_test.create_subtest('test_mass_storage')
Pawel Zarembski 0:01f31e923fe2 317
Pawel Zarembski 0:01f31e923fe2 318 # Setup test
Pawel Zarembski 0:01f31e923fe2 319 board = workspace.board
Pawel Zarembski 0:01f31e923fe2 320 target = workspace.target
Pawel Zarembski 0:01f31e923fe2 321 bin_file = target.bin_path
Pawel Zarembski 0:01f31e923fe2 322 hex_file = target.hex_path
Pawel Zarembski 0:01f31e923fe2 323 with open(bin_file, 'rb') as test_file:
Pawel Zarembski 0:01f31e923fe2 324 bin_file_contents = bytearray(test_file.read())
Pawel Zarembski 0:01f31e923fe2 325 with open(hex_file, 'rb') as test_file:
Pawel Zarembski 0:01f31e923fe2 326 hex_file_contents = bytearray(test_file.read())
Pawel Zarembski 0:01f31e923fe2 327 blank_bin_contents = bytearray([0xff]) * 0x2000
Pawel Zarembski 0:01f31e923fe2 328 vectors_and_pad = bin_file_contents[0:32] + blank_bin_contents
Pawel Zarembski 0:01f31e923fe2 329 locked_when_erased = board.get_board_id() in info.BOARD_ID_LOCKED_WHEN_ERASED
Pawel Zarembski 0:01f31e923fe2 330 page_erase_supported = board.get_board_id() in info.BOARD_ID_SUPPORTING_PAGE_ERASE
Pawel Zarembski 0:01f31e923fe2 331 bad_vector_table = target.name in info.TARGET_WITH_BAD_VECTOR_TABLE_LIST
Pawel Zarembski 0:01f31e923fe2 332
Pawel Zarembski 0:01f31e923fe2 333 intel_hex = intelhex.IntelHex(hex_file)
Pawel Zarembski 0:01f31e923fe2 334 addresses = intel_hex.addresses()
Pawel Zarembski 0:01f31e923fe2 335 addresses.sort()
Pawel Zarembski 0:01f31e923fe2 336 start = addresses[0]
Pawel Zarembski 0:01f31e923fe2 337
Pawel Zarembski 0:01f31e923fe2 338 # Test loading a binary file with shutils
Pawel Zarembski 0:01f31e923fe2 339 if not bad_vector_table:
Pawel Zarembski 0:01f31e923fe2 340 test = MassStorageTester(board, test_info, "Shutil binary file load")
Pawel Zarembski 0:01f31e923fe2 341 test.set_shutils_copy(bin_file)
Pawel Zarembski 0:01f31e923fe2 342 test.set_expected_data(bin_file_contents, start)
Pawel Zarembski 0:01f31e923fe2 343 test.run()
Pawel Zarembski 0:01f31e923fe2 344
Pawel Zarembski 0:01f31e923fe2 345 # Test loading a binary file with flushes
Pawel Zarembski 0:01f31e923fe2 346 if not bad_vector_table:
Pawel Zarembski 0:01f31e923fe2 347 test = MassStorageTester(board, test_info, "Load binary with flushes")
Pawel Zarembski 0:01f31e923fe2 348 test.set_programming_data(bin_file_contents, 'image.bin')
Pawel Zarembski 0:01f31e923fe2 349 test.set_expected_data(bin_file_contents, start)
Pawel Zarembski 0:01f31e923fe2 350 test.set_flush_size(0x1000)
Pawel Zarembski 0:01f31e923fe2 351 test.run()
Pawel Zarembski 0:01f31e923fe2 352
Pawel Zarembski 0:01f31e923fe2 353 # Test loading a hex file with shutils
Pawel Zarembski 0:01f31e923fe2 354 test = MassStorageTester(board, test_info, "Shutil hex file load")
Pawel Zarembski 0:01f31e923fe2 355 test.set_shutils_copy(hex_file)
Pawel Zarembski 0:01f31e923fe2 356 test.set_expected_data(bin_file_contents, start)
Pawel Zarembski 0:01f31e923fe2 357 test.run()
Pawel Zarembski 0:01f31e923fe2 358
Pawel Zarembski 0:01f31e923fe2 359 # Test loading a hex file with flushes
Pawel Zarembski 0:01f31e923fe2 360 test = MassStorageTester(board, test_info, "Load hex with flushes")
Pawel Zarembski 0:01f31e923fe2 361 test.set_programming_data(hex_file_contents, 'image.hex')
Pawel Zarembski 0:01f31e923fe2 362 test.set_expected_data(bin_file_contents, start)
Pawel Zarembski 0:01f31e923fe2 363 test.set_flush_size(0x1000)
Pawel Zarembski 0:01f31e923fe2 364 test.run()
Pawel Zarembski 0:01f31e923fe2 365
Pawel Zarembski 0:01f31e923fe2 366 # Test loading a binary smaller than a sector
Pawel Zarembski 0:01f31e923fe2 367 if not bad_vector_table:
Pawel Zarembski 0:01f31e923fe2 368 test = MassStorageTester(board, test_info, "Load .bin smaller than sector")
Pawel Zarembski 0:01f31e923fe2 369 test_data_size = 0x789
Pawel Zarembski 0:01f31e923fe2 370 test_data = bin_file_contents[0:0 + test_data_size]
Pawel Zarembski 0:01f31e923fe2 371 test.set_programming_data(test_data, 'image.bin')
Pawel Zarembski 0:01f31e923fe2 372 test.set_expected_data(test_data, start)
Pawel Zarembski 0:01f31e923fe2 373 test.run()
Pawel Zarembski 0:01f31e923fe2 374
Pawel Zarembski 0:01f31e923fe2 375 # Test loading a blank binary - this image should cause a timeout
Pawel Zarembski 0:01f31e923fe2 376 # since it doesn't have a valid vector table
Pawel Zarembski 0:01f31e923fe2 377 test = MassStorageTester(board, test_info, "Load blank binary")
Pawel Zarembski 0:01f31e923fe2 378 test.set_programming_data(blank_bin_contents, 'image.bin')
Pawel Zarembski 0:01f31e923fe2 379 test.set_expected_failure_msg("The transfer timed out.", "transient, user")
Pawel Zarembski 0:01f31e923fe2 380 test.set_expected_data(None, start)
Pawel Zarembski 0:01f31e923fe2 381 test.run()
Pawel Zarembski 0:01f31e923fe2 382
Pawel Zarembski 0:01f31e923fe2 383 # Test loading a blank binary with a vector table but padded with 0xFF.
Pawel Zarembski 0:01f31e923fe2 384 # A blank image can lock some devices.
Pawel Zarembski 0:01f31e923fe2 385 if not bad_vector_table:
Pawel Zarembski 0:01f31e923fe2 386 test = MassStorageTester(board, test_info, "Load blank binary + vector table")
Pawel Zarembski 0:01f31e923fe2 387 test.set_programming_data(vectors_and_pad, 'image.bin')
Pawel Zarembski 0:01f31e923fe2 388 if locked_when_erased:
Pawel Zarembski 0:01f31e923fe2 389 test.set_expected_failure_msg("The interface firmware ABORTED programming. Image is trying to set security bits", "user")
Pawel Zarembski 0:01f31e923fe2 390 test.set_expected_data(None, start)
Pawel Zarembski 0:01f31e923fe2 391 else:
Pawel Zarembski 0:01f31e923fe2 392 test.set_expected_data(vectors_and_pad, start)
Pawel Zarembski 0:01f31e923fe2 393 test.run()
Pawel Zarembski 0:01f31e923fe2 394
Pawel Zarembski 0:01f31e923fe2 395 # Test a normal load with dummy files created beforehand
Pawel Zarembski 0:01f31e923fe2 396 test = MassStorageTester(board, test_info, "Extra Files")
Pawel Zarembski 0:01f31e923fe2 397 test.set_programming_data(hex_file_contents, 'image.hex')
Pawel Zarembski 0:01f31e923fe2 398 test.add_mock_dirs(MOCK_DIR_LIST)
Pawel Zarembski 0:01f31e923fe2 399 test.add_mock_files(MOCK_FILE_LIST)
Pawel Zarembski 0:01f31e923fe2 400 test.add_mock_dirs_after_load(MOCK_DIR_LIST_AFTER)
Pawel Zarembski 0:01f31e923fe2 401 test.add_mock_files_after_load(MOCK_FILE_LIST_AFTER)
Pawel Zarembski 0:01f31e923fe2 402 test.set_expected_data(bin_file_contents, start)
Pawel Zarembski 0:01f31e923fe2 403 test.run()
Pawel Zarembski 0:01f31e923fe2 404 # Note - it is not unexpected for an "Extra Files" test to fail
Pawel Zarembski 0:01f31e923fe2 405 # when a binary file is loaded, since there is no way to
Pawel Zarembski 0:01f31e923fe2 406 # tell where the end of the file is.
Pawel Zarembski 0:01f31e923fe2 407
Pawel Zarembski 0:01f31e923fe2 408 if page_erase_supported:
Pawel Zarembski 0:01f31e923fe2 409 # Test page erase, a.k.a. sector erase by generating iHex with discrete addresses,
Pawel Zarembski 0:01f31e923fe2 410 # programing the device then comparing device memory against expected content.
Pawel Zarembski 0:01f31e923fe2 411 test = MassStorageTester(board, test_info, "Sector Erase")
Pawel Zarembski 0:01f31e923fe2 412 with ConnectHelper.session_with_chosen_probe(unique_id=board.get_unique_id(), open_session=False) as session:
Pawel Zarembski 0:01f31e923fe2 413 memory_map = session.target.memory_map
Pawel Zarembski 0:01f31e923fe2 414 flash_regions = memory_map.get_regions_of_type(MemoryType.FLASH)
Pawel Zarembski 0:01f31e923fe2 415
Pawel Zarembski 0:01f31e923fe2 416 max_address = intel_hex.maxaddr()
Pawel Zarembski 0:01f31e923fe2 417 # Create an object. We'll add the addresses of unused even blocks to it first, then unused odd blocks for each region
Pawel Zarembski 0:01f31e923fe2 418 ih = intelhex.IntelHex()
Pawel Zarembski 0:01f31e923fe2 419 # Add the content from test bin first
Pawel Zarembski 0:01f31e923fe2 420 expected_bin_contents = bin_file_contents
Pawel Zarembski 0:01f31e923fe2 421 for region_index, the_region in enumerate(flash_regions):
Pawel Zarembski 0:01f31e923fe2 422 if the_region.is_boot_memory is False:
Pawel Zarembski 0:01f31e923fe2 423 continue
Pawel Zarembski 0:01f31e923fe2 424 flash_start = the_region.start
Pawel Zarembski 0:01f31e923fe2 425 flash_length = the_region.length
Pawel Zarembski 0:01f31e923fe2 426 block_size = the_region.blocksize
Pawel Zarembski 0:01f31e923fe2 427
Pawel Zarembski 0:01f31e923fe2 428 number_of_blocks = flash_length // block_size
Pawel Zarembski 0:01f31e923fe2 429
Pawel Zarembski 0:01f31e923fe2 430 # Sanity check the regions are contiguous
Pawel Zarembski 0:01f31e923fe2 431 if region_index:
Pawel Zarembski 0:01f31e923fe2 432 assert flash_start == (flash_regions[region_index - 1].start + flash_regions[region_index - 1].length)
Pawel Zarembski 0:01f31e923fe2 433
Pawel Zarembski 0:01f31e923fe2 434 if max_address >= (flash_start + flash_length):
Pawel Zarembski 0:01f31e923fe2 435 # This bin image crosses this region, don't modify the content, go to the next region
Pawel Zarembski 0:01f31e923fe2 436 continue
Pawel Zarembski 0:01f31e923fe2 437 elif max_address >= flash_start:
Pawel Zarembski 0:01f31e923fe2 438 # This bin image occupies partial region. Skip the used portion to avoid touching any security bits and pad the rest
Pawel Zarembski 0:01f31e923fe2 439 expected_bin_contents += bytearray([0xff]) * (flash_start + flash_length - max_address - 1)
Pawel Zarembski 0:01f31e923fe2 440 # Calculate the starting block after the image to avoid stumbling upon security bits
Pawel Zarembski 0:01f31e923fe2 441 block_start = (max_address - flash_start) // block_size + 1
Pawel Zarembski 0:01f31e923fe2 442 else:
Pawel Zarembski 0:01f31e923fe2 443 # This bin image doesn't reach this region
Pawel Zarembski 0:01f31e923fe2 444 expected_bin_contents += bytearray([0xff]) * flash_length
Pawel Zarembski 0:01f31e923fe2 445 block_start = 0
Pawel Zarembski 0:01f31e923fe2 446 # For all even blocks, overwrite all addresses with 0x55; for all odd blocks, overwrite all addresses with 0xAA
Pawel Zarembski 0:01f31e923fe2 447 for pass_number in range (2):
Pawel Zarembski 0:01f31e923fe2 448 if pass_number == 0:
Pawel Zarembski 0:01f31e923fe2 449 modifier = 0x55
Pawel Zarembski 0:01f31e923fe2 450 else:
Pawel Zarembski 0:01f31e923fe2 451 modifier = 0xAA
Pawel Zarembski 0:01f31e923fe2 452 block_start += 1
Pawel Zarembski 0:01f31e923fe2 453 for block_idx in range(block_start, number_of_blocks, 2):
Pawel Zarembski 0:01f31e923fe2 454 for address_to_modify in range (flash_start + block_idx * block_size, flash_start + (block_idx + 1) * block_size):
Pawel Zarembski 0:01f31e923fe2 455 expected_bin_contents[address_to_modify] = modifier
Pawel Zarembski 0:01f31e923fe2 456 ih[address_to_modify] = modifier
Pawel Zarembski 0:01f31e923fe2 457 if not os.path.exists("tmp"):
Pawel Zarembski 0:01f31e923fe2 458 os.makedirs("tmp")
Pawel Zarembski 0:01f31e923fe2 459 # Write out the modified iHex to file
Pawel Zarembski 0:01f31e923fe2 460 ih.tofile("tmp/interleave.hex", format='hex')
Pawel Zarembski 0:01f31e923fe2 461 # Load this hex file with shutils
Pawel Zarembski 0:01f31e923fe2 462 test.set_shutils_copy("tmp/interleave.hex")
Pawel Zarembski 0:01f31e923fe2 463 test.set_expected_data(expected_bin_contents, start)
Pawel Zarembski 0:01f31e923fe2 464 test.run()
Pawel Zarembski 0:01f31e923fe2 465
Pawel Zarembski 0:01f31e923fe2 466 # Finally, load a good binary
Pawel Zarembski 0:01f31e923fe2 467 test = MassStorageTester(board, test_info, "Load good file to restore state")
Pawel Zarembski 0:01f31e923fe2 468 test.set_programming_data(hex_file_contents, 'image.hex')
Pawel Zarembski 0:01f31e923fe2 469 test.set_expected_data(bin_file_contents, start)
Pawel Zarembski 0:01f31e923fe2 470 test.run()
Pawel Zarembski 0:01f31e923fe2 471
Pawel Zarembski 0:01f31e923fe2 472 # Ideas for future tests - contributions welcome
Pawel Zarembski 0:01f31e923fe2 473 # -Zero length file
Pawel Zarembski 0:01f31e923fe2 474 # -Corrupt hex file
Pawel Zarembski 0:01f31e923fe2 475 # -Dummy files loaded before test
Pawel Zarembski 0:01f31e923fe2 476 # -Very large file
Pawel Zarembski 0:01f31e923fe2 477 # -Any MSD regressions
Pawel Zarembski 0:01f31e923fe2 478 # -Security bits in hex files
Pawel Zarembski 0:01f31e923fe2 479 # -Hex file with data at the end **
Pawel Zarembski 0:01f31e923fe2 480 # -Hidden files
Pawel Zarembski 0:01f31e923fe2 481 # -change file extension
Pawel Zarembski 0:01f31e923fe2 482 # -Change size (make smaller)
Pawel Zarembski 0:01f31e923fe2 483 # -change starting address