def flash_target(probe, binary, progressCallback=None): print(f"Flashing {binary} to {probe.description}") try: with Session(probe) as session: board = session.board target = board.target # Load firmware into device. FileProgrammer(session, progress=progressCallback).program(binary) # Reset, run. target.reset() except Exception as e: print(f"Error: {e}")
def __init__(self, manager, probe_id: str, target: str = 'stm32f407vg', options: dict = None, idle_time: float = 20): self._manager = manager probe = DebugProbeAggregator.get_probe_with_id(probe_id) if not probe: raise KeyError(f'Failed to find probe {probe_id}') self._session = PyOCDSession(probe, auto_open=False, target_override=target, options=options) self._idle_time = idle_time self._idle_event = None self.lock = threading.Lock()
def test_board(board_id, n, loglevel, logToConsole, commonLogFile): """! @brief Run all tests on a given board. When multiple test jobs are being used, this function is the entry point executed in child processes. Always writes both stdout and log messages of tests to a board-specific log file, and saves the output for each test to a string that is stored in the TestResult object. Depending on the logToConsole and commonLogFile parameters, output may also be copied to the console (sys.stdout) and/or a common log file for all boards. @param board_id Unique ID of the board to test. @param n Unique index of the test run. @param loglevel Log level passed to logger instance. Usually INFO or DEBUG. @param logToConsole Boolean indicating whether output should be copied to sys.stdout. @param commonLogFile If not None, an open file object to which output should be copied. """ probe = DebugProbeAggregator.get_probe_with_id(board_id) assert probe is not None session = Session(probe, **get_session_options()) board = session.board originalStdout = sys.stdout originalStderr = sys.stderr # Open board-specific output file. env_name = (("_" + os.environ['TOX_ENV_NAME']) if ('TOX_ENV_NAME' in os.environ) else '') name_info = "{}_{}_{}".format(env_name, board.name, n) log_filename = LOG_FILE_TEMPLATE.format(name_info) if os.path.exists(log_filename): os.remove(log_filename) log_file = open(log_filename, "a", buffering=1) # 1=Unbuffered # Setup logging. log_handler = RecordingLogHandler(None) log_handler.setFormatter(logging.Formatter(LOG_FORMAT)) root_logger = logging.getLogger() root_logger.setLevel(loglevel) root_logger.addHandler(log_handler) result_list = [] try: # Write board header to board log file, common log file, and console. print_board_header(log_file, board, n) if commonLogFile: print_board_header(commonLogFile, board, n, includeLeadingNewline=(n != 0)) print_board_header(originalStdout, board, n, logToConsole, includeLeadingNewline=(n != 0)) # Skip this board if we don't have a test binary. if board.test_binary is None: print("Skipping board %s due to missing test binary" % board.unique_id) return result_list # Run all tests on this board. for test in test_list: print("{} #{}: starting {}...".format(board.name, n, test.name), file=originalStdout) # Set a unique port for the GdbTest. if isinstance(test, GdbTest): test.n = n # Create a StringIO object to record the test's output, an IOTee to copy # output to both the log file and StringIO, then set the log handler and # stdio to write to the tee. testOutput = io.StringIO() tee = IOTee(log_file, testOutput) if logToConsole: tee.add(originalStdout) if commonLogFile is not None: tee.add(commonLogFile) log_handler.stream = tee sys.stdout = tee sys.stderr = tee test_start = time() result = test.run(board) test_stop = time() result.time = test_stop - test_start tee.flush() result.output = testOutput.getvalue() result_list.append(result) passFail = "PASSED" if result.passed else "FAILED" print("{} #{}: finished {}... {} ({:.3f} s)".format( board.name, n, test.name, passFail, result.time), file=originalStdout) finally: # Restore stdout/stderr in case we're running in the parent process (1 job). sys.stdout = originalStdout sys.stderr = originalStderr root_logger.removeHandler(log_handler) log_handler.flush() log_handler.close() return result_list
def test_board(board_id, n, loglevel, logToConsole, commonLogFile): probe = DebugProbeAggregator.get_probe_with_id(board_id) assert probe is not None session = Session(probe, **get_session_options()) board = session.board originalStdout = sys.stdout originalStderr = sys.stderr # Open board-specific output file. env_name = (("_" + os.environ['TOX_ENV_NAME']) if ('TOX_ENV_NAME' in os.environ) else '') name_info = "{}_{}_{}".format(env_name, board.name, n) log_filename = LOG_FILE_TEMPLATE.format(name_info) if os.path.exists(log_filename): os.remove(log_filename) log_file = open(log_filename, "a", buffering=1) # 1=Unbuffered # Setup logging. log_handler = RecordingLogHandler(None) log_handler.setFormatter(logging.Formatter(LOG_FORMAT)) root_logger = logging.getLogger() root_logger.setLevel(loglevel) root_logger.addHandler(log_handler) result_list = [] try: # Write board header to board log file, common log file, and console. print_board_header(log_file, board, n) if commonLogFile: print_board_header(commonLogFile, board, n, includeLeadingNewline=(n != 0)) print_board_header(originalStdout, board, n, logToConsole, includeLeadingNewline=(n != 0)) # Skip this board if we don't have a test binary. if board.test_binary is None: print("Skipping board %s due to missing test binary" % board.unique_id) return result_list # Run all tests on this board. for test in test_list: print("{} #{}: starting {}...".format(board.name, n, test.name), file=originalStdout) # Set a unique port for the GdbTest. if isinstance(test, GdbTest): test.n = n # Create a StringIO object to record the test's output, an IOTee to copy # output to both the log file and StringIO, then set the log handler and # stdio to write to the tee. testOutput = io.StringIO() tee = IOTee(log_file, testOutput) if logToConsole: tee.add(originalStdout) if commonLogFile is not None: tee.add(commonLogFile) log_handler.stream = tee sys.stdout = tee sys.stderr = tee test_start = time() result = test.run(board) test_stop = time() result.time = test_stop - test_start tee.flush() result.output = testOutput.getvalue() result_list.append(result) passFail = "PASSED" if result.passed else "FAILED" print("{} #{}: finished {}... {} ({:.3f} s)".format( board.name, n, test.name, passFail, result.time), file=originalStdout) finally: # Restore stdout/stderr in case we're running in the parent process (1 job). sys.stdout = originalStdout sys.stderr = originalStderr root_logger.removeHandler(log_handler) log_handler.flush() log_handler.close() return result_list
class OCDSession: def __init__(self, manager, probe_id: str, target: str = 'stm32f407vg', options: dict = None, idle_time: float = 20): self._manager = manager probe = DebugProbeAggregator.get_probe_with_id(probe_id) if not probe: raise KeyError(f'Failed to find probe {probe_id}') self._session = PyOCDSession(probe, auto_open=False, target_override=target, options=options) self._idle_time = idle_time self._idle_event = None self.lock = threading.Lock() @property def id(self): return self._session.probe.unique_id def __eq__(self, other): return other.id == self.id def __hash__(self): return hash(self.id) def _open(self): with self.lock: if not self._session.is_open: try: self._session.open(init_board=True) except USBError as ex: if ex.errno == errno.EBUSY: return False raise return True def _close(self, cancel_idle=True): with self.lock: if self._idle_event: if cancel_idle: self._manager._scheduler.cancel(self._idle_event) self._idle_event = None if not self._session.is_open: return self._manager.logger.info(f'Closing probe {self.id}') self._session.close() def __idle_close(self): self._manager.logger.info(f'Probe {self.id} has become idle') self._close(cancel_idle=False) def __enter__(self): with self.lock: if self._idle_event: self._manager._scheduler.cancel(self._idle_event) self._session.target.reset_and_halt( reset_type=PyOCDTarget.ResetType.HW) self._manager._active.add(self) return self._session def __exit__(self, type_, value, tb): with self.lock: self._idle_event = self._manager._scheduler.enter( self._idle_time, 10, self.__idle_close) self._manager._active.remove(self) self._manager._all.put(self)
def test_gdb(board_id=None, n=0): temp_test_elf_name = None result = GdbTestResult() with ConnectHelper.session_with_chosen_probe(unique_id=board_id, **get_session_options()) as session: board = session.board memory_map = board.target.get_memory_map() ram_region = memory_map.get_default_region_of_type(MemoryType.RAM) rom_region = memory_map.get_boot_memory() target_type = board.target_type binary_file = get_test_binary_path(board.test_binary) if board_id is None: board_id = board.unique_id target_test_params = get_target_test_params(session) test_port = 3333 + n telnet_port = 4444 + n # Hardware breakpoints are not supported above 0x20000000 on # Cortex-M devices with FPB revision 1. fpb = session.target.selected_core.fpb assert fpb is not None ignore_hw_bkpt_result = int(fpb.revision == 1 and ram_region.start >= 0x20000000) # Program with initial test image FileProgrammer(session).program(binary_file, base_address=rom_region.start) # Generate an elf from the binary test file. temp_test_elf_name = binary_to_elf_file(binary_file, rom_region.start) # Write out the test configuration test_params = { "test_port" : test_port, "rom_start" : rom_region.start, "rom_length" : rom_region.length, "ram_start" : ram_region.start, "ram_length" : ram_region.length, "invalid_start" : 0x3E000000, "invalid_length" : 0x1000, "expect_error_on_invalid_access" : target_test_params['error_on_invalid_access'], "ignore_hw_bkpt_result" : ignore_hw_bkpt_result, "test_elf" : temp_test_elf_name, } test_param_filename = os.path.join(TEST_OUTPUT_DIR, "gdb_test_params%s_%d.txt" % (get_env_file_name(), n)) with open(test_param_filename, "w") as f: f.write(json.dumps(test_params)) # Remove result from previous run. test_result_filename = os.path.join(TEST_OUTPUT_DIR, "gdb_test_results%s_%d.txt" % (get_env_file_name(), n)) if os.path.exists(test_result_filename): os.remove(test_result_filename) # Run the test gdb_args = [PYTHON_GDB, "--nh", "-ex", "set $testn=%d" % n, "--command=%s" % GDB_SCRIPT_PATH] gdb_output_filename = os.path.join(TEST_OUTPUT_DIR, "gdb_output%s_%s_%d.txt" % (get_env_file_name(), board.target_type, n)) with open(gdb_output_filename, "w") as f: LOG.info('Starting gdb (stdout -> %s): %s', gdb_output_filename, ' '.join(gdb_args)) gdb_program = Popen(gdb_args, stdin=PIPE, stdout=f, stderr=STDOUT) server_args = ['gdbserver', '--port=%i' % test_port, "--telnet-port=%i" % telnet_port, "--frequency=%i" % target_test_params['test_clock'], "--uid=%s" % board_id, ] server = PyOCDTool() server._setup_logging = lambda: None # Disable logging setup so we don't have duplicate log output. LOG.info('Starting gdbserver: %s', ' '.join(server_args)) server_thread = threading.Thread(target=server.run, args=[server_args]) server_thread.daemon = True server_thread.start() LOG.info('Waiting for gdb to finish...') did_complete = wait_with_deadline(gdb_program, TEST_TIMEOUT_SECONDS) if not did_complete: LOG.error("Test timed out!") LOG.info('Waiting for server to finish...') server_thread.join(timeout=SERVER_EXIT_TIMEOUT) if server_thread.is_alive(): LOG.error('Server is still running! Stopping now... and failing test') did_complete = False session = Session.get_current() LOG.info(f"gdbserver session: {session}") LOG.info(f"gdbservers: {session.gdbservers}") for g in session.gdbservers.values(): g.stop() # Wait again for server thread to complete now that the gdbservers are stopped. server_thread.join(timeout=SERVER_EXIT_TIMEOUT) if server_thread.is_alive(): # The server thread is _still_ alive. Not much we can do at this point. Any tests run # past this point will likely fail. LOG.error("Server thread is still alive after stopping gdbservers!") try: with open(gdb_output_filename, 'r') as f: LOG.debug('Gdb output:\n%s', f.read()) except IOError: pass # Read back the result result.passed = False if did_complete: try: with open(test_result_filename, "r") as f: test_result = json.loads(f.read()) # Print results if set(TEST_RESULT_KEYS).issubset(test_result): print("----------------Test Results----------------") print("HW breakpoint count: %s" % test_result["breakpoint_count"]) print("Watchpoint count: %s" % test_result["watchpoint_count"]) print("Average instruction step time: %s" % test_result["step_time_si"]) print("Average single step time: %s" % test_result["step_time_s"]) print("Average over step time: %s" % test_result["step_time_n"]) print("Failure count: %i" % test_result["fail_count"]) result.passed = test_result["fail_count"] == 0 except IOError as err: LOG.error("Error reading test results: %s", err, exc_info=True) if result.passed: print("GDB TEST PASSED") else: print("GDB TEST FAILED") # Cleanup try: if temp_test_elf_name and os.path.exists(temp_test_elf_name): os.remove(temp_test_elf_name) os.remove(test_result_filename) os.remove(test_param_filename) except IOError as err: pass return result
# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # from pyocd.probe.pydapaccess.dap_access_api import DAPAccessIntf from pyocd.probe.cmsis_dap_probe import CMSISDAPProbe from pyocd.probe.debug_probe import DebugProbe from pyocd.core.session import Session for probe in CMSISDAPProbe.get_all_connected_probes(): probe.session = Session(probe, False) probe.open() probe.connect(DebugProbe.Protocol.SWD) # 0x01 = Get the Vendor Name (string). # 0x02 = Get the Product Name (string). # 0x03 = Get the Serial Number (string). # 0x04 = Get the CMSIS-DAP Protocol Version (string). # 0x05 = Get the Target Device Vendor (string). # 0x06 = Get the Target Device Name (string). # 0x07 = Get the Target Board Vendor (string). # 0x08 = Get the Target Board Name (string). # 0x09 = Get the Product Firmware Version (string, vendor-specific format). print("Vendor Name: %s" % probe._link._protocol.dap_info(DAPAccessIntf.ID.VENDOR)) print("Product Name: %s" %