Exemple #1
0
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}")
Exemple #2
0
    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()
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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)
Exemple #6
0
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
Exemple #7
0
# 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" %