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
Pawel Zarembski 0:01f31e923fe2 21 import os
Pawel Zarembski 0:01f31e923fe2 22 import re
Pawel Zarembski 0:01f31e923fe2 23 import time
Pawel Zarembski 0:01f31e923fe2 24 import subprocess
Pawel Zarembski 0:01f31e923fe2 25 import sys
Pawel Zarembski 0:01f31e923fe2 26 import binascii
Pawel Zarembski 0:01f31e923fe2 27 import itertools
Pawel Zarembski 0:01f31e923fe2 28 import mbed_lstools
Pawel Zarembski 0:01f31e923fe2 29 import info
Pawel Zarembski 0:01f31e923fe2 30 import test_daplink
Pawel Zarembski 0:01f31e923fe2 31 from test_info import TestInfoStub, TestInfo
Pawel Zarembski 0:01f31e923fe2 32 from intelhex import IntelHex
Pawel Zarembski 0:01f31e923fe2 33 from pyocd.core.helpers import ConnectHelper
Pawel Zarembski 0:01f31e923fe2 34
Pawel Zarembski 0:01f31e923fe2 35 FILE_IGNORE_PATTERN_LIST = [
Pawel Zarembski 0:01f31e923fe2 36 re.compile("\\._\\.Trashes")
Pawel Zarembski 0:01f31e923fe2 37 ]
Pawel Zarembski 0:01f31e923fe2 38
Pawel Zarembski 0:01f31e923fe2 39
Pawel Zarembski 0:01f31e923fe2 40 # This prevents the following error message from getting
Pawel Zarembski 0:01f31e923fe2 41 # displayed on windows if the mbed dismounts unexpectedly
Pawel Zarembski 0:01f31e923fe2 42 # during a transfer:
Pawel Zarembski 0:01f31e923fe2 43 # There is no disk in the drive. Please insert a disk into
Pawel Zarembski 0:01f31e923fe2 44 # drive \Device\<Harddiskx>\<rdrive>
Pawel Zarembski 0:01f31e923fe2 45 def disable_popup():
Pawel Zarembski 0:01f31e923fe2 46 if sys.platform.startswith("win"):
Pawel Zarembski 0:01f31e923fe2 47 # pylint: disable=invalid-name
Pawel Zarembski 0:01f31e923fe2 48 import ctypes
Pawel Zarembski 0:01f31e923fe2 49 SEM_FAILCRITICALERRORS = 1
Pawel Zarembski 0:01f31e923fe2 50 GetErrorMode = \
Pawel Zarembski 0:01f31e923fe2 51 ctypes.windll.kernel32.GetErrorMode # @UndefinedVariable
Pawel Zarembski 0:01f31e923fe2 52 GetErrorMode.restype = ctypes.c_uint
Pawel Zarembski 0:01f31e923fe2 53 GetErrorMode.argtypes = []
Pawel Zarembski 0:01f31e923fe2 54 SetErrorMode = \
Pawel Zarembski 0:01f31e923fe2 55 ctypes.windll.kernel32.SetErrorMode # @UndefinedVariable
Pawel Zarembski 0:01f31e923fe2 56 SetErrorMode.restype = ctypes.c_uint
Pawel Zarembski 0:01f31e923fe2 57 SetErrorMode.argtypes = [ctypes.c_uint]
Pawel Zarembski 0:01f31e923fe2 58
Pawel Zarembski 0:01f31e923fe2 59 err_mode = GetErrorMode()
Pawel Zarembski 0:01f31e923fe2 60 err_mode |= SEM_FAILCRITICALERRORS
Pawel Zarembski 0:01f31e923fe2 61 SetErrorMode(err_mode)
Pawel Zarembski 0:01f31e923fe2 62
Pawel Zarembski 0:01f31e923fe2 63 disable_popup()
Pawel Zarembski 0:01f31e923fe2 64
Pawel Zarembski 0:01f31e923fe2 65
Pawel Zarembski 0:01f31e923fe2 66 def get_all_attached_daplink_boards():
Pawel Zarembski 0:01f31e923fe2 67 all_boards = []
Pawel Zarembski 0:01f31e923fe2 68 lstools = mbed_lstools.create()
Pawel Zarembski 0:01f31e923fe2 69 mbed_list = lstools.list_mbeds()
Pawel Zarembski 0:01f31e923fe2 70 for mbed in mbed_list:
Pawel Zarembski 0:01f31e923fe2 71 unique_id = mbed['target_id']
Pawel Zarembski 0:01f31e923fe2 72 board = DaplinkBoard(unique_id)
Pawel Zarembski 0:01f31e923fe2 73 if board._mode is not None: #Valid daplink should have set this mode
Pawel Zarembski 0:01f31e923fe2 74 all_boards.append(board)
Pawel Zarembski 0:01f31e923fe2 75 else:
Pawel Zarembski 0:01f31e923fe2 76 print("Warning: DAPLink tests cannot be done on board %s" % board.unique_id)
Pawel Zarembski 0:01f31e923fe2 77 return all_boards
Pawel Zarembski 0:01f31e923fe2 78
Pawel Zarembski 0:01f31e923fe2 79
Pawel Zarembski 0:01f31e923fe2 80 def _unique_id_to_host_id(unique_id):
Pawel Zarembski 0:01f31e923fe2 81 """Return the chip id unique to the daplink host procesor
Pawel Zarembski 0:01f31e923fe2 82
Pawel Zarembski 0:01f31e923fe2 83 Unique ID has the following fomat
Pawel Zarembski 0:01f31e923fe2 84 Board ID - 4 bytes
Pawel Zarembski 0:01f31e923fe2 85 Version - 4 bytes
Pawel Zarembski 0:01f31e923fe2 86 Host ID - Everything else
Pawel Zarembski 0:01f31e923fe2 87 """
Pawel Zarembski 0:01f31e923fe2 88 return unique_id[8:8 + 32]
Pawel Zarembski 0:01f31e923fe2 89
Pawel Zarembski 0:01f31e923fe2 90
Pawel Zarembski 0:01f31e923fe2 91 def _get_board_endpoints(unique_id):
Pawel Zarembski 0:01f31e923fe2 92 """Return a tuple of unique_id, serial_port, mount_point"""
Pawel Zarembski 0:01f31e923fe2 93 lstools = mbed_lstools.create()
Pawel Zarembski 0:01f31e923fe2 94 mbed_list = lstools.list_mbeds()
Pawel Zarembski 0:01f31e923fe2 95
Pawel Zarembski 0:01f31e923fe2 96 host_id = _unique_id_to_host_id(unique_id)
Pawel Zarembski 0:01f31e923fe2 97 for mbed in mbed_list:
Pawel Zarembski 0:01f31e923fe2 98 mbed_unique_id = mbed['target_id']
Pawel Zarembski 0:01f31e923fe2 99 mbed_serial_port = mbed['serial_port']
Pawel Zarembski 0:01f31e923fe2 100 mbed_mount_point = mbed['mount_point']
Pawel Zarembski 0:01f31e923fe2 101 mbed_host_id = _unique_id_to_host_id(mbed_unique_id)
Pawel Zarembski 0:01f31e923fe2 102 if mbed_host_id == host_id:
Pawel Zarembski 0:01f31e923fe2 103 return mbed_unique_id, mbed_serial_port, mbed_mount_point
Pawel Zarembski 0:01f31e923fe2 104 return None
Pawel Zarembski 0:01f31e923fe2 105
Pawel Zarembski 0:01f31e923fe2 106
Pawel Zarembski 0:01f31e923fe2 107 def _ranges(i):
Pawel Zarembski 0:01f31e923fe2 108 for _, b in itertools.groupby(enumerate(i), lambda x_y: x_y[1] - x_y[0]):
Pawel Zarembski 0:01f31e923fe2 109 b = list(b)
Pawel Zarembski 0:01f31e923fe2 110 yield b[0][1], b[-1][1]
Pawel Zarembski 0:01f31e923fe2 111
Pawel Zarembski 0:01f31e923fe2 112
Pawel Zarembski 0:01f31e923fe2 113 def _parse_kvp_file(file_path, parent_test=None):
Pawel Zarembski 0:01f31e923fe2 114 """Parse details.txt and return True if successful"""
Pawel Zarembski 0:01f31e923fe2 115 test_info = None
Pawel Zarembski 0:01f31e923fe2 116 kvp = {}
Pawel Zarembski 0:01f31e923fe2 117 if parent_test is not None:
Pawel Zarembski 0:01f31e923fe2 118 test_info = parent_test.create_subtest('parse_kvp_file')
Pawel Zarembski 0:01f31e923fe2 119 line_format = re.compile("^([a-zA-Z0-9 ]+): +(.+)$")
Pawel Zarembski 0:01f31e923fe2 120 if not os.path.isfile(file_path):
Pawel Zarembski 0:01f31e923fe2 121 return kvp
Pawel Zarembski 0:01f31e923fe2 122
Pawel Zarembski 0:01f31e923fe2 123 with open(file_path, "r") as file_handle:
Pawel Zarembski 0:01f31e923fe2 124 for line in file_handle:
Pawel Zarembski 0:01f31e923fe2 125 if len(line) <= 0:
Pawel Zarembski 0:01f31e923fe2 126 if test_info is not None:
Pawel Zarembski 0:01f31e923fe2 127 test_info.failure("Empty line in %s" % file_path)
Pawel Zarembski 0:01f31e923fe2 128 continue
Pawel Zarembski 0:01f31e923fe2 129
Pawel Zarembski 0:01f31e923fe2 130 if line[0] == '#':
Pawel Zarembski 0:01f31e923fe2 131 # The line is a comment
Pawel Zarembski 0:01f31e923fe2 132 continue
Pawel Zarembski 0:01f31e923fe2 133
Pawel Zarembski 0:01f31e923fe2 134 match = line_format.match(line)
Pawel Zarembski 0:01f31e923fe2 135 if match is None:
Pawel Zarembski 0:01f31e923fe2 136 if test_info is not None:
Pawel Zarembski 0:01f31e923fe2 137 test_info.failure("Invalid line: %s" % line)
Pawel Zarembski 0:01f31e923fe2 138 continue
Pawel Zarembski 0:01f31e923fe2 139
Pawel Zarembski 0:01f31e923fe2 140 key = match.group(1)
Pawel Zarembski 0:01f31e923fe2 141 key = key.lower().replace(" ", "_")
Pawel Zarembski 0:01f31e923fe2 142 value = match.group(2)
Pawel Zarembski 0:01f31e923fe2 143 value = value.lower()
Pawel Zarembski 0:01f31e923fe2 144 value = value.strip()
Pawel Zarembski 0:01f31e923fe2 145 if key in kvp:
Pawel Zarembski 0:01f31e923fe2 146 if test_info is not None:
Pawel Zarembski 0:01f31e923fe2 147 test_info.failure("Duplicate key %s" % key)
Pawel Zarembski 0:01f31e923fe2 148 continue
Pawel Zarembski 0:01f31e923fe2 149 kvp[key] = value
Pawel Zarembski 0:01f31e923fe2 150 return kvp
Pawel Zarembski 0:01f31e923fe2 151
Pawel Zarembski 0:01f31e923fe2 152
Pawel Zarembski 0:01f31e923fe2 153 def _compute_crc(hex_file_path):
Pawel Zarembski 0:01f31e923fe2 154 # Read in hex file
Pawel Zarembski 0:01f31e923fe2 155 new_hex_file = IntelHex()
Pawel Zarembski 0:01f31e923fe2 156 new_hex_file.padding = 0xFF
Pawel Zarembski 0:01f31e923fe2 157 new_hex_file.fromfile(hex_file_path, format='hex')
Pawel Zarembski 0:01f31e923fe2 158
Pawel Zarembski 0:01f31e923fe2 159 # Get the starting and ending address
Pawel Zarembski 0:01f31e923fe2 160 addresses = new_hex_file.addresses()
Pawel Zarembski 0:01f31e923fe2 161 addresses.sort()
Pawel Zarembski 0:01f31e923fe2 162 start_end_pairs = list(_ranges(addresses))
Pawel Zarembski 0:01f31e923fe2 163 regions = len(start_end_pairs)
Pawel Zarembski 0:01f31e923fe2 164 assert regions == 1, ("Error - only 1 region allowed in "
Pawel Zarembski 0:01f31e923fe2 165 "hex file %i found." % regions)
Pawel Zarembski 0:01f31e923fe2 166 start, end = start_end_pairs[0]
Pawel Zarembski 0:01f31e923fe2 167
Pawel Zarembski 0:01f31e923fe2 168 # Compute checksum over the range (don't include data at location of crc)
Pawel Zarembski 0:01f31e923fe2 169 size = end - start + 1
Pawel Zarembski 0:01f31e923fe2 170 crc_size = size - 4
Pawel Zarembski 0:01f31e923fe2 171 data = new_hex_file.tobinarray(start=start, size=crc_size)
Pawel Zarembski 0:01f31e923fe2 172 data_crc32 = binascii.crc32(data) & 0xFFFFFFFF
Pawel Zarembski 0:01f31e923fe2 173
Pawel Zarembski 0:01f31e923fe2 174 # Grab the crc from the image
Pawel Zarembski 0:01f31e923fe2 175 embedded_crc32 = (((new_hex_file[end - 3] & 0xFF) << 0) |
Pawel Zarembski 0:01f31e923fe2 176 ((new_hex_file[end - 2] & 0xFF) << 8) |
Pawel Zarembski 0:01f31e923fe2 177 ((new_hex_file[end - 1] & 0xFF) << 16) |
Pawel Zarembski 0:01f31e923fe2 178 ((new_hex_file[end - 0] & 0xFF) << 24))
Pawel Zarembski 0:01f31e923fe2 179 return data_crc32, embedded_crc32
Pawel Zarembski 0:01f31e923fe2 180
Pawel Zarembski 0:01f31e923fe2 181
Pawel Zarembski 0:01f31e923fe2 182 def _run_chkdsk(drive):
Pawel Zarembski 0:01f31e923fe2 183 args = ["chkdsk", drive]
Pawel Zarembski 0:01f31e923fe2 184 process = subprocess.Popen(args, stdin=subprocess.PIPE,
Pawel Zarembski 0:01f31e923fe2 185 stdout=subprocess.PIPE,
Pawel Zarembski 0:01f31e923fe2 186 stderr=subprocess.PIPE)
Pawel Zarembski 0:01f31e923fe2 187 process.communicate(input=bytearray('n\r\n',encoding='ascii')) # Answer no if prompted
Pawel Zarembski 0:01f31e923fe2 188 process.wait()
Pawel Zarembski 0:01f31e923fe2 189 return process.returncode
Pawel Zarembski 0:01f31e923fe2 190
Pawel Zarembski 0:01f31e923fe2 191
Pawel Zarembski 0:01f31e923fe2 192 class AssertInfo(object):
Pawel Zarembski 0:01f31e923fe2 193
Pawel Zarembski 0:01f31e923fe2 194 def __init__(self, file_name, line_number):
Pawel Zarembski 0:01f31e923fe2 195 self._file = file_name
Pawel Zarembski 0:01f31e923fe2 196 self._line = line_number
Pawel Zarembski 0:01f31e923fe2 197
Pawel Zarembski 0:01f31e923fe2 198 @property
Pawel Zarembski 0:01f31e923fe2 199 def file(self):
Pawel Zarembski 0:01f31e923fe2 200 return self._file
Pawel Zarembski 0:01f31e923fe2 201
Pawel Zarembski 0:01f31e923fe2 202 @property
Pawel Zarembski 0:01f31e923fe2 203 def line(self):
Pawel Zarembski 0:01f31e923fe2 204 return self._line
Pawel Zarembski 0:01f31e923fe2 205
Pawel Zarembski 0:01f31e923fe2 206
Pawel Zarembski 0:01f31e923fe2 207 class DaplinkBoard(object):
Pawel Zarembski 0:01f31e923fe2 208
Pawel Zarembski 0:01f31e923fe2 209 MODE_IF = "interface"
Pawel Zarembski 0:01f31e923fe2 210 MODE_BL = "bootloader"
Pawel Zarembski 0:01f31e923fe2 211
Pawel Zarembski 0:01f31e923fe2 212 # Keys for details.txt
Pawel Zarembski 0:01f31e923fe2 213 KEY_UNIQUE_ID = "unique_id"
Pawel Zarembski 0:01f31e923fe2 214 KEY_HIC_ID = "hic_id"
Pawel Zarembski 0:01f31e923fe2 215 KEY_MODE = "daplink_mode"
Pawel Zarembski 0:01f31e923fe2 216 KEY_BL_VERSION = "bootloader_version"
Pawel Zarembski 0:01f31e923fe2 217 KEY_IF_VERSION = "interface_version"
Pawel Zarembski 0:01f31e923fe2 218 KEY_GIT_SHA = "git_sha"
Pawel Zarembski 0:01f31e923fe2 219 KEY_LOCAL_MODS = "local_mods"
Pawel Zarembski 0:01f31e923fe2 220 KEY_USB_INTERFACES = "usb_interfaces"
Pawel Zarembski 0:01f31e923fe2 221 KEY_BL_CRC = "bootloader_crc"
Pawel Zarembski 0:01f31e923fe2 222 KEY_IF_CRC = "interface_crc"
Pawel Zarembski 0:01f31e923fe2 223 KEY_REMOUNT_COUNT = "remount_count"
Pawel Zarembski 0:01f31e923fe2 224
Pawel Zarembski 0:01f31e923fe2 225 def __init__(self, unique_id):
Pawel Zarembski 0:01f31e923fe2 226
Pawel Zarembski 0:01f31e923fe2 227 self.unique_id = unique_id
Pawel Zarembski 0:01f31e923fe2 228 self.details_txt = None
Pawel Zarembski 0:01f31e923fe2 229 self._mode = None
Pawel Zarembski 0:01f31e923fe2 230 self._remount_count = None
Pawel Zarembski 0:01f31e923fe2 231 self._assert = None
Pawel Zarembski 0:01f31e923fe2 232 self._check_fs_on_remount = False
Pawel Zarembski 0:01f31e923fe2 233 self._manage_assert = False
Pawel Zarembski 0:01f31e923fe2 234 self.update_board_info()
Pawel Zarembski 0:01f31e923fe2 235
Pawel Zarembski 0:01f31e923fe2 236 def __str__(self):
Pawel Zarembski 0:01f31e923fe2 237 return "Name=%s Unique ID=%s" % (self.name, self.get_unique_id())
Pawel Zarembski 0:01f31e923fe2 238
Pawel Zarembski 0:01f31e923fe2 239 def get_unique_id(self):
Pawel Zarembski 0:01f31e923fe2 240 return self.unique_id
Pawel Zarembski 0:01f31e923fe2 241
Pawel Zarembski 0:01f31e923fe2 242 def get_board_id(self):
Pawel Zarembski 0:01f31e923fe2 243 return self.board_id
Pawel Zarembski 0:01f31e923fe2 244
Pawel Zarembski 0:01f31e923fe2 245 @property
Pawel Zarembski 0:01f31e923fe2 246 def hic_id(self):
Pawel Zarembski 0:01f31e923fe2 247 return self._hic_id
Pawel Zarembski 0:01f31e923fe2 248
Pawel Zarembski 0:01f31e923fe2 249 @property
Pawel Zarembski 0:01f31e923fe2 250 def name(self):
Pawel Zarembski 0:01f31e923fe2 251 if self.board_id in info.BOARD_ID_TO_BUILD_TARGET:
Pawel Zarembski 0:01f31e923fe2 252 board_target = info.BOARD_ID_TO_BUILD_TARGET[self.board_id]
Pawel Zarembski 0:01f31e923fe2 253 else:
Pawel Zarembski 0:01f31e923fe2 254 board_target = "Unknown"
Pawel Zarembski 0:01f31e923fe2 255 return board_target
Pawel Zarembski 0:01f31e923fe2 256
Pawel Zarembski 0:01f31e923fe2 257 def get_serial_port(self):
Pawel Zarembski 0:01f31e923fe2 258 return self.serial_port
Pawel Zarembski 0:01f31e923fe2 259
Pawel Zarembski 0:01f31e923fe2 260 def get_mount_point(self):
Pawel Zarembski 0:01f31e923fe2 261 return self.mount_point
Pawel Zarembski 0:01f31e923fe2 262
Pawel Zarembski 0:01f31e923fe2 263 def get_connected(self):
Pawel Zarembski 0:01f31e923fe2 264 """Check if the board is connected"""
Pawel Zarembski 0:01f31e923fe2 265 return os.path.isdir(self.mount_point)
Pawel Zarembski 0:01f31e923fe2 266
Pawel Zarembski 0:01f31e923fe2 267 def get_failure_message_and_type(self):
Pawel Zarembski 0:01f31e923fe2 268 """Get the failure message and types from fail.txt
Pawel Zarembski 0:01f31e923fe2 269
Pawel Zarembski 0:01f31e923fe2 270 return None if there there is no failure
Pawel Zarembski 0:01f31e923fe2 271 """
Pawel Zarembski 0:01f31e923fe2 272 error = None
Pawel Zarembski 0:01f31e923fe2 273 error_type = None
Pawel Zarembski 0:01f31e923fe2 274 fail_file = self.get_file_path('FAIL.TXT')
Pawel Zarembski 0:01f31e923fe2 275 if not self.get_connected():
Pawel Zarembski 0:01f31e923fe2 276 raise Exception('Board not connected')
Pawel Zarembski 0:01f31e923fe2 277 if os.path.isfile(fail_file):
Pawel Zarembski 0:01f31e923fe2 278 with open(fail_file, 'r') as fail_file_handle:
Pawel Zarembski 0:01f31e923fe2 279 msg = fail_file_handle.read()
Pawel Zarembski 0:01f31e923fe2 280 lines = msg.splitlines()
Pawel Zarembski 0:01f31e923fe2 281 if len(lines) == 2:
Pawel Zarembski 0:01f31e923fe2 282 if lines[0].startswith('error: '):
Pawel Zarembski 0:01f31e923fe2 283 error = lines[0][7:]
Pawel Zarembski 0:01f31e923fe2 284 else:
Pawel Zarembski 0:01f31e923fe2 285 raise Exception('Can not parse error line in FAIL.TXT')
Pawel Zarembski 0:01f31e923fe2 286 if lines[1].startswith('type: '):
Pawel Zarembski 0:01f31e923fe2 287 error_type = lines[1][6:]
Pawel Zarembski 0:01f31e923fe2 288 else:
Pawel Zarembski 0:01f31e923fe2 289 raise Exception('Can not parse type line in FAIL.TXT')
Pawel Zarembski 0:01f31e923fe2 290 else:
Pawel Zarembski 0:01f31e923fe2 291 raise Exception('Wrong number of lines in FAIL.TXT, expected: 2')
Pawel Zarembski 0:01f31e923fe2 292 return error, error_type
Pawel Zarembski 0:01f31e923fe2 293
Pawel Zarembski 0:01f31e923fe2 294 def get_assert_info(self):
Pawel Zarembski 0:01f31e923fe2 295 """Return an AssertInfo if an assert occurred, else None"""
Pawel Zarembski 0:01f31e923fe2 296 return self._assert
Pawel Zarembski 0:01f31e923fe2 297
Pawel Zarembski 0:01f31e923fe2 298 def get_mode(self):
Pawel Zarembski 0:01f31e923fe2 299 """Return either MODE_IF or MODE_BL"""
Pawel Zarembski 0:01f31e923fe2 300 assert ((self._mode is DaplinkBoard.MODE_BL) or
Pawel Zarembski 0:01f31e923fe2 301 (self._mode is DaplinkBoard.MODE_IF))
Pawel Zarembski 0:01f31e923fe2 302 return self._mode
Pawel Zarembski 0:01f31e923fe2 303
Pawel Zarembski 0:01f31e923fe2 304 def get_file_path(self, file_name):
Pawel Zarembski 0:01f31e923fe2 305 """Convenience function to the path to a file on the drive"""
Pawel Zarembski 0:01f31e923fe2 306 return os.path.normpath(self.mount_point + os.sep + file_name)
Pawel Zarembski 0:01f31e923fe2 307
Pawel Zarembski 0:01f31e923fe2 308 def refresh(self, parent_test):
Pawel Zarembski 0:01f31e923fe2 309 """Remount driver to get updated contents"""
Pawel Zarembski 0:01f31e923fe2 310 refresh_filename = self.get_file_path('REFRESH.ACT')
Pawel Zarembski 0:01f31e923fe2 311 with open(refresh_filename, 'wb') as _:
Pawel Zarembski 0:01f31e923fe2 312 pass
Pawel Zarembski 0:01f31e923fe2 313 self.wait_for_remount(parent_test)
Pawel Zarembski 0:01f31e923fe2 314
Pawel Zarembski 0:01f31e923fe2 315 def set_mode(self, mode, parent_test=None):
Pawel Zarembski 0:01f31e923fe2 316 """Set the mode to either MODE_IF or MODE_BL"""
Pawel Zarembski 0:01f31e923fe2 317 assert ((mode is DaplinkBoard.MODE_BL) or
Pawel Zarembski 0:01f31e923fe2 318 (mode is DaplinkBoard.MODE_IF))
Pawel Zarembski 0:01f31e923fe2 319 if parent_test is None:
Pawel Zarembski 0:01f31e923fe2 320 parent_test = TestInfoStub()
Pawel Zarembski 0:01f31e923fe2 321 test_info = parent_test.create_subtest('set_mode')
Pawel Zarembski 0:01f31e923fe2 322 current_mode = self.get_mode()
Pawel Zarembski 0:01f31e923fe2 323 if current_mode is mode:
Pawel Zarembski 0:01f31e923fe2 324 # No mode change needed
Pawel Zarembski 0:01f31e923fe2 325 return
Pawel Zarembski 0:01f31e923fe2 326
Pawel Zarembski 0:01f31e923fe2 327 if mode is self.MODE_BL:
Pawel Zarembski 0:01f31e923fe2 328 test_info.info("changing mode IF -> BL")
Pawel Zarembski 0:01f31e923fe2 329 # Create file to enter BL mode
Pawel Zarembski 0:01f31e923fe2 330 start_bl_path = self.get_file_path('START_BL.ACT')
Pawel Zarembski 0:01f31e923fe2 331 with open(start_bl_path, 'wb') as _: pass
Pawel Zarembski 0:01f31e923fe2 332 elif mode is self.MODE_IF:
Pawel Zarembski 0:01f31e923fe2 333 test_info.info("changing mode BL -> IF")
Pawel Zarembski 0:01f31e923fe2 334 # Create file to enter IF mode
Pawel Zarembski 0:01f31e923fe2 335 start_if_path = self.get_file_path('START_IF.ACT')
Pawel Zarembski 0:01f31e923fe2 336 with open(start_if_path, 'wb') as _: pass
Pawel Zarembski 0:01f31e923fe2 337 else:
Pawel Zarembski 0:01f31e923fe2 338 test_info.warning("Board is in unknown mode")
Pawel Zarembski 0:01f31e923fe2 339 self.wait_for_remount(test_info)
Pawel Zarembski 0:01f31e923fe2 340
Pawel Zarembski 0:01f31e923fe2 341 new_mode = self.get_mode()
Pawel Zarembski 0:01f31e923fe2 342 if new_mode != mode:
Pawel Zarembski 0:01f31e923fe2 343 test_info.failure("Board in wrong mode: %s" % new_mode)
Pawel Zarembski 0:01f31e923fe2 344 raise Exception("Could not change board mode")
Pawel Zarembski 0:01f31e923fe2 345
Pawel Zarembski 0:01f31e923fe2 346 def set_check_fs_on_remount(self, enabled):
Pawel Zarembski 0:01f31e923fe2 347 assert isinstance(enabled, bool)
Pawel Zarembski 0:01f31e923fe2 348 self._check_fs_on_remount = enabled
Pawel Zarembski 0:01f31e923fe2 349 self.set_assert_auto_manage(enabled)
Pawel Zarembski 0:01f31e923fe2 350
Pawel Zarembski 0:01f31e923fe2 351 def set_assert_auto_manage(self, enabled):
Pawel Zarembski 0:01f31e923fe2 352 assert isinstance(enabled, bool)
Pawel Zarembski 0:01f31e923fe2 353 self.clear_assert()
Pawel Zarembski 0:01f31e923fe2 354 self._manage_assert = enabled
Pawel Zarembski 0:01f31e923fe2 355
Pawel Zarembski 0:01f31e923fe2 356 def clear_assert(self):
Pawel Zarembski 0:01f31e923fe2 357 assert_path = self.get_file_path("ASSERT.TXT")
Pawel Zarembski 0:01f31e923fe2 358 if os.path.isfile(assert_path):
Pawel Zarembski 0:01f31e923fe2 359 os.remove(assert_path)
Pawel Zarembski 0:01f31e923fe2 360 self.wait_for_remount(TestInfoStub())
Pawel Zarembski 0:01f31e923fe2 361
Pawel Zarembski 0:01f31e923fe2 362 def run_board_test(self, parent_test):
Pawel Zarembski 0:01f31e923fe2 363 test_daplink.daplink_test(self, parent_test)
Pawel Zarembski 0:01f31e923fe2 364
Pawel Zarembski 0:01f31e923fe2 365 def read_target_memory(self, addr, size, resume=True):
Pawel Zarembski 0:01f31e923fe2 366 assert self.get_mode() == self.MODE_IF
Pawel Zarembski 0:01f31e923fe2 367 with ConnectHelper.session_with_chosen_probe(unique_id=self.get_unique_id(),
Pawel Zarembski 0:01f31e923fe2 368 resume_on_disconnect=resume) as session:
Pawel Zarembski 0:01f31e923fe2 369 data = session.target.read_memory_block8(addr, size)
Pawel Zarembski 0:01f31e923fe2 370 return bytearray(data)
Pawel Zarembski 0:01f31e923fe2 371
Pawel Zarembski 0:01f31e923fe2 372 def test_fs(self, parent_test):
Pawel Zarembski 0:01f31e923fe2 373 """Check if the raw filesystem is valid"""
Pawel Zarembski 0:01f31e923fe2 374 if sys.platform.startswith("win"):
Pawel Zarembski 0:01f31e923fe2 375 test_info = parent_test.create_subtest('test_fs')
Pawel Zarembski 0:01f31e923fe2 376 returncode = _run_chkdsk(self.mount_point)
Pawel Zarembski 0:01f31e923fe2 377 test_info.info('chkdsk returned %s' % returncode)
Pawel Zarembski 0:01f31e923fe2 378 if returncode != 0:
Pawel Zarembski 0:01f31e923fe2 379 test_info.failure('Disk corrupt')
Pawel Zarembski 0:01f31e923fe2 380
Pawel Zarembski 0:01f31e923fe2 381 # Windows 8/10 workaround - rerun chkdsk until disk caching is on
Pawel Zarembski 0:01f31e923fe2 382 # Notes about this problem:
Pawel Zarembski 0:01f31e923fe2 383 # - This is less likely to occur when the "storage" service is
Pawel Zarembski 0:01f31e923fe2 384 # turned off and/or you are running as administrator
Pawel Zarembski 0:01f31e923fe2 385 # - When creating a directory with os.mkdir the
Pawel Zarembski 0:01f31e923fe2 386 # following error occurs: "WindowsError: [Error 1392] The
Pawel Zarembski 0:01f31e923fe2 387 # file or directory is corrupted and unreadable: '<directory>'"
Pawel Zarembski 0:01f31e923fe2 388 # - When creating a file with open(<filename>, "wb") the
Pawel Zarembski 0:01f31e923fe2 389 # following error occurs: "OError: [Errno 22] invalid
Pawel Zarembski 0:01f31e923fe2 390 # mode ('wb') or filename: '<filename>'"
Pawel Zarembski 0:01f31e923fe2 391 # - When a file or directory is created on the drive in explorer
Pawel Zarembski 0:01f31e923fe2 392 # and you preform a refresh, the newly created file or
Pawel Zarembski 0:01f31e923fe2 393 # directory disappears
Pawel Zarembski 0:01f31e923fe2 394 persist_test_dir = self.get_file_path("persist_test_dir")
Pawel Zarembski 0:01f31e923fe2 395 for _ in range(10):
Pawel Zarembski 0:01f31e923fe2 396 try:
Pawel Zarembski 0:01f31e923fe2 397 os.mkdir(persist_test_dir)
Pawel Zarembski 0:01f31e923fe2 398 except EnvironmentError as exception:
Pawel Zarembski 0:01f31e923fe2 399 test_info.info("cache check exception %s" % exception)
Pawel Zarembski 0:01f31e923fe2 400 if os.path.exists(persist_test_dir):
Pawel Zarembski 0:01f31e923fe2 401 os.rmdir(persist_test_dir)
Pawel Zarembski 0:01f31e923fe2 402 break
Pawel Zarembski 0:01f31e923fe2 403 test_info.info("running checkdisk to re-enable caching")
Pawel Zarembski 0:01f31e923fe2 404 _run_chkdsk(self.mount_point)
Pawel Zarembski 0:01f31e923fe2 405 else:
Pawel Zarembski 0:01f31e923fe2 406 raise Exception("Unable to re-enable caching")
Pawel Zarembski 0:01f31e923fe2 407
Pawel Zarembski 0:01f31e923fe2 408 # TODO - as a future improvement add linux and mac support
Pawel Zarembski 0:01f31e923fe2 409
Pawel Zarembski 0:01f31e923fe2 410 # Tests for the following:
Pawel Zarembski 0:01f31e923fe2 411 # 1. Correct files present -TODO
Pawel Zarembski 0:01f31e923fe2 412 # 2. Contents of file are valid ascii
Pawel Zarembski 0:01f31e923fe2 413 # 3. Each line ends with \r\n
Pawel Zarembski 0:01f31e923fe2 414 # 4. There is no whitespace at the end of the line
Pawel Zarembski 0:01f31e923fe2 415 # 5. Each file ends with \r\n
Pawel Zarembski 0:01f31e923fe2 416 def test_fs_contents(self, parent_test):
Pawel Zarembski 0:01f31e923fe2 417 """Check if the file contents are valid"""
Pawel Zarembski 0:01f31e923fe2 418 test_info = parent_test.create_subtest('test_fs_contents')
Pawel Zarembski 0:01f31e923fe2 419 non_ascii = b'[^\x20-\x7F\r\n]'
Pawel Zarembski 0:01f31e923fe2 420 non_cr_lf = b'\r[^\n]|[^\r]\n'
Pawel Zarembski 0:01f31e923fe2 421 trail_white = b'(?:\ \r|\ \n)'
Pawel Zarembski 0:01f31e923fe2 422 end_of_file = b'\r\n$'
Pawel Zarembski 0:01f31e923fe2 423 files = os.listdir(self.mount_point)
Pawel Zarembski 0:01f31e923fe2 424 non_ascii_re = re.compile(non_ascii)
Pawel Zarembski 0:01f31e923fe2 425 non_cr_lf_re = re.compile(non_cr_lf)
Pawel Zarembski 0:01f31e923fe2 426 trail_white_re = re.compile(trail_white)
Pawel Zarembski 0:01f31e923fe2 427 end_of_file_re = re.compile(end_of_file)
Pawel Zarembski 0:01f31e923fe2 428 for filename in files:
Pawel Zarembski 0:01f31e923fe2 429 filepath = self.get_file_path(filename)
Pawel Zarembski 0:01f31e923fe2 430 if not os.path.isfile(filepath):
Pawel Zarembski 0:01f31e923fe2 431 test_info.info("Skipping non file item %s" % filepath)
Pawel Zarembski 0:01f31e923fe2 432 continue
Pawel Zarembski 0:01f31e923fe2 433 skip = False
Pawel Zarembski 0:01f31e923fe2 434 for pattern in FILE_IGNORE_PATTERN_LIST:
Pawel Zarembski 0:01f31e923fe2 435 if pattern.match(filename):
Pawel Zarembski 0:01f31e923fe2 436 skip = True
Pawel Zarembski 0:01f31e923fe2 437 break
Pawel Zarembski 0:01f31e923fe2 438 if skip:
Pawel Zarembski 0:01f31e923fe2 439 continue
Pawel Zarembski 0:01f31e923fe2 440
Pawel Zarembski 0:01f31e923fe2 441 with open(filepath, 'rb') as file_handle:
Pawel Zarembski 0:01f31e923fe2 442 file_contents = file_handle.read()
Pawel Zarembski 0:01f31e923fe2 443 if non_ascii_re.search(file_contents):
Pawel Zarembski 0:01f31e923fe2 444 test_info.failure("Non ascii characters in %s" % filepath)
Pawel Zarembski 0:01f31e923fe2 445 elif non_cr_lf_re.search(file_contents):
Pawel Zarembski 0:01f31e923fe2 446 test_info.failure("File has non-standard line endings %s" %
Pawel Zarembski 0:01f31e923fe2 447 filepath)
Pawel Zarembski 0:01f31e923fe2 448 elif trail_white_re.search(file_contents):
Pawel Zarembski 0:01f31e923fe2 449 test_info.warning("File trailing whitespace %s" %
Pawel Zarembski 0:01f31e923fe2 450 filepath)
Pawel Zarembski 0:01f31e923fe2 451 elif end_of_file_re.search(file_contents) is None:
Pawel Zarembski 0:01f31e923fe2 452 test_info.warning("No newline at end of file %s" %
Pawel Zarembski 0:01f31e923fe2 453 filepath)
Pawel Zarembski 0:01f31e923fe2 454 else:
Pawel Zarembski 0:01f31e923fe2 455 test_info.info("File %s valid" % filepath)
Pawel Zarembski 0:01f31e923fe2 456
Pawel Zarembski 0:01f31e923fe2 457 self.test_details_txt(test_info)
Pawel Zarembski 0:01f31e923fe2 458
Pawel Zarembski 0:01f31e923fe2 459 def load_interface(self, filepath, parent_test):
Pawel Zarembski 0:01f31e923fe2 460 """Load an interface binary or hex"""
Pawel Zarembski 0:01f31e923fe2 461 assert isinstance(filepath, str), "Invalid bootloader image!"
Pawel Zarembski 0:01f31e923fe2 462 assert isinstance(parent_test, TestInfo), "Invalid parent test object!"
Pawel Zarembski 0:01f31e923fe2 463
Pawel Zarembski 0:01f31e923fe2 464 test_info = parent_test.create_subtest('load_interface')
Pawel Zarembski 0:01f31e923fe2 465 self.set_mode(self.MODE_BL, test_info)
Pawel Zarembski 0:01f31e923fe2 466
Pawel Zarembski 0:01f31e923fe2 467 data_crc, crc_in_image = _compute_crc(filepath)
Pawel Zarembski 0:01f31e923fe2 468 assert data_crc == crc_in_image, ("CRC in interface is wrong "
Pawel Zarembski 0:01f31e923fe2 469 "expected 0x%x, found 0x%x" %
Pawel Zarembski 0:01f31e923fe2 470 (data_crc, crc_in_image))
Pawel Zarembski 0:01f31e923fe2 471
Pawel Zarembski 0:01f31e923fe2 472 filename = os.path.basename(filepath)
Pawel Zarembski 0:01f31e923fe2 473 with open(filepath, 'rb') as firmware_file:
Pawel Zarembski 0:01f31e923fe2 474 data = firmware_file.read()
Pawel Zarembski 0:01f31e923fe2 475 out_file = self.get_file_path(filename)
Pawel Zarembski 0:01f31e923fe2 476 start = time.time()
Pawel Zarembski 0:01f31e923fe2 477 with open(out_file, 'wb') as firmware_file:
Pawel Zarembski 0:01f31e923fe2 478 firmware_file.write(data)
Pawel Zarembski 0:01f31e923fe2 479 stop = time.time()
Pawel Zarembski 0:01f31e923fe2 480 test_info.info("programming took %s s" % (stop - start))
Pawel Zarembski 0:01f31e923fe2 481 self.wait_for_remount(test_info)
Pawel Zarembski 0:01f31e923fe2 482
Pawel Zarembski 0:01f31e923fe2 483 # Check the CRC
Pawel Zarembski 0:01f31e923fe2 484 self.set_mode(self.MODE_IF, test_info)
Pawel Zarembski 0:01f31e923fe2 485 if DaplinkBoard.KEY_IF_CRC not in self.details_txt:
Pawel Zarembski 0:01f31e923fe2 486 test_info.failure("No interface CRC in details.txt")
Pawel Zarembski 0:01f31e923fe2 487 return
Pawel Zarembski 0:01f31e923fe2 488 details_crc = int(self.details_txt[DaplinkBoard.KEY_IF_CRC], 0)
Pawel Zarembski 0:01f31e923fe2 489 test_info.info("Interface crc: 0x%x" % details_crc)
Pawel Zarembski 0:01f31e923fe2 490 if data_crc != details_crc:
Pawel Zarembski 0:01f31e923fe2 491 test_info.failure("Interface CRC is wrong")
Pawel Zarembski 0:01f31e923fe2 492
Pawel Zarembski 0:01f31e923fe2 493 def load_bootloader(self, filepath, parent_test):
Pawel Zarembski 0:01f31e923fe2 494 """Load a bootloader binary or hex"""
Pawel Zarembski 0:01f31e923fe2 495 assert isinstance(filepath, str), "Invalid bootloader image!"
Pawel Zarembski 0:01f31e923fe2 496 assert isinstance(parent_test, TestInfo), "Invalid parent test object!"
Pawel Zarembski 0:01f31e923fe2 497
Pawel Zarembski 0:01f31e923fe2 498 test_info = parent_test.create_subtest('load_bootloader')
Pawel Zarembski 0:01f31e923fe2 499 self.set_mode(self.MODE_IF, test_info)
Pawel Zarembski 0:01f31e923fe2 500
Pawel Zarembski 0:01f31e923fe2 501 # Check image CRC
Pawel Zarembski 0:01f31e923fe2 502 data_crc, crc_in_image = _compute_crc(filepath)
Pawel Zarembski 0:01f31e923fe2 503 assert data_crc == crc_in_image, ("CRC in bootloader is wrong "
Pawel Zarembski 0:01f31e923fe2 504 "expected 0x%x, found 0x%x" %
Pawel Zarembski 0:01f31e923fe2 505 (data_crc, crc_in_image))
Pawel Zarembski 0:01f31e923fe2 506
Pawel Zarembski 0:01f31e923fe2 507 filename = os.path.basename(filepath)
Pawel Zarembski 0:01f31e923fe2 508 with open(filepath, 'rb') as firmware_file:
Pawel Zarembski 0:01f31e923fe2 509 data = firmware_file.read()
Pawel Zarembski 0:01f31e923fe2 510 out_file = self.get_file_path(filename)
Pawel Zarembski 0:01f31e923fe2 511 start = time.time()
Pawel Zarembski 0:01f31e923fe2 512 with open(out_file, 'wb') as firmware_file:
Pawel Zarembski 0:01f31e923fe2 513 firmware_file.write(data)
Pawel Zarembski 0:01f31e923fe2 514 stop = time.time()
Pawel Zarembski 0:01f31e923fe2 515 test_info.info("programming took %s s" % (stop - start))
Pawel Zarembski 0:01f31e923fe2 516 self.wait_for_remount(test_info)
Pawel Zarembski 0:01f31e923fe2 517
Pawel Zarembski 0:01f31e923fe2 518 # Check the CRC
Pawel Zarembski 0:01f31e923fe2 519 self.set_mode(self.MODE_IF, test_info)
Pawel Zarembski 0:01f31e923fe2 520 if DaplinkBoard.KEY_BL_CRC not in self.details_txt:
Pawel Zarembski 0:01f31e923fe2 521 test_info.failure("No bootloader CRC in details.txt")
Pawel Zarembski 0:01f31e923fe2 522 return
Pawel Zarembski 0:01f31e923fe2 523 details_crc = int(self.details_txt[DaplinkBoard.KEY_BL_CRC], 0)
Pawel Zarembski 0:01f31e923fe2 524 test_info.info("Bootloader crc: 0x%x" % details_crc)
Pawel Zarembski 0:01f31e923fe2 525 if data_crc != details_crc:
Pawel Zarembski 0:01f31e923fe2 526 test_info.failure("Bootloader CRC is wrong")
Pawel Zarembski 0:01f31e923fe2 527
Pawel Zarembski 0:01f31e923fe2 528 def wait_for_remount(self, parent_test, wait_time=600):
Pawel Zarembski 0:01f31e923fe2 529 mode = self._mode
Pawel Zarembski 0:01f31e923fe2 530 count = self._remount_count
Pawel Zarembski 0:01f31e923fe2 531 test_info = parent_test.create_subtest('wait_for_remount')
Pawel Zarembski 0:01f31e923fe2 532
Pawel Zarembski 0:01f31e923fe2 533 elapsed = 0
Pawel Zarembski 0:01f31e923fe2 534 start = time.time()
Pawel Zarembski 0:01f31e923fe2 535 remounted = False
Pawel Zarembski 0:01f31e923fe2 536 while os.path.isdir(self.mount_point):
Pawel Zarembski 0:01f31e923fe2 537 if self.update_board_info(False): #check info if it is already mounted
Pawel Zarembski 0:01f31e923fe2 538 if mode is not None and self._mode is not None and mode is not self._mode:
Pawel Zarembski 0:01f31e923fe2 539 remounted = True
Pawel Zarembski 0:01f31e923fe2 540 test_info.info("already remounted with change mode")
Pawel Zarembski 0:01f31e923fe2 541 break
Pawel Zarembski 0:01f31e923fe2 542 elif count is not None and self._remount_count is not None and count != self._remount_count:
Pawel Zarembski 0:01f31e923fe2 543 remounted = True
Pawel Zarembski 0:01f31e923fe2 544 test_info.info("already remounted with change mount count")
Pawel Zarembski 0:01f31e923fe2 545 break
Pawel Zarembski 0:01f31e923fe2 546 if elapsed > wait_time:
Pawel Zarembski 0:01f31e923fe2 547 raise Exception("Dismount timed out")
Pawel Zarembski 0:01f31e923fe2 548 time.sleep(0.1)
Pawel Zarembski 0:01f31e923fe2 549 elapsed += 0.2
Pawel Zarembski 0:01f31e923fe2 550 else:
Pawel Zarembski 0:01f31e923fe2 551 stop = time.time()
Pawel Zarembski 0:01f31e923fe2 552 test_info.info("unmount took %s s" % (stop - start))
Pawel Zarembski 0:01f31e923fe2 553 elapsed = 0
Pawel Zarembski 0:01f31e923fe2 554 start = time.time()
Pawel Zarembski 0:01f31e923fe2 555
Pawel Zarembski 0:01f31e923fe2 556 while not remounted:
Pawel Zarembski 0:01f31e923fe2 557 if self.update_board_info(False):
Pawel Zarembski 0:01f31e923fe2 558 if os.path.isdir(self.mount_point):
Pawel Zarembski 0:01f31e923fe2 559 # Information returned by mbed-ls could be old.
Pawel Zarembski 0:01f31e923fe2 560 # Only break from the loop if the second call to
Pawel Zarembski 0:01f31e923fe2 561 # mbed-ls returns the same mount point.
Pawel Zarembski 0:01f31e923fe2 562 tmp_mount = self.mount_point
Pawel Zarembski 0:01f31e923fe2 563 if self.update_board_info(False):
Pawel Zarembski 0:01f31e923fe2 564 if tmp_mount == self.mount_point:
Pawel Zarembski 0:01f31e923fe2 565 break
Pawel Zarembski 0:01f31e923fe2 566 if elapsed > wait_time:
Pawel Zarembski 0:01f31e923fe2 567 raise Exception("Mount timed out")
Pawel Zarembski 0:01f31e923fe2 568 time.sleep(0.1)
Pawel Zarembski 0:01f31e923fe2 569 elapsed += 0.1
Pawel Zarembski 0:01f31e923fe2 570 stop = time.time()
Pawel Zarembski 0:01f31e923fe2 571 test_info.info("mount took %s s" % (stop - start))
Pawel Zarembski 0:01f31e923fe2 572
Pawel Zarembski 0:01f31e923fe2 573 if count is not None and self._remount_count is not None:
Pawel Zarembski 0:01f31e923fe2 574 expected_count = (0 if mode is not self._mode
Pawel Zarembski 0:01f31e923fe2 575 else (count + 1) & 0xFFFFFFFF)
Pawel Zarembski 0:01f31e923fe2 576 if expected_count != self._remount_count:
Pawel Zarembski 0:01f31e923fe2 577 test_info.failure('Expected remount count of %s got %s' %
Pawel Zarembski 0:01f31e923fe2 578 (expected_count, self._remount_count))
Pawel Zarembski 0:01f31e923fe2 579
Pawel Zarembski 0:01f31e923fe2 580 # If enabled check the filesystem
Pawel Zarembski 0:01f31e923fe2 581 if self._check_fs_on_remount:
Pawel Zarembski 0:01f31e923fe2 582 self.test_fs(parent_test)
Pawel Zarembski 0:01f31e923fe2 583 self.test_fs_contents(parent_test)
Pawel Zarembski 0:01f31e923fe2 584 self.test_details_txt(parent_test)
Pawel Zarembski 0:01f31e923fe2 585 if self._manage_assert:
Pawel Zarembski 0:01f31e923fe2 586 if self._assert is not None:
Pawel Zarembski 0:01f31e923fe2 587 test_info.failure('Assert on line %s in file %s' %
Pawel Zarembski 0:01f31e923fe2 588 (self._assert.line, self._assert.file))
Pawel Zarembski 0:01f31e923fe2 589 self.clear_assert()
Pawel Zarembski 0:01f31e923fe2 590
Pawel Zarembski 0:01f31e923fe2 591 def update_board_info(self, exptn_on_fail=True):
Pawel Zarembski 0:01f31e923fe2 592 """Update board info
Pawel Zarembski 0:01f31e923fe2 593
Pawel Zarembski 0:01f31e923fe2 594 Update all board information variables that could
Pawel Zarembski 0:01f31e923fe2 595 change when remounting or changing modes.
Pawel Zarembski 0:01f31e923fe2 596 Note - before this function is set self.unique_id
Pawel Zarembski 0:01f31e923fe2 597 must be set.
Pawel Zarembski 0:01f31e923fe2 598 """
Pawel Zarembski 0:01f31e923fe2 599
Pawel Zarembski 0:01f31e923fe2 600 try:
Pawel Zarembski 0:01f31e923fe2 601 endpoints = _get_board_endpoints(self.unique_id)
Pawel Zarembski 0:01f31e923fe2 602 if endpoints is None:
Pawel Zarembski 0:01f31e923fe2 603 if exptn_on_fail:
Pawel Zarembski 0:01f31e923fe2 604 raise Exception("Could not update board info: %s" %
Pawel Zarembski 0:01f31e923fe2 605 self.unique_id)
Pawel Zarembski 0:01f31e923fe2 606 return False
Pawel Zarembski 0:01f31e923fe2 607 self.unique_id, self.serial_port, self.mount_point = endpoints
Pawel Zarembski 0:01f31e923fe2 608 # Serial port can be missing
Pawel Zarembski 0:01f31e923fe2 609 if self.unique_id is None:
Pawel Zarembski 0:01f31e923fe2 610 if exptn_on_fail:
Pawel Zarembski 0:01f31e923fe2 611 raise Exception("Mount point is null")
Pawel Zarembski 0:01f31e923fe2 612 return False
Pawel Zarembski 0:01f31e923fe2 613 if self.mount_point is None:
Pawel Zarembski 0:01f31e923fe2 614 if exptn_on_fail:
Pawel Zarembski 0:01f31e923fe2 615 raise Exception("Mount point is null")
Pawel Zarembski 0:01f31e923fe2 616 return False
Pawel Zarembski 0:01f31e923fe2 617 self.board_id = int(self.unique_id[0:4], 16)
Pawel Zarembski 0:01f31e923fe2 618 self._hic_id = int(self.unique_id[-8:], 16)
Pawel Zarembski 0:01f31e923fe2 619
Pawel Zarembski 0:01f31e923fe2 620 # Note - Some legacy boards might not have details.txt
Pawel Zarembski 0:01f31e923fe2 621 details_txt_path = self.get_file_path("details.txt")
Pawel Zarembski 0:01f31e923fe2 622 self.details_txt = _parse_kvp_file(details_txt_path)
Pawel Zarembski 0:01f31e923fe2 623 self._parse_assert_txt()
Pawel Zarembski 0:01f31e923fe2 624
Pawel Zarembski 0:01f31e923fe2 625 self._remount_count = None
Pawel Zarembski 0:01f31e923fe2 626 if DaplinkBoard.KEY_REMOUNT_COUNT in self.details_txt:
Pawel Zarembski 0:01f31e923fe2 627 self._remount_count = int(self.details_txt[DaplinkBoard.KEY_REMOUNT_COUNT])
Pawel Zarembski 0:01f31e923fe2 628 self._mode = None
Pawel Zarembski 0:01f31e923fe2 629 if DaplinkBoard.KEY_MODE in self.details_txt:
Pawel Zarembski 0:01f31e923fe2 630 DETAILS_TO_MODE = {
Pawel Zarembski 0:01f31e923fe2 631 "interface": DaplinkBoard.MODE_IF,
Pawel Zarembski 0:01f31e923fe2 632 "bootloader": DaplinkBoard.MODE_BL,
Pawel Zarembski 0:01f31e923fe2 633 }
Pawel Zarembski 0:01f31e923fe2 634 mode_str = self.details_txt[DaplinkBoard.KEY_MODE]
Pawel Zarembski 0:01f31e923fe2 635 self._mode = DETAILS_TO_MODE[mode_str]
Pawel Zarembski 0:01f31e923fe2 636 else:
Pawel Zarembski 0:01f31e923fe2 637 #check for race condition here
Pawel Zarembski 0:01f31e923fe2 638 return False
Pawel Zarembski 0:01f31e923fe2 639 return True
Pawel Zarembski 0:01f31e923fe2 640 except Exception as e:
Pawel Zarembski 0:01f31e923fe2 641 if exptn_on_fail:
Pawel Zarembski 0:01f31e923fe2 642 raise e
Pawel Zarembski 0:01f31e923fe2 643 else:
Pawel Zarembski 0:01f31e923fe2 644 return False
Pawel Zarembski 0:01f31e923fe2 645
Pawel Zarembski 0:01f31e923fe2 646 def test_details_txt(self, parent_test):
Pawel Zarembski 0:01f31e923fe2 647 """Check that details.txt has all requied fields"""
Pawel Zarembski 0:01f31e923fe2 648 test_info = parent_test.create_subtest('test_details_txt')
Pawel Zarembski 0:01f31e923fe2 649 required_key_and_format = {
Pawel Zarembski 0:01f31e923fe2 650 DaplinkBoard.KEY_UNIQUE_ID: re.compile("^[a-f0-9]{48}$"),
Pawel Zarembski 0:01f31e923fe2 651 DaplinkBoard.KEY_HIC_ID: re.compile("^[a-f0-9]{8}$"),
Pawel Zarembski 0:01f31e923fe2 652 DaplinkBoard.KEY_GIT_SHA: re.compile("^[a-f0-9]{40}$"),
Pawel Zarembski 0:01f31e923fe2 653 DaplinkBoard.KEY_LOCAL_MODS: re.compile("^[01]{1}$"),
Pawel Zarembski 0:01f31e923fe2 654 DaplinkBoard.KEY_USB_INTERFACES: re.compile("^.+$"),
Pawel Zarembski 0:01f31e923fe2 655 DaplinkBoard.KEY_MODE: re.compile("(interface|bootloader)"),
Pawel Zarembski 0:01f31e923fe2 656 }
Pawel Zarembski 0:01f31e923fe2 657 optional_key_and_format = {
Pawel Zarembski 0:01f31e923fe2 658 DaplinkBoard.KEY_BL_VERSION: re.compile("^[0-9]{4}$"),
Pawel Zarembski 0:01f31e923fe2 659 DaplinkBoard.KEY_IF_VERSION: re.compile("^[0-9]{4}$"),
Pawel Zarembski 0:01f31e923fe2 660 DaplinkBoard.KEY_BL_CRC: re.compile("^0x[a-f0-9]{8}$"),
Pawel Zarembski 0:01f31e923fe2 661 DaplinkBoard.KEY_IF_CRC: re.compile("^0x[a-f0-9]{8}$"),
Pawel Zarembski 0:01f31e923fe2 662 }
Pawel Zarembski 0:01f31e923fe2 663 # 1. keys and values are alphanumeric
Pawel Zarembski 0:01f31e923fe2 664 # 2. no duplicate keys
Pawel Zarembski 0:01f31e923fe2 665 # 3. format is key : value
Pawel Zarembski 0:01f31e923fe2 666 # 4. required keys are present
Pawel Zarembski 0:01f31e923fe2 667 # 5. optional keys have the expected format
Pawel Zarembski 0:01f31e923fe2 668 details_txt_path = self.get_file_path("details.txt")
Pawel Zarembski 0:01f31e923fe2 669 details_txt = _parse_kvp_file(details_txt_path, test_info)
Pawel Zarembski 0:01f31e923fe2 670 if not details_txt:
Pawel Zarembski 0:01f31e923fe2 671 test_info.failure("Could not parse details.txt")
Pawel Zarembski 0:01f31e923fe2 672 return
Pawel Zarembski 0:01f31e923fe2 673
Pawel Zarembski 0:01f31e923fe2 674 # Check for required keys
Pawel Zarembski 0:01f31e923fe2 675 for key in required_key_and_format:
Pawel Zarembski 0:01f31e923fe2 676 if key not in details_txt:
Pawel Zarembski 0:01f31e923fe2 677 test_info.failure("Missing detail.txt entry: %s" % key)
Pawel Zarembski 0:01f31e923fe2 678 continue
Pawel Zarembski 0:01f31e923fe2 679
Pawel Zarembski 0:01f31e923fe2 680 value = details_txt[key]
Pawel Zarembski 0:01f31e923fe2 681 pattern = required_key_and_format[key]
Pawel Zarembski 0:01f31e923fe2 682 if pattern.match(value) is None:
Pawel Zarembski 0:01f31e923fe2 683 test_info.failure("Bad format detail.txt %s: %s" %
Pawel Zarembski 0:01f31e923fe2 684 (key, value))
Pawel Zarembski 0:01f31e923fe2 685
Pawel Zarembski 0:01f31e923fe2 686 # Check format of optional values
Pawel Zarembski 0:01f31e923fe2 687 for key in optional_key_and_format:
Pawel Zarembski 0:01f31e923fe2 688 if key not in details_txt:
Pawel Zarembski 0:01f31e923fe2 689 continue
Pawel Zarembski 0:01f31e923fe2 690
Pawel Zarembski 0:01f31e923fe2 691 value = details_txt[key]
Pawel Zarembski 0:01f31e923fe2 692 pattern = optional_key_and_format[key]
Pawel Zarembski 0:01f31e923fe2 693 if pattern.match(value) is None:
Pawel Zarembski 0:01f31e923fe2 694 test_info.failure("Bad format detail.txt %s: %s" %
Pawel Zarembski 0:01f31e923fe2 695 (key, value))
Pawel Zarembski 0:01f31e923fe2 696
Pawel Zarembski 0:01f31e923fe2 697 # Check details.txt contents
Pawel Zarembski 0:01f31e923fe2 698 details_unique_id = None
Pawel Zarembski 0:01f31e923fe2 699 details_hic_id = None
Pawel Zarembski 0:01f31e923fe2 700 if DaplinkBoard.KEY_UNIQUE_ID in details_txt:
Pawel Zarembski 0:01f31e923fe2 701 details_unique_id = details_txt[DaplinkBoard.KEY_UNIQUE_ID]
Pawel Zarembski 0:01f31e923fe2 702 if DaplinkBoard.KEY_HIC_ID in details_txt:
Pawel Zarembski 0:01f31e923fe2 703 details_hic_id = details_txt[DaplinkBoard.KEY_HIC_ID]
Pawel Zarembski 0:01f31e923fe2 704 if details_unique_id is not None:
Pawel Zarembski 0:01f31e923fe2 705 if details_unique_id != self.unique_id:
Pawel Zarembski 0:01f31e923fe2 706 test_info.failure("Unique ID mismatch in details.txt "
Pawel Zarembski 0:01f31e923fe2 707 "details.txt=%s, usb=%s" %
Pawel Zarembski 0:01f31e923fe2 708 (details_unique_id, self.unique_id))
Pawel Zarembski 0:01f31e923fe2 709 if details_hic_id is not None:
Pawel Zarembski 0:01f31e923fe2 710 usb_hic = details_unique_id[-8:]
Pawel Zarembski 0:01f31e923fe2 711 if details_hic_id != usb_hic:
Pawel Zarembski 0:01f31e923fe2 712 test_info.failure("HIC ID is not the last 8 "
Pawel Zarembski 0:01f31e923fe2 713 "digits of unique ID "
Pawel Zarembski 0:01f31e923fe2 714 "details.txt=%s, usb=%s" %
Pawel Zarembski 0:01f31e923fe2 715 (details_hic_id, usb_hic))
Pawel Zarembski 0:01f31e923fe2 716
Pawel Zarembski 0:01f31e923fe2 717 def _parse_assert_txt(self):
Pawel Zarembski 0:01f31e923fe2 718 file_path = self.get_file_path("ASSERT.TXT")
Pawel Zarembski 0:01f31e923fe2 719 if not os.path.isfile(file_path):
Pawel Zarembski 0:01f31e923fe2 720 self._assert = None
Pawel Zarembski 0:01f31e923fe2 721 return
Pawel Zarembski 0:01f31e923fe2 722
Pawel Zarembski 0:01f31e923fe2 723 assert_table = _parse_kvp_file(file_path)
Pawel Zarembski 0:01f31e923fe2 724 assert "file" in assert_table
Pawel Zarembski 0:01f31e923fe2 725 assert "line" in assert_table
Pawel Zarembski 0:01f31e923fe2 726
Pawel Zarembski 0:01f31e923fe2 727 self._assert = AssertInfo(assert_table["file"], assert_table['line'])