4630 lines
148 KiB
Python
4630 lines
148 KiB
Python
# decompyle3 version 3.9.0
|
|
# Python bytecode version base 3.7.0 (3394)
|
|
# Decompiled from: Python 3.7.16 (default, Mar 30 2023, 01:25:49)
|
|
# [GCC 12.2.1 20220924]
|
|
# Embedded file name: pylink/jlink.py
|
|
from . import binpacker
|
|
from . import decorators
|
|
from . import enums
|
|
from . import errors
|
|
from . import jlock
|
|
from . import library
|
|
from . import structs
|
|
from . import unlockers
|
|
from . import util
|
|
import ctypes, datetime, functools, itertools, logging, math, operator, sys, time, six
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class JLink(object):
|
|
__doc__ = 'Python interface for the SEGGER J-Link.\n\n This is a wrapper around the J-Link C SDK to provide a Python interface\n to it. The shared library is loaded and used to call the SDK methods.\n '
|
|
MAX_BUF_SIZE = 336
|
|
MAX_NUM_CPU_REGISTERS = 256
|
|
MAX_JTAG_SPEED = 12000
|
|
MIN_JTAG_SPEED = 5
|
|
INVALID_JTAG_SPEED = 65534
|
|
AUTO_JTAG_SPEED = 0
|
|
ADAPTIVE_JTAG_SPEED = 65535
|
|
MAX_NUM_MOES = 8
|
|
|
|
def minimum_required(version):
|
|
"""Decorator to specify the minimum SDK version required.
|
|
|
|
Args:
|
|
version (str): valid version string
|
|
|
|
Returns:
|
|
A decorator function.
|
|
"""
|
|
|
|
def _minimum_required(func):
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(self, *args, **kwargs):
|
|
if list(self.version) < list(version):
|
|
raise errors.JLinkException('Version %s required.' % version)
|
|
return func(self, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return _minimum_required
|
|
|
|
def open_required(func):
|
|
"""Decorator to specify that the J-Link DLL must be opened, and a
|
|
J-Link connection must be established.
|
|
|
|
Args:
|
|
func (function): function being decorated
|
|
|
|
Returns:
|
|
The wrapper function.
|
|
"""
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(self, *args, **kwargs):
|
|
if not self.opened():
|
|
raise errors.JLinkException('J-Link DLL is not open.')
|
|
else:
|
|
if not self.connected():
|
|
raise errors.JLinkException('J-Link connection has been lost.')
|
|
return func(self, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
def connection_required(func):
|
|
"""Decorator to specify that a target connection is required in order
|
|
for the given method to be used.
|
|
|
|
Args:
|
|
func (function): function being decorated
|
|
|
|
Returns:
|
|
The wrapper function.
|
|
"""
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(self, *args, **kwargs):
|
|
if not self.target_connected():
|
|
raise errors.JLinkException('Target is not connected.')
|
|
return func(self, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
def interface_required(interface):
|
|
"""Decorator to specify that a particular interface type is required
|
|
for the given method to be used.
|
|
|
|
Args:
|
|
interface (int): attribute of ``JLinkInterfaces``
|
|
|
|
Returns:
|
|
A decorator function.
|
|
"""
|
|
|
|
def _interface_required(func):
|
|
|
|
@functools.wraps(func)
|
|
def wrapper(self, *args, **kwargs):
|
|
if self.tif != interface:
|
|
raise errors.JLinkException('Unsupported for current interface.')
|
|
return func(self, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return _interface_required
|
|
|
|
def __init__(self, lib=None, log=None, detailed_log=None, error=None, warn=None, unsecure_hook=None, serial_no=None, ip_addr=None, open_tunnel=False):
|
|
"""Initializes the J-Link interface object.
|
|
|
|
Note:
|
|
By default, the unsecure dialog will reject unsecuring the device on
|
|
connection. If you wish to change this behaviour (to have the device
|
|
be unsecured and erased), pass a callback that returns
|
|
``JLinkFlags.DLG_BUTTON_YES`` as its return value.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
lib (Library): a valid ``Library`` instance (not ``None`` dll)
|
|
log (function): function to be called to write out log messages, by
|
|
default this writes to standard out
|
|
detailed_log (function): function to be called to write out detailed
|
|
log messages, by default this writes to standard out
|
|
error (function): function to be called to write out error messages,
|
|
default this writes to standard error
|
|
warn (function): function to be called to write out warning messages,
|
|
default this his writes to standard error
|
|
unsecure_hook (function): function to be called for the unsecure
|
|
dialog
|
|
serial_no (int): serial number of the J-Link
|
|
ip_addr (str): IP address and port of the J-Link
|
|
(e.g. 192.168.1.1:80)
|
|
open_tunnel (bool, None): If ``False`` (default), the ``open``
|
|
method will be called when entering the context manager using
|
|
the ``serial_no`` and ``ip_addr`` provided here.
|
|
If ``True`` ``open_tunnel`` method will be called instead
|
|
of ``open`` method.
|
|
If ``None``, the driver will not be opened automatically
|
|
(however, it is still closed when exiting the context manager).
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
TypeError: if lib's DLL is ``None``
|
|
"""
|
|
self._initialized = False
|
|
if lib is None:
|
|
lib = library.Library()
|
|
if lib.dll() is None:
|
|
raise TypeError('Expected to be given a valid DLL.')
|
|
self._library = lib
|
|
self._dll = lib.dll()
|
|
self._tif = enums.JLinkInterfaces.JTAG
|
|
self._unsecure_hook = unsecure_hook or util.unsecure_hook_dialog
|
|
self._log_handler = None
|
|
self._warning_handler = None
|
|
self._error_handler = None
|
|
self._detailed_log_handler = None
|
|
self._swo_enabled = False
|
|
self._lock = None
|
|
self._device = None
|
|
self._open_refcount = 0
|
|
self._dll.JLINKARM_OpenEx.restype = ctypes.POINTER(ctypes.c_char)
|
|
self._dll.JLINKARM_GetCompileDateTime.restype = ctypes.POINTER(ctypes.c_char)
|
|
self._dll.JLINKARM_GetRegisterName.restype = ctypes.POINTER(ctypes.c_char)
|
|
self.error_handler = lambda s: error or logger.error(s.decode())
|
|
self.warning_handler = lambda s: warn or logger.warning(s.decode())
|
|
self.log_handler = lambda s: log or logger.info(s.decode())
|
|
self.detailed_log_handler = lambda s: detailed_log or logger.debug(s.decode())
|
|
self._JLink__serial_no = serial_no
|
|
self._JLink__ip_addr = ip_addr
|
|
self._JLink__open_tunnel = open_tunnel
|
|
self._initialized = True
|
|
|
|
def __del__(self):
|
|
"""Destructor for the ``JLink`` instance. Closes the J-Link connection
|
|
if one exists.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._finalize()
|
|
|
|
def __enter__(self):
|
|
"""Connects to the J-Link emulator (defaults to USB) using context manager.
|
|
|
|
Parameters passed to __init__ are used for open() function.
|
|
|
|
Returns:
|
|
the ``JLink`` instance
|
|
|
|
Raises:
|
|
JLinkException: if fails to open (i.e. if device is unplugged)
|
|
TypeError: if ``serial_no`` is present, but not ``int`` coercible.
|
|
AttributeError: if ``serial_no`` and ``ip_addr`` are both ``None``.
|
|
"""
|
|
if self._JLink__open_tunnel is False:
|
|
self.open(serial_no=(self._JLink__serial_no), ip_addr=(self._JLink__ip_addr))
|
|
else:
|
|
if self._JLink__open_tunnel is True:
|
|
self.open_tunnel(serial_no=(self._JLink__serial_no))
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
"""Closes the JLink connection on exit of the context manager.
|
|
|
|
Stops the SWO if enabled and closes the J-Link connection if one
|
|
exists.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
exc_type (BaseExceptionType, None): the exception class, if any
|
|
raised inside the context manager
|
|
exc_val (BaseException, None): the exception object, if any raised
|
|
inside the context manager
|
|
exc_tb (TracebackType, None): the exception traceback, if any
|
|
exception was raised inside the context manager.
|
|
|
|
Returns:
|
|
``True`` if exception raised inside the context manager was handled
|
|
and shall be suppressed (not propagated), ``None`` otherwise.
|
|
"""
|
|
self._finalize()
|
|
|
|
def _finalize(self):
|
|
"""Finalizer ("destructor") for the ``JLink`` instance.
|
|
|
|
Stops the SWO if enabled and closes the J-Link connection if one
|
|
exists.
|
|
Called when exiting the context manager or when this object is
|
|
destructed (garbage collected).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
if self._initialized:
|
|
if self.connected():
|
|
if self.swo_enabled():
|
|
self.swo_stop()
|
|
if self.opened():
|
|
self.close()
|
|
|
|
def _get_register_index_from_name(self, register):
|
|
"""
|
|
Converts a register name to a register index
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register (str): the register name
|
|
|
|
Returns:
|
|
``int``
|
|
"""
|
|
regs = list((self.register_name(idx) for idx in self.register_list()))
|
|
if isinstance(register, six.string_types):
|
|
try:
|
|
result = regs.index(register)
|
|
except ValueError:
|
|
error_message = 'No register found matching name: {}. (available registers: {})'
|
|
raise errors.JLinkException(error_message.format(register, ', '.join(regs)))
|
|
|
|
return result
|
|
|
|
def opened(self):
|
|
"""Returns whether the DLL is open.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if the J-Link is open, otherwise ``False``.
|
|
"""
|
|
return bool(self._dll.JLINKARM_IsOpen())
|
|
|
|
def connected(self):
|
|
"""Returns whether a J-Link is connected.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if the J-Link is open and connected, otherwise ``False``.
|
|
"""
|
|
return self.opened() and bool(self._dll.JLINKARM_EMU_IsConnected())
|
|
|
|
def target_connected(self):
|
|
"""Returns whether a target is connected to the J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if a target is connected, otherwise ``False``.
|
|
"""
|
|
return self.connected() and bool(self._dll.JLINKARM_IsConnected())
|
|
|
|
@property
|
|
def log_handler(self):
|
|
"""Returns the log handler function.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None`` if the log handler was not set, otherwise a
|
|
``ctypes.CFUNCTYPE``.
|
|
"""
|
|
return self._log_handler
|
|
|
|
@log_handler.setter
|
|
def log_handler(self, handler):
|
|
"""Setter for the log handler function.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
if not self.opened():
|
|
handler = handler or util.noop
|
|
self._log_handler = enums.JLinkFunctions.LOG_PROTOTYPE(handler)
|
|
self._dll.JLINKARM_EnableLog(self._log_handler)
|
|
|
|
@property
|
|
def detailed_log_handler(self):
|
|
"""Returns the detailed log handler function.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None`` if the detailed log handler was not set, otherwise a
|
|
``ctypes.CFUNCTYPE``.
|
|
"""
|
|
return self._detailed_log_handler
|
|
|
|
@detailed_log_handler.setter
|
|
def detailed_log_handler(self, handler):
|
|
"""Setter for the detailed log handler function.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
if not self.opened():
|
|
handler = handler or util.noop
|
|
self._detailed_log_handler = enums.JLinkFunctions.LOG_PROTOTYPE(handler)
|
|
self._dll.JLINKARM_EnableLogCom(self._detailed_log_handler)
|
|
|
|
@property
|
|
def error_handler(self):
|
|
"""Returns the error handler function.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None`` if the error handler was not set, otherwise a
|
|
``ctypes.CFUNCTYPE``.
|
|
"""
|
|
return self._error_handler
|
|
|
|
@error_handler.setter
|
|
def error_handler(self, handler):
|
|
"""Setter for the error handler function.
|
|
|
|
If the DLL is open, this function is a no-op, so it should be called
|
|
prior to calling ``open()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
handler (function): function to call on error messages
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
if not self.opened():
|
|
handler = handler or util.noop
|
|
self._error_handler = enums.JLinkFunctions.LOG_PROTOTYPE(handler)
|
|
self._dll.JLINKARM_SetErrorOutHandler(self._error_handler)
|
|
|
|
@property
|
|
def warning_handler(self):
|
|
"""Returns the warning handler function.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None`` if the warning handler was not set, otherwise a
|
|
``ctypes.CFUNCTYPE``.
|
|
"""
|
|
return self._warning_handler
|
|
|
|
@warning_handler.setter
|
|
def warning_handler(self, handler):
|
|
"""Setter for the warning handler function.
|
|
|
|
If the DLL is open, this function is a no-op, so it should be called
|
|
prior to calling ``open()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
handler (function): function to call on warning messages
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
if not self.opened():
|
|
handler = handler or util.noop
|
|
self._warning_handler = enums.JLinkFunctions.LOG_PROTOTYPE(handler)
|
|
self._dll.JLINKARM_SetWarnOutHandler(self._warning_handler)
|
|
|
|
def num_connected_emulators(self):
|
|
"""Returns the number of emulators which are connected via USB to the
|
|
host.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The number of connected emulators.
|
|
"""
|
|
return self._dll.JLINKARM_EMU_GetNumDevices()
|
|
|
|
def connected_emulators(self, host=enums.JLinkHost.USB):
|
|
"""Returns a list of all the connected emulators.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
host (int): host type to search (default: ``JLinkHost.USB``)
|
|
|
|
Returns:
|
|
List of ``JLinkConnectInfo`` specifying the connected emulators.
|
|
|
|
Raises:
|
|
JLinkException: if fails to enumerate devices.
|
|
"""
|
|
res = self._dll.JLINKARM_EMU_GetList(host, 0, 0)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
num_devices = res
|
|
info = (structs.JLinkConnectInfo * num_devices)()
|
|
num_found = self._dll.JLINKARM_EMU_GetList(host, info, num_devices)
|
|
if num_found < 0:
|
|
raise errors.JLinkException(num_found)
|
|
return list(info)[:num_found]
|
|
|
|
def num_supported_devices(self):
|
|
"""Returns the number of devices that are supported by the opened
|
|
J-Link DLL.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Number of devices the J-Link DLL supports.
|
|
"""
|
|
return int(self._dll.JLINKARM_DEVICE_GetInfo(-1, 0))
|
|
|
|
def supported_device(self, index=0):
|
|
"""Gets the device at the given ``index``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
index (int): the index of the device whose information to get
|
|
|
|
Returns:
|
|
A ``JLinkDeviceInfo`` describing the requested device.
|
|
|
|
Raises:
|
|
ValueError: if index is less than 0 or >= supported device count.
|
|
"""
|
|
if not util.is_natural(index) or index >= self.num_supported_devices():
|
|
raise ValueError('Invalid index.')
|
|
info = structs.JLinkDeviceInfo()
|
|
result = self._dll.JLINKARM_DEVICE_GetInfo(index, ctypes.byref(info))
|
|
return info
|
|
|
|
def open(self, serial_no=None, ip_addr=None):
|
|
"""Connects to the J-Link emulator (defaults to USB).
|
|
|
|
If ``serial_no`` and ``ip_addr`` are both given, this function will
|
|
connect to the J-Link over TCP/IP.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
serial_no (int): serial number of the J-Link
|
|
ip_addr (str): IP address and port of the J-Link (e.g. 192.168.1.1:80)
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: if fails to open (i.e. if device is unplugged)
|
|
TypeError: if ``serial_no`` is present, but not ``int`` coercible.
|
|
AttributeError: if ``serial_no`` and ``ip_addr`` are both ``None``.
|
|
"""
|
|
if self._open_refcount > 0:
|
|
self._open_refcount += 1
|
|
return
|
|
self.close()
|
|
if ip_addr is not None:
|
|
addr, port = ip_addr.rsplit(':', 1)
|
|
if serial_no is None:
|
|
result = self._dll.JLINKARM_SelectIP(addr.encode(), int(port))
|
|
if result == 1:
|
|
raise errors.JLinkException('Could not connect to emulator at %s.' % ip_addr)
|
|
else:
|
|
self._dll.JLINKARM_EMU_SelectIPBySN(int(serial_no))
|
|
else:
|
|
if serial_no is not None:
|
|
result = self._dll.JLINKARM_EMU_SelectByUSBSN(int(serial_no))
|
|
if result < 0:
|
|
raise errors.JLinkException('No emulator with serial number %s found.' % serial_no)
|
|
else:
|
|
result = self._dll.JLINKARM_SelectUSB(0)
|
|
if result != 0:
|
|
raise errors.JlinkException('Could not connect to default emulator.')
|
|
if serial_no is not None:
|
|
self._lock = jlock.JLock(serial_no)
|
|
if not self._lock.acquire():
|
|
raise errors.JLinkException('J-Link is already open.')
|
|
result = self._dll.JLINKARM_OpenEx(self.log_handler, self.error_handler)
|
|
result = ctypes.cast(result, ctypes.c_char_p).value
|
|
if result is not None:
|
|
raise errors.JLinkException(result.decode())
|
|
unsecure_hook = self._unsecure_hook
|
|
if unsecure_hook is not None:
|
|
if hasattr(self._dll, 'JLINK_SetHookUnsecureDialog'):
|
|
func = enums.JLinkFunctions.UNSECURE_HOOK_PROTOTYPE(unsecure_hook)
|
|
self._dll.JLINK_SetHookUnsecureDialog(func)
|
|
self._open_refcount = 1
|
|
|
|
def open_tunnel(self, serial_no, port=19020):
|
|
"""Connects to the J-Link emulator (over SEGGER tunnel).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
serial_no (int): serial number of the J-Link
|
|
port (int): optional port number (default to 19020).
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
return self.open(ip_addr=('tunnel:' + str(serial_no) + ':' + str(port)))
|
|
|
|
def close(self):
|
|
"""Closes the open J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: if there is no connected JLink.
|
|
"""
|
|
if self._open_refcount == 0:
|
|
return
|
|
self._open_refcount -= 1
|
|
if self._open_refcount > 0:
|
|
return
|
|
self._dll.JLINKARM_Close()
|
|
if self._lock is not None:
|
|
del self._lock
|
|
self._lock = None
|
|
|
|
def test(self):
|
|
"""Performs a self test.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if test passed, otherwise ``False``.
|
|
"""
|
|
res = self._dll.JLINKARM_Test()
|
|
return res == 0
|
|
|
|
@open_required
|
|
def invalidate_firmware(self):
|
|
"""Invalidates the emulator's firmware.
|
|
|
|
This method is useful for downgrading the firmware on an emulator. By
|
|
calling this method, the current emulator's firmware is invalidated,
|
|
which will make the emulator download the firmware of the J-Link SDK
|
|
DLL that this instance was created with.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on hardware error.
|
|
"""
|
|
self.exec_command('InvalidateFW')
|
|
|
|
@open_required
|
|
def update_firmware(self):
|
|
"""Performs a firmware update.
|
|
|
|
If there is a newer version of firmware available for the J-Link
|
|
device, then updates the firmware.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Checksum of the new firmware on update, ``0`` if the firmware was not
|
|
changed.
|
|
"""
|
|
return self._dll.JLINKARM_UpdateFirmwareIfNewer()
|
|
|
|
@open_required
|
|
def sync_firmware(self):
|
|
"""Syncs the emulator's firmware version and the DLL's firmware.
|
|
|
|
This method is useful for ensuring that the firmware running on the
|
|
J-Link matches the firmware supported by the DLL.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
serial_no = self.serial_number
|
|
if self.firmware_newer():
|
|
try:
|
|
self.invalidate_firmware()
|
|
self.update_firmware()
|
|
except errors.JLinkException as e:
|
|
try:
|
|
pass
|
|
finally:
|
|
e = None
|
|
del e
|
|
|
|
res = self.open(serial_no=serial_no)
|
|
if self.firmware_newer():
|
|
raise errors.JLinkException('Failed to sync firmware version.')
|
|
return res
|
|
if self.firmware_outdated():
|
|
try:
|
|
self.update_firmware()
|
|
except errors.JLinkException as e:
|
|
try:
|
|
pass
|
|
finally:
|
|
e = None
|
|
del e
|
|
|
|
if self.firmware_outdated():
|
|
raise errors.JLinkException('Failed to sync firmware version.')
|
|
return self.open(serial_no=serial_no)
|
|
|
|
def exec_command(self, cmd):
|
|
"""Executes the given command.
|
|
|
|
This method executes a command by calling the DLL's exec method.
|
|
Direct API methods should be prioritized over calling this method.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
cmd (str): the command to run
|
|
|
|
Returns:
|
|
The return code of running the command.
|
|
|
|
Raises:
|
|
JLinkException: if the command is invalid or fails.
|
|
|
|
See Also:
|
|
For a full list of the supported commands, please see the SEGGER
|
|
J-Link documentation,
|
|
`UM08001 <https://www.segger.com/downloads/jlink>`__.
|
|
"""
|
|
err_buf = (ctypes.c_char * self.MAX_BUF_SIZE)()
|
|
res = self._dll.JLINKARM_ExecCommand(cmd.encode(), err_buf, self.MAX_BUF_SIZE)
|
|
err_buf = ctypes.string_at(err_buf).decode()
|
|
if len(err_buf) > 0:
|
|
raise errors.JLinkException(err_buf.strip())
|
|
return res
|
|
|
|
@minimum_required('5.02')
|
|
def enable_dialog_boxes(self):
|
|
"""Enables showing dialog boxes on certain methods.
|
|
|
|
Note:
|
|
Dialog boxes only appear on Windows platforms.
|
|
|
|
Note:
|
|
This can be used for batch or automized test running.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self.exec_command('SetBatchMode = 0')
|
|
|
|
@minimum_required('5.02')
|
|
def disable_dialog_boxes(self):
|
|
"""Disables showing dialog boxes on certain methods.
|
|
|
|
Note:
|
|
Dialog boxes only appear on Windows platforms.
|
|
|
|
Warning:
|
|
This has the effect of also silencing dialog boxes that appear when
|
|
updating firmware / to confirm updating firmware.
|
|
|
|
Dialog boxes will be shown for a brief period of time (approximately
|
|
five seconds), before being automatically hidden, and the default
|
|
option chosen.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self.exec_command('SilentUpdateFW')
|
|
self.exec_command('SuppressInfoUpdateFW')
|
|
self.exec_command('SetBatchMode = 1')
|
|
|
|
@open_required
|
|
def jtag_configure(self, instr_regs=0, data_bits=0):
|
|
"""Configures the JTAG scan chain to determine which CPU to address.
|
|
|
|
Must be called if the J-Link is connected to a JTAG scan chain with
|
|
multiple devices.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
instr_regs (int): length of instruction registers of all devices
|
|
closer to TD1 then the addressed CPU
|
|
data_bits (int): total number of data bits closer to TD1 than the
|
|
addressed CPU
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
ValueError: if ``instr_regs`` or ``data_bits`` are not natural numbers
|
|
"""
|
|
if not util.is_natural(instr_regs):
|
|
raise ValueError('IR value is not a natural number.')
|
|
if not util.is_natural(data_bits):
|
|
raise ValueError('Data bits is not a natural number.')
|
|
self._dll.JLINKARM_ConfigJTAG(instr_regs, data_bits)
|
|
|
|
@open_required
|
|
@minimum_required('4.98e')
|
|
def coresight_configure(self, ir_pre=0, dr_pre=0, ir_post=0, dr_post=0, ir_len=0, perform_tif_init=True):
|
|
"""Prepares target and J-Link for CoreSight function usage.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
ir_pre (int): sum of instruction register length of all JTAG devices
|
|
in the JTAG chain, close to TDO than the actual one, that J-Link
|
|
shall communicate with
|
|
dr_pre (int): number of JTAG devices in the JTAG chain, closer to TDO
|
|
than the actual one, that J-Link shall communicate with
|
|
ir_post (int): sum of instruction register length of all JTAG devices
|
|
in the JTAG chain, following the actual one, that J-Link shall
|
|
communicate with
|
|
dr_post (int): Number of JTAG devices in the JTAG chain, following
|
|
the actual one, J-Link shall communicate with
|
|
ir_len (int): instruction register length of the actual device that
|
|
J-Link shall communicate with
|
|
perform_tif_init (bool): if ``False``, then do not output switching
|
|
sequence on completion
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Note:
|
|
This must be called before calling ``coresight_read()`` or
|
|
``coresight_write()``.
|
|
"""
|
|
if self.tif == enums.JLinkInterfaces.SWD:
|
|
res = self._dll.JLINKARM_CORESIGHT_Configure('')
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return
|
|
config_string = 'IRPre=%s;DRPre=%s;IRPost=%s;DRPost=%s;IRLenDevice=%s;'
|
|
config_string = config_string % (ir_pre, dr_pre, ir_post, dr_post, ir_len)
|
|
if not perform_tif_init:
|
|
config_string = config_string + 'PerformTIFInit=0;'
|
|
res = self._dll.JLINKARM_CORESIGHT_Configure(config_string.encode())
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@open_required
|
|
def connect(self, chip_name, speed='auto', verbose=False):
|
|
"""Connects the J-Link to its target.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
chip_name (str): target chip name
|
|
speed (int): connection speed, one of ``{5-12000, 'auto', 'adaptive'}``
|
|
verbose (bool): boolean indicating if connection should be verbose in logging
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: if connection fails to establish.
|
|
TypeError: if given speed is invalid
|
|
"""
|
|
if verbose:
|
|
self.exec_command('EnableRemarks = 1')
|
|
self.exec_command('Device = %s' % chip_name)
|
|
if speed == 'auto':
|
|
self.set_speed(auto=True)
|
|
else:
|
|
if speed == 'adaptive':
|
|
self.set_speed(adaptive=True)
|
|
else:
|
|
self.set_speed(speed)
|
|
result = self._dll.JLINKARM_Connect()
|
|
if result < 0:
|
|
raise errors.JLinkException(result)
|
|
try:
|
|
self.halted()
|
|
except errors.JLinkException:
|
|
pass
|
|
|
|
for index in range(self.num_supported_devices()):
|
|
device = self.supported_device(index)
|
|
if device.name.lower() == chip_name.lower():
|
|
self._device = device
|
|
break
|
|
else:
|
|
raise errors.JLinkException('Unsupported device was connected to.')
|
|
|
|
@property
|
|
def error(self):
|
|
"""DLL internal error state.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The DLL internal error state. This is set if any error occurs in
|
|
underlying DLL, otherwise it is ``None``.
|
|
"""
|
|
error = int(self._dll.JLINKARM_HasError())
|
|
if error == 0:
|
|
return
|
|
return error
|
|
|
|
def clear_error(self):
|
|
"""Clears the DLL internal error state.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The error state before the clear.
|
|
"""
|
|
error = self.error
|
|
self._dll.JLINKARM_ClrError()
|
|
return error
|
|
|
|
@property
|
|
def compile_date(self):
|
|
"""Returns a string specifying the date and time at which the DLL was
|
|
translated.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Datetime string.
|
|
"""
|
|
result = self._dll.JLINKARM_GetCompileDateTime()
|
|
return ctypes.cast(result, ctypes.c_char_p).value.decode()
|
|
|
|
@property
|
|
def version(self):
|
|
"""Returns the device's version.
|
|
|
|
The device's version is returned as a string of the format: M.mr where
|
|
``M`` is major number, ``m`` is minor number, and ``r`` is revision
|
|
character.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Device version string.
|
|
"""
|
|
version = int(self._dll.JLINKARM_GetDLLVersion())
|
|
major = version / 10000
|
|
minor = version / 100 % 100
|
|
rev = version % 100
|
|
rev = '' if rev == 0 else chr(rev + ord('a') - 1)
|
|
return '%d.%02d%s' % (major, minor, rev)
|
|
|
|
@property
|
|
@open_required
|
|
def compatible_firmware_version(self):
|
|
"""Returns the DLL's compatible J-Link firmware version.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The firmware version of the J-Link that the DLL is compatible
|
|
with.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
identifier = self.firmware_version.split('compiled')[0]
|
|
buf_size = self.MAX_BUF_SIZE
|
|
buf = (ctypes.c_char * buf_size)()
|
|
res = self._dll.JLINKARM_GetEmbeddedFWString(identifier.encode(), buf, buf_size)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@open_required
|
|
def firmware_outdated(self):
|
|
"""Returns whether the J-Link's firmware version is older than the one
|
|
that the DLL is compatible with.
|
|
|
|
Note:
|
|
This is not the same as calling ``not jlink.firmware_newer()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if the J-Link's firmware is older than the one supported by
|
|
the DLL, otherwise ``False``.
|
|
"""
|
|
datefmt = ' %b %d %Y %H:%M:%S'
|
|
compat_date = self.compatible_firmware_version.split('compiled')[1]
|
|
compat_date = datetime.datetime.strptime(compat_date, datefmt)
|
|
fw_date = self.firmware_version.split('compiled')[1]
|
|
fw_date = datetime.datetime.strptime(fw_date, datefmt)
|
|
return compat_date > fw_date
|
|
|
|
@open_required
|
|
def firmware_newer(self):
|
|
"""Returns whether the J-Link's firmware version is newer than the one
|
|
that the DLL is compatible with.
|
|
|
|
Note:
|
|
This is not the same as calling ``not jlink.firmware_outdated()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if the J-Link's firmware is newer than the one supported by
|
|
the DLL, otherwise ``False``.
|
|
"""
|
|
if self.firmware_outdated():
|
|
return False
|
|
return self.firmware_version != self.compatible_firmware_version
|
|
|
|
@property
|
|
@open_required
|
|
def hardware_info(self, mask=4294967295):
|
|
"""Returns a list of 32 integer values corresponding to the bitfields
|
|
specifying the power consumption of the target.
|
|
|
|
The values returned by this function only have significance if the
|
|
J-Link is powering the target.
|
|
|
|
The words, indexed, have the following significance:
|
|
0. If ``1``, target is powered via J-Link.
|
|
1. Overcurrent bitfield:
|
|
0: No overcurrent.
|
|
1: Overcurrent happened. 2ms @ 3000mA
|
|
2: Overcurrent happened. 10ms @ 1000mA
|
|
3: Overcurrent happened. 40ms @ 400mA
|
|
2. Power consumption of target (mA).
|
|
3. Peak of target power consumption (mA).
|
|
4. Peak of target power consumption during J-Link operation (mA).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
mask (int): bit mask to decide which hardware information words are
|
|
returned (defaults to all the words).
|
|
|
|
Returns:
|
|
List of bitfields specifying different states based on their index
|
|
within the list and their value.
|
|
|
|
Raises:
|
|
JLinkException: on hardware error.
|
|
"""
|
|
buf = (ctypes.c_uint32 * 32)()
|
|
res = self._dll.JLINKARM_GetHWInfo(mask, ctypes.byref(buf))
|
|
if res != 0:
|
|
raise errors.JLinkException(res)
|
|
return list(buf)
|
|
|
|
@property
|
|
@open_required
|
|
def hardware_status(self):
|
|
"""Retrieves and returns the hardware status.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
A ``JLinkHardwareStatus`` describing the J-Link hardware.
|
|
"""
|
|
stat = structs.JLinkHardwareStatus()
|
|
res = self._dll.JLINKARM_GetHWStatus(ctypes.byref(stat))
|
|
if res == 1:
|
|
raise errors.JLinkException('Error in reading hardware status.')
|
|
return stat
|
|
|
|
@property
|
|
@open_required
|
|
def hardware_version(self):
|
|
"""Returns the hardware version of the connected J-Link as a
|
|
major.minor string.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Hardware version string.
|
|
"""
|
|
version = self._dll.JLINKARM_GetHardwareVersion()
|
|
major = version / 10000 % 100
|
|
minor = version / 100 % 100
|
|
return '%d.%02d' % (major, minor)
|
|
|
|
@property
|
|
@open_required
|
|
def firmware_version(self):
|
|
"""Returns a firmware identification string of the connected J-Link.
|
|
|
|
It consists of the following:
|
|
- Product Name (e.g. J-Link)
|
|
- The string: compiled
|
|
- Compile data and time.
|
|
- Optional additional information.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Firmware identification string.
|
|
"""
|
|
buf = (ctypes.c_char * self.MAX_BUF_SIZE)()
|
|
self._dll.JLINKARM_GetFirmwareString(buf, self.MAX_BUF_SIZE)
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@property
|
|
@open_required
|
|
def capabilities(self):
|
|
"""Returns a bitwise combination of the emulator's capabilities.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Bitfield of emulator capabilities.
|
|
"""
|
|
return self._dll.JLINKARM_GetEmuCaps()
|
|
|
|
@property
|
|
@open_required
|
|
def extended_capabilities(self):
|
|
"""Gets the capabilities of the connected emulator as a list.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
List of 32 integers which define the extended capabilities based on
|
|
their value and index within the list.
|
|
"""
|
|
buf = (ctypes.c_uint8 * 32)()
|
|
self._dll.JLINKARM_GetEmuCapsEx(buf, 32)
|
|
return list(buf)
|
|
|
|
@open_required
|
|
def extended_capability(self, capability):
|
|
"""Checks if the emulator has the given extended capability.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
capability (int): capability being queried
|
|
|
|
Returns:
|
|
``True`` if the emulator has the given extended capability, otherwise
|
|
``False``.
|
|
"""
|
|
res = self._dll.JLINKARM_EMU_HasCapEx(capability)
|
|
return res == 1
|
|
|
|
@property
|
|
@open_required
|
|
def features(self):
|
|
"""Returns a list of the J-Link embedded features.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
A list of strings, each a feature. Example:
|
|
``[ 'RDI', 'FlashBP', 'FlashDL', 'JFlash', 'GDB' ]``
|
|
"""
|
|
buf = (ctypes.c_char * self.MAX_BUF_SIZE)()
|
|
self._dll.JLINKARM_GetFeatureString(buf)
|
|
result = ctypes.string_at(buf).decode().strip()
|
|
if len(result) == 0:
|
|
return list()
|
|
return result.split(', ')
|
|
|
|
@property
|
|
@open_required
|
|
def product_name(self):
|
|
"""Returns the product name of the connected J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Product name.
|
|
"""
|
|
buf = (ctypes.c_char * self.MAX_BUF_SIZE)()
|
|
self._dll.JLINKARM_EMU_GetProductName(buf, self.MAX_BUF_SIZE)
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@property
|
|
@open_required
|
|
def serial_number(self):
|
|
"""Returns the serial number of the connected J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Serial number as an integer.
|
|
"""
|
|
return self._dll.JLINKARM_GetSN()
|
|
|
|
@property
|
|
@open_required
|
|
def oem(self):
|
|
"""Retrieves and returns the OEM string of the connected J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The string of the OEM. If this is an original SEGGER product, then
|
|
``None`` is returned instead.
|
|
|
|
Raises:
|
|
JLinkException: on hardware error.
|
|
"""
|
|
buf = (ctypes.c_char * self.MAX_BUF_SIZE)()
|
|
res = self._dll.JLINKARM_GetOEMString(ctypes.byref(buf))
|
|
if res != 0:
|
|
raise errors.JLinkException('Failed to grab OEM string.')
|
|
oem = ctypes.string_at(buf).decode()
|
|
if len(oem) == 0:
|
|
return
|
|
return oem
|
|
|
|
@property
|
|
@open_required
|
|
def index(self):
|
|
"""Retrieves and returns the index number of the actual selected
|
|
J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Index of the currently connected J-Link.
|
|
"""
|
|
return self._dll.JLINKARM_GetSelDevice()
|
|
|
|
@property
|
|
@open_required
|
|
def speed(self):
|
|
"""Returns the current JTAG connection speed.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
JTAG connection speed.
|
|
"""
|
|
return self._dll.JLINKARM_GetSpeed()
|
|
|
|
@open_required
|
|
def set_speed(self, speed=None, auto=False, adaptive=False):
|
|
"""Sets the speed of the JTAG communication with the ARM core.
|
|
|
|
If no arguments are present, automatically detects speed.
|
|
|
|
If a ``speed`` is provided, the speed must be no larger than
|
|
``JLink.MAX_JTAG_SPEED`` and no smaller than ``JLink.MIN_JTAG_SPEED``.
|
|
The given ``speed`` can also not be ``JLink.INVALID_JTAG_SPEED``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
speed (int): the speed in kHz to set the communication at
|
|
auto (bool): automatically detect correct speed
|
|
adaptive (bool): select adaptive clocking as JTAG speed
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
TypeError: if given speed is not a natural number.
|
|
ValueError: if given speed is too high, too low, or invalid.
|
|
"""
|
|
if speed is None:
|
|
speed = 0
|
|
else:
|
|
if not util.is_natural(speed):
|
|
raise TypeError('Expected positive number for speed, given %s.' % speed)
|
|
else:
|
|
if speed > self.MAX_JTAG_SPEED:
|
|
raise ValueError('Given speed exceeds max speed of %d.' % self.MAX_JTAG_SPEED)
|
|
else:
|
|
if speed < self.MIN_JTAG_SPEED:
|
|
raise ValueError('Given speed is too slow. Minimum is %d.' % self.MIN_JTAG_SPEED)
|
|
if auto:
|
|
speed = speed | self.AUTO_JTAG_SPEED
|
|
if adaptive:
|
|
speed = speed | self.ADAPTIVE_JTAG_SPEED
|
|
self._dll.JLINKARM_SetSpeed(speed)
|
|
|
|
@open_required
|
|
def set_max_speed(self):
|
|
"""Sets JTAG communication speed to the maximum supported speed.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_SetMaxSpeed()
|
|
|
|
@property
|
|
@open_required
|
|
def speed_info(self):
|
|
"""Retrieves information about supported target interface speeds.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The ``JLinkSpeedInfo`` instance describing the supported target
|
|
interface speeds.
|
|
"""
|
|
speed_info = structs.JLinkSpeedInfo()
|
|
self._dll.JLINKARM_GetSpeedInfo(ctypes.byref(speed_info))
|
|
return speed_info
|
|
|
|
@property
|
|
@open_required
|
|
def licenses(self):
|
|
"""Returns a string of the built-in licenses the J-Link has.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
String of the contents of the built-in licenses the J-Link has.
|
|
"""
|
|
buf_size = self.MAX_BUF_SIZE
|
|
buf = (ctypes.c_char * buf_size)()
|
|
res = self._dll.JLINK_GetAvailableLicense(buf, buf_size)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@property
|
|
@open_required
|
|
@minimum_required('4.98b')
|
|
def custom_licenses(self):
|
|
"""Returns a string of the installed licenses the J-Link has.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
String of the contents of the custom licenses the J-Link has.
|
|
"""
|
|
buf = (ctypes.c_char * self.MAX_BUF_SIZE)()
|
|
result = self._dll.JLINK_EMU_GetLicenses(buf, self.MAX_BUF_SIZE)
|
|
if result < 0:
|
|
raise errors.JLinkException(result)
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@open_required
|
|
@minimum_required('4.98b')
|
|
def add_license(self, contents):
|
|
"""Adds the given ``contents`` as a new custom license to the J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
contents: the string contents of the new custom license
|
|
|
|
Returns:
|
|
``True`` if license was added, ``False`` if license already existed.
|
|
|
|
Raises:
|
|
JLinkException: if the write fails.
|
|
|
|
Note:
|
|
J-Link V9 and J-Link ULTRA/PRO V4 have 336 Bytes of memory for
|
|
licenses, while older versions of 80 bytes.
|
|
"""
|
|
buf_size = len(contents)
|
|
buf = (ctypes.c_char * (buf_size + 1))(*contents.encode())
|
|
res = self._dll.JLINK_EMU_AddLicense(buf)
|
|
if res == -1:
|
|
raise errors.JLinkException('Unspecified error.')
|
|
else:
|
|
if res == -2:
|
|
raise errors.JLinkException('Failed to read/write license area.')
|
|
else:
|
|
if res == -3:
|
|
raise errors.JLinkException('J-Link out of space.')
|
|
return res == 0
|
|
|
|
@open_required
|
|
@minimum_required('4.98b')
|
|
def erase_licenses(self):
|
|
"""Erases the custom licenses from the connected J-Link.
|
|
|
|
Note:
|
|
This method will erase all licenses stored on the J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` on success, otherwise ``False``.
|
|
"""
|
|
res = self._dll.JLINK_EMU_EraseLicenses()
|
|
return res == 0
|
|
|
|
@property
|
|
@open_required
|
|
def tif(self):
|
|
"""Returns the current target interface of the J-Link.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Integer specifying the current target interface.
|
|
"""
|
|
return self._tif
|
|
|
|
@open_required
|
|
def supported_tifs(self):
|
|
"""Returns a bitmask of the supported target interfaces.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Bitfield specifying which target interfaces are supported.
|
|
"""
|
|
buf = ctypes.c_uint32()
|
|
self._dll.JLINKARM_TIF_GetAvailable(ctypes.byref(buf))
|
|
return buf.value
|
|
|
|
@open_required
|
|
def set_tif(self, interface):
|
|
"""Selects the specified target interface.
|
|
|
|
Note that a restart must be triggered for this to take effect.
|
|
|
|
Args:
|
|
self (Jlink): the ``JLink`` instance
|
|
interface (int): integer identifier of the interface
|
|
|
|
Returns:
|
|
``True`` if target was updated, otherwise ``False``.
|
|
|
|
Raises:
|
|
JLinkException: if the given interface is invalid or unsupported.
|
|
"""
|
|
if not 1 << interface & self.supported_tifs():
|
|
raise errors.JLinkException('Unsupported target interface: %s' % interface)
|
|
res = self._dll.JLINKARM_TIF_Select(interface)
|
|
if res != 0:
|
|
return False
|
|
self._tif = interface
|
|
return True
|
|
|
|
@open_required
|
|
def gpio_properties(self):
|
|
"""Returns the properties of the user-controllable GPIOs.
|
|
|
|
Provided the device supports user-controllable GPIOs, they will be
|
|
returned by this method.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
A list of ``JLinkGPIODescriptor`` instances totalling the number of
|
|
requested properties.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
res = self._dll.JLINK_EMU_GPIO_GetProps(0, 0)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
num_props = res
|
|
buf = (structs.JLinkGPIODescriptor * num_props)()
|
|
res = self._dll.JLINK_EMU_GPIO_GetProps(ctypes.byref(buf), num_props)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return list(buf)
|
|
|
|
@open_required
|
|
def gpio_get(self, pins=None):
|
|
"""Returns a list of states for the given pins.
|
|
|
|
Defaults to the first four pins if an argument is not given.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
pins (list): indices of the GPIO pins whose states are requested
|
|
|
|
Returns:
|
|
A list of states.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
if pins is None:
|
|
pins = range(4)
|
|
size = len(pins)
|
|
indices = (ctypes.c_uint8 * size)(*pins)
|
|
statuses = (ctypes.c_uint8 * size)()
|
|
result = self._dll.JLINK_EMU_GPIO_GetState(ctypes.byref(indices), ctypes.byref(statuses), size)
|
|
if result < 0:
|
|
raise errors.JLinkException(result)
|
|
return list(statuses)
|
|
|
|
@open_required
|
|
def gpio_set(self, pins, states):
|
|
"""Sets the state for one or more user-controllable GPIOs.
|
|
|
|
For each of the given pins, sets the the corresponding state based on
|
|
the index.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
pins (list): list of GPIO indices
|
|
states (list): list of states to set
|
|
|
|
Returns:
|
|
A list of updated states.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
ValueError: if ``len(pins) != len(states)``
|
|
"""
|
|
if len(pins) != len(states):
|
|
raise ValueError('Length mismatch between pins and states.')
|
|
size = len(pins)
|
|
indices = (ctypes.c_uint8 * size)(*pins)
|
|
states = (ctypes.c_uint8 * size)(*states)
|
|
result_states = (ctypes.c_uint8 * size)()
|
|
result = self._dll.JLINK_EMU_GPIO_SetState(ctypes.byref(indices), ctypes.byref(states), ctypes.byref(result_states), size)
|
|
if result < 0:
|
|
raise errors.JLinkException(result)
|
|
return list(result_states)
|
|
|
|
@open_required
|
|
def comm_supported(self):
|
|
"""Returns true if the connected emulator supports ``comm_*``
|
|
functions.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if the emulator supports ``comm_*`` functions, otherwise
|
|
``False``.
|
|
"""
|
|
return bool(self._dll.JLINKARM_EMU_COM_IsSupported())
|
|
|
|
@open_required
|
|
def power_on(self, default=False):
|
|
"""Turns on the power supply over pin 19 of the JTAG connector.
|
|
|
|
If given the optional ``default`` parameter, activates the power supply
|
|
by default.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
default (bool): boolean indicating if to set power by default
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: if J-Link does not support powering the target.
|
|
"""
|
|
if default:
|
|
return self.exec_command('SupplyPowerDefault = 1')
|
|
return self.exec_command('SupplyPower = 1')
|
|
|
|
@open_required
|
|
def power_off(self, default=False):
|
|
"""Turns off the power supply over pin 19 of the JTAG connector.
|
|
|
|
If given the optional ``default`` parameter, deactivates the power supply
|
|
by default.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
default (bool): boolean indicating if to set power off by default
|
|
|
|
Returns:
|
|
The current ``JLink`` instance
|
|
|
|
Raises:
|
|
JLinkException: if J-Link does not support powering the target.
|
|
"""
|
|
if default:
|
|
return self.exec_command('SupplyPowerDefault = 0')
|
|
return self.exec_command('SupplyPower = 0')
|
|
|
|
@connection_required
|
|
def unlock(self):
|
|
"""Unlocks the device connected to the J-Link.
|
|
|
|
Unlocking a device allows for access to read/writing memory, as well as
|
|
flash programming.
|
|
|
|
Note:
|
|
Unlock is not supported on all devices.
|
|
|
|
Supported Devices:
|
|
Kinetis
|
|
|
|
Returns:
|
|
``True``.
|
|
|
|
Raises:
|
|
JLinkException: if the device fails to unlock.
|
|
"""
|
|
if not unlockers.unlock(self, self._device.manufacturer):
|
|
raise errors.JLinkException('Failed to unlock device.')
|
|
return True
|
|
|
|
@connection_required
|
|
def cpu_capability(self, capability):
|
|
"""Checks whether the J-Link has support for a CPU capability.
|
|
|
|
This method checks if the emulator has built-in intelligence to handle
|
|
the given CPU capability for the target CPU it is connected to.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
capability (int): the capability to check for
|
|
|
|
Returns:
|
|
``True`` if the J-Link has built-in intelligence to support the given
|
|
``capability`` for the CPU it is connected to, otherwise ``False``.
|
|
"""
|
|
res = self._dll.JLINKARM_EMU_HasCPUCap(capability)
|
|
return res == 1
|
|
|
|
@connection_required
|
|
def set_trace_source(self, source):
|
|
"""Sets the source to be used for tracing.
|
|
|
|
The ``source`` must be one of the ones provided by
|
|
``enums.JLinkTraceSource``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
source (int): the source to use.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_SelectTraceSource(source)
|
|
|
|
@connection_required
|
|
def set_etb_trace(self):
|
|
"""Sets the trace source to ETB.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
return self.set_trace_source(enums.JLinkTraceSource.ETB)
|
|
|
|
@connection_required
|
|
def set_etm_trace(self):
|
|
"""Sets the trace source to ETM.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
return self.set_trace_source(enums.JLinkTraceSource.ETM)
|
|
|
|
@connection_required
|
|
def set_reset_strategy(self, strategy):
|
|
"""Sets the reset strategy for the target.
|
|
|
|
The reset strategy defines what happens when the target is reset.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
strategy (int): the reset strategy to use
|
|
|
|
Returns:
|
|
The previous reset streategy.
|
|
"""
|
|
return self._dll.JLINKARM_SetResetType(strategy)
|
|
|
|
@connection_required
|
|
def set_reset_pin_high(self):
|
|
"""Sets the reset pin high.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_SetRESET()
|
|
|
|
@connection_required
|
|
def set_reset_pin_low(self):
|
|
"""Sets the reset pin low.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ClrRESET()
|
|
|
|
@connection_required
|
|
def set_tck_pin_high(self):
|
|
"""Sets the TCK pin to the high value (1).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: if the emulator does not support this feature.
|
|
"""
|
|
res = self._dll.JLINKARM_SetTCK()
|
|
if res < 0:
|
|
raise errors.JLinkException('Feature not supported.')
|
|
|
|
@connection_required
|
|
def set_tck_pin_low(self):
|
|
"""Sets the TCK pin to the low value (0).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: if the emulator does not support this feature.
|
|
"""
|
|
res = self._dll.JLINKARM_ClrTCK()
|
|
if res < 0:
|
|
raise errors.JLinkException('Feature not supported.')
|
|
|
|
@connection_required
|
|
def set_tdi_pin_high(self):
|
|
"""Sets the test data input to logical ``1``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_SetTDI()
|
|
|
|
@connection_required
|
|
def set_tdi_pin_low(self):
|
|
"""Clears the test data input.
|
|
|
|
TDI is set to logical ``0`` (Ground).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ClrTDI()
|
|
|
|
@connection_required
|
|
def set_tms_pin_high(self):
|
|
"""Sets the test mode select to logical ``1``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_SetTMS()
|
|
|
|
@connection_required
|
|
def set_tms_pin_low(self):
|
|
"""Clears the test mode select.
|
|
|
|
TMS is set to logical ``0`` (Ground).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ClrTMS()
|
|
|
|
@connection_required
|
|
def set_trst_pin_high(self):
|
|
"""Sets the TRST pin to high (``1``).
|
|
|
|
Deasserts the TRST pin.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_SetTRST()
|
|
|
|
@connection_required
|
|
def set_trst_pin_low(self):
|
|
"""Sets the TRST pin to low (``0``).
|
|
|
|
This asserts the TRST pin.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ClrTRST()
|
|
|
|
@connection_required
|
|
def erase(self):
|
|
"""Erases the flash contents of the device.
|
|
|
|
This erases the flash memory of the target device. If this method
|
|
fails, the device may be left in an inoperable state.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Number of bytes erased.
|
|
"""
|
|
try:
|
|
if not self.halted():
|
|
self.halt()
|
|
except errors.JLinkException:
|
|
pass
|
|
|
|
res = self._dll.JLINK_EraseChip()
|
|
if res < 0:
|
|
raise errors.JLinkEraseException(res)
|
|
return res
|
|
|
|
@connection_required
|
|
def flash(self, data, addr, on_progress=None, power_on=False, flags=0):
|
|
"""Flashes the target device.
|
|
|
|
The given ``on_progress`` callback will be called as
|
|
``on_progress(action, progress_string, percentage)`` periodically as the
|
|
data is written to flash. The action is one of ``Compare``, ``Erase``,
|
|
``Verify``, ``Flash``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
data (list): list of bytes to write to flash
|
|
addr (int): start address on flash which to write the data
|
|
on_progress (function): callback to be triggered on flash progress
|
|
power_on (boolean): whether to power the target before flashing
|
|
flags (int): reserved, do not use
|
|
|
|
Returns:
|
|
Number of bytes flashed. This number may not necessarily be equal to
|
|
``len(data)``, but that does not indicate an error.
|
|
|
|
Raises:
|
|
JLinkException: on hardware errors.
|
|
"""
|
|
if flags != 0:
|
|
raise errors.JLinkException('Flags are reserved for future use.')
|
|
if on_progress is not None:
|
|
func = enums.JLinkFunctions.FLASH_PROGRESS_PROTOTYPE(on_progress)
|
|
self._dll.JLINK_SetFlashProgProgressCallback(func)
|
|
else:
|
|
self._dll.JLINK_SetFlashProgProgressCallback(0)
|
|
if power_on:
|
|
self.power_on()
|
|
try:
|
|
if not self.halted():
|
|
self.halt()
|
|
except errors.JLinkException:
|
|
pass
|
|
|
|
res = self.flash_write(addr, data, flags=flags)
|
|
return res
|
|
|
|
@connection_required
|
|
def flash_file(self, path, addr, on_progress=None, power_on=False):
|
|
"""Flashes the target device.
|
|
|
|
The given ``on_progress`` callback will be called as
|
|
``on_progress(action, progress_string, percentage)`` periodically as the
|
|
data is written to flash. The action is one of ``Compare``, ``Erase``,
|
|
``Verify``, ``Flash``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
path (str): absolute path to the source file to flash
|
|
addr (int): start address on flash which to write the data
|
|
on_progress (function): callback to be triggered on flash progress
|
|
power_on (boolean): whether to power the target before flashing
|
|
|
|
Returns:
|
|
Integer value greater than or equal to zero. Has no significance.
|
|
|
|
Raises:
|
|
JLinkException: on hardware errors.
|
|
"""
|
|
if on_progress is not None:
|
|
func = enums.JLinkFunctions.FLASH_PROGRESS_PROTOTYPE(on_progress)
|
|
self._dll.JLINK_SetFlashProgProgressCallback(func)
|
|
else:
|
|
self._dll.JLINK_SetFlashProgProgressCallback(0)
|
|
if power_on:
|
|
self.power_on()
|
|
try:
|
|
if not self.halted():
|
|
self.halt()
|
|
except errors.JLinkException:
|
|
pass
|
|
|
|
bytes_flashed = self._dll.JLINK_DownloadFile(path.encode(), addr)
|
|
if bytes_flashed < 0:
|
|
raise errors.JLinkFlashException(bytes_flashed)
|
|
return bytes_flashed
|
|
|
|
@connection_required
|
|
def reset(self, ms=0, halt=True):
|
|
"""Resets the target.
|
|
|
|
This method resets the target, and by default toggles the RESET and
|
|
TRST pins.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
ms (int): Amount of milliseconds to delay after reset (default: 0)
|
|
halt (bool): if the CPU should halt after reset (default: True)
|
|
|
|
Returns:
|
|
Number of bytes read.
|
|
"""
|
|
self._dll.JLINKARM_SetResetDelay(ms)
|
|
res = self._dll.JLINKARM_Reset()
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
else:
|
|
if not halt:
|
|
self._dll.JLINKARM_Go()
|
|
return res
|
|
|
|
@connection_required
|
|
def reset_tap(self):
|
|
"""Resets the TAP controller via TRST.
|
|
|
|
Note:
|
|
This must be called at least once after power up if the TAP
|
|
controller is to be used.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ResetTRST()
|
|
|
|
@connection_required
|
|
def restart(self, num_instructions=0, skip_breakpoints=False):
|
|
"""Restarts the CPU core and simulates/emulates instructions.
|
|
|
|
Note:
|
|
This is a no-op if the CPU isn't halted.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
num_instructions (int): number of instructions to simulate, defaults
|
|
to zero
|
|
skip_breakpoints (bool): skip current breakpoint (default: ``False``)
|
|
|
|
Returns:
|
|
``True`` if device was restarted, otherwise ``False``.
|
|
|
|
Raises:
|
|
ValueError: if instruction count is not a natural number.
|
|
"""
|
|
if not util.is_natural(num_instructions):
|
|
raise ValueError('Invalid instruction count: %s.' % num_instructions)
|
|
if not self.halted():
|
|
return False
|
|
flags = 0
|
|
if skip_breakpoints:
|
|
flags = flags | enums.JLinkFlags.GO_OVERSTEP_BP
|
|
self._dll.JLINKARM_GoEx(num_instructions, flags)
|
|
return True
|
|
|
|
@connection_required
|
|
@decorators.async_decorator
|
|
def halt(self):
|
|
"""Halts the CPU Core.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if halted, ``False`` otherwise.
|
|
"""
|
|
res = int(self._dll.JLINKARM_Halt())
|
|
if res == 0:
|
|
time.sleep(1)
|
|
return True
|
|
return False
|
|
|
|
@connection_required
|
|
def halted(self):
|
|
"""Returns whether the CPU core was halted.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if the CPU core is halted, otherwise ``False``.
|
|
|
|
Raises:
|
|
JLinkException: on device errors.
|
|
"""
|
|
result = int(self._dll.JLINKARM_IsHalted())
|
|
if result < 0:
|
|
raise errors.JLinkException(result)
|
|
return result > 0
|
|
|
|
@connection_required
|
|
def core_id(self):
|
|
"""Returns the identifier of the target ARM core.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Integer identifier of ARM core.
|
|
"""
|
|
return self._dll.JLINKARM_GetId()
|
|
|
|
@connection_required
|
|
def core_cpu(self):
|
|
"""Returns the identifier of the core CPU.
|
|
|
|
Note:
|
|
This is distinct from the value returned from ``core_id()`` which is
|
|
the ARM specific identifier.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The identifier of the CPU core.
|
|
"""
|
|
return self._dll.JLINKARM_CORE_GetFound()
|
|
|
|
@connection_required
|
|
def core_name(self):
|
|
"""Returns the name of the target ARM core.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The target core's name.
|
|
"""
|
|
buf_size = self.MAX_BUF_SIZE
|
|
buf = (ctypes.c_char * buf_size)()
|
|
self._dll.JLINKARM_Core2CoreName(self.core_cpu(), buf, buf_size)
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@connection_required
|
|
def ir_len(self):
|
|
"""Counts and returns the total length of instruction registers of all
|
|
the devices in the JTAG scan chain.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Total instruction register length.
|
|
"""
|
|
return self._dll.JLINKARM_GetIRLen()
|
|
|
|
@connection_required
|
|
def scan_len(self):
|
|
"""Retrieves and returns the length of the scan chain select register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Length of the scan chain select register.
|
|
"""
|
|
return self._dll.JLINKARM_GetScanLen()
|
|
|
|
@connection_required
|
|
def scan_chain_len(self, scan_chain):
|
|
"""Retrieves and returns the number of bits in the scan chain.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
scan_chain (int): scan chain to be measured
|
|
|
|
Returns:
|
|
Number of bits in the specified scan chain.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
res = self._dll.JLINKARM_MeasureSCLen(scan_chain)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return res
|
|
|
|
@connection_required
|
|
def device_family(self):
|
|
"""Returns the device family of the target CPU.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Integer identifier of the device family.
|
|
"""
|
|
return self._dll.JLINKARM_GetDeviceFamily()
|
|
|
|
@connection_required
|
|
def register_list(self):
|
|
"""Returns a list of the indices for the CPU registers.
|
|
|
|
The returned indices can be used to read the register content or grab
|
|
the register name.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
List of registers.
|
|
"""
|
|
num_items = self.MAX_NUM_CPU_REGISTERS
|
|
buf = (ctypes.c_uint32 * num_items)()
|
|
num_regs = self._dll.JLINKARM_GetRegisterList(buf, num_items)
|
|
return buf[:num_regs]
|
|
|
|
@connection_required
|
|
def register_name(self, register_index):
|
|
"""Retrives and returns the name of an ARM CPU register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register_index (int): index of the register whose name to retrieve
|
|
|
|
Returns:
|
|
Name of the register.
|
|
"""
|
|
result = self._dll.JLINKARM_GetRegisterName(register_index)
|
|
return ctypes.cast(result, ctypes.c_char_p).value.decode()
|
|
|
|
@connection_required
|
|
def cpu_speed(self, silent=False):
|
|
"""Retrieves the CPU speed of the target.
|
|
|
|
If the target does not support CPU frequency detection, this function
|
|
will return ``0``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
silent (bool): ``True`` if the CPU detection should not report errors
|
|
to the error handler on failure.
|
|
|
|
Returns:
|
|
The measured CPU frequency on success, otherwise ``0`` if the core does
|
|
not support CPU frequency detection.
|
|
|
|
Raises:
|
|
JLinkException: on hardware error.
|
|
"""
|
|
res = self._dll.JLINKARM_MeasureCPUSpeedEx(-1, 1, int(silent))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return res
|
|
|
|
@connection_required
|
|
def cpu_halt_reasons(self):
|
|
"""Retrives the reasons that the CPU was halted.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
A list of ``JLInkMOEInfo`` instances specifying the reasons for which
|
|
the CPU was halted. This list may be empty in the case that the CPU
|
|
is not halted.
|
|
|
|
Raises:
|
|
JLinkException: on hardware error.
|
|
"""
|
|
buf_size = self.MAX_NUM_MOES
|
|
buf = (structs.JLinkMOEInfo * buf_size)()
|
|
num_reasons = self._dll.JLINKARM_GetMOEs(buf, buf_size)
|
|
if num_reasons < 0:
|
|
raise errors.JLinkException(num_reasons)
|
|
return list(buf)[:num_reasons]
|
|
|
|
@connection_required
|
|
def jtag_create_clock(self):
|
|
"""Creates a JTAG clock on TCK.
|
|
|
|
Note:
|
|
This function only needs to be called once.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The state of the TDO pin: either ``0`` or ``1``.
|
|
"""
|
|
return self._dll.JLINKARM_Clock()
|
|
|
|
@connection_required
|
|
def jtag_send(self, tms, tdi, num_bits):
|
|
"""Sends data via JTAG.
|
|
|
|
Sends data via JTAG on the rising clock edge, TCK. At on each rising
|
|
clock edge, on bit is transferred in from TDI and out to TDO. The
|
|
clock uses the TMS to step through the standard JTAG state machine.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
tms (int): used to determine the state transitions for the Test
|
|
Access Port (TAP) controller from its current state
|
|
tdi (int): input data to be transferred in from TDI to TDO
|
|
num_bits (int): a number in the range ``[1, 32]`` inclusively
|
|
specifying the number of meaningful bits in the ``tms`` and
|
|
``tdi`` parameters for the purpose of extracting state and data
|
|
information
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
ValueError: if ``num_bits < 1`` or ``num_bits > 32``.
|
|
|
|
See Also:
|
|
`JTAG Technical Overview <https://www.xjtag.com/about-jtag/jtag-a-technical-overview>`_.
|
|
"""
|
|
if util.is_natural(num_bits) and num_bits <= 0 or num_bits > 32:
|
|
raise ValueError('Number of bits must be >= 1 and <= 32.')
|
|
self._dll.JLINKARM_StoreBits(tms, tdi, num_bits)
|
|
|
|
@connection_required
|
|
def jtag_flush(self):
|
|
"""Flushes the internal JTAG buffer.
|
|
|
|
Note:
|
|
The buffer is automatically flushed when a response from the target
|
|
is expected, or the buffer is full. This can be used after a
|
|
``memory_write()`` in order to flush the buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_WriteBits()
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_read8(self, offset):
|
|
"""Gets a unit of ``8`` bits from the input buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
offset (int): the offset (in bits) from which to start reading
|
|
|
|
Returns:
|
|
The integer read from the input buffer.
|
|
"""
|
|
value = self._dll.JLINK_SWD_GetU8(offset)
|
|
return ctypes.c_uint8(value).value
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_read16(self, offset):
|
|
"""Gets a unit of ``16`` bits from the input buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
offset (int): the offset (in bits) from which to start reading
|
|
|
|
Returns:
|
|
The integer read from the input buffer.
|
|
"""
|
|
value = self._dll.JLINK_SWD_GetU16(offset)
|
|
return ctypes.c_uint16(value).value
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_read32(self, offset):
|
|
"""Gets a unit of ``32`` bits from the input buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
offset (int): the offset (in bits) from which to start reading
|
|
|
|
Returns:
|
|
The integer read from the input buffer.
|
|
"""
|
|
value = self._dll.JLINK_SWD_GetU32(offset)
|
|
return ctypes.c_uint32(value).value
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_write(self, output, value, nbits):
|
|
"""Writes bytes over SWD (Serial Wire Debug).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
output (int): the output buffer offset to write to
|
|
value (int): the value to write to the output buffer
|
|
nbits (int): the number of bits needed to represent the ``output`` and
|
|
``value``
|
|
|
|
Returns:
|
|
The bit position of the response in the input buffer.
|
|
"""
|
|
pDir = binpacker.pack(output, nbits)
|
|
pIn = binpacker.pack(value, nbits)
|
|
bitpos = self._dll.JLINK_SWD_StoreRaw(pDir, pIn, nbits)
|
|
if bitpos < 0:
|
|
raise errors.JLinkException(bitpos)
|
|
return bitpos
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_write8(self, output, value):
|
|
"""Writes one byte over SWD (Serial Wire Debug).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
output (int): the output buffer offset to write to
|
|
value (int): the value to write to the output buffer
|
|
|
|
Returns:
|
|
The bit position of the response in the input buffer.
|
|
"""
|
|
return self.swd_write(output, value, 8)
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_write16(self, output, value):
|
|
"""Writes two bytes over SWD (Serial Wire Debug).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
output (int): the output buffer offset to write to
|
|
value (int): the value to write to the output buffer
|
|
|
|
Returns:
|
|
The bit position of the response in the input buffer.
|
|
"""
|
|
return self.swd_write(output, value, 16)
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_write32(self, output, value):
|
|
"""Writes four bytes over SWD (Serial Wire Debug).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
output (int): the output buffer offset to write to
|
|
value (int): the value to write to the output buffer
|
|
|
|
Returns:
|
|
The bit position of the response in the input buffer.
|
|
"""
|
|
return self.swd_write(output, value, 32)
|
|
|
|
@interface_required(enums.JLinkInterfaces.SWD)
|
|
@connection_required
|
|
def swd_sync(self, pad=False):
|
|
"""Causes a flush to write all data remaining in output buffers to SWD
|
|
device.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
pad (bool): ``True`` if should pad the data to full byte size
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
if pad:
|
|
self._dll.JLINK_SWD_SyncBytes()
|
|
else:
|
|
self._dll.JLINK_SWD_SyncBits()
|
|
|
|
@connection_required
|
|
def flash_write(self, addr, data, nbits=None, flags=0):
|
|
"""Writes data to the flash region of a device.
|
|
|
|
The given number of bits, if provided, must be either ``8``, ``16``, or
|
|
``32``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): starting flash address to write to
|
|
data (list): list of data units to write
|
|
nbits (int): number of bits to use for each unit
|
|
|
|
Returns:
|
|
Number of bytes written to flash.
|
|
"""
|
|
self._dll.JLINKARM_BeginDownload(flags)
|
|
self.memory_write(addr, data, nbits=nbits)
|
|
bytes_flashed = self._dll.JLINKARM_EndDownload()
|
|
if bytes_flashed < 0:
|
|
raise errors.JLinkFlashException(bytes_flashed)
|
|
return bytes_flashed
|
|
|
|
@connection_required
|
|
def flash_write8(self, addr, data):
|
|
"""Writes bytes to the flash region of a device.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): starting flash address to write to
|
|
data (list): list of bytes to write
|
|
|
|
Returns:
|
|
Number of bytes written to flash.
|
|
"""
|
|
return self.flash_write(addr, data, 8)
|
|
|
|
@connection_required
|
|
def flash_write16(self, addr, data):
|
|
"""Writes halfwords to the flash region of a device.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): starting flash address to write to
|
|
data (list): list of halfwords to write
|
|
|
|
Returns:
|
|
Number of bytes written to flash.
|
|
"""
|
|
return self.flash_write(addr, data, 16)
|
|
|
|
@connection_required
|
|
def flash_write32(self, addr, data):
|
|
"""Writes words to the flash region of a device.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): starting flash address to write to
|
|
data (list): list of words to write
|
|
|
|
Returns:
|
|
Number of bytes written to flash.
|
|
"""
|
|
return self.flash_write(addr, data, 32)
|
|
|
|
@connection_required
|
|
def code_memory_read(self, addr, num_bytes):
|
|
"""Reads bytes from code memory.
|
|
|
|
Note:
|
|
This is similar to calling ``memory_read`` or ``memory_read8``,
|
|
except that this uses a cache and reads ahead. This should be used
|
|
in instances where you want to read a small amount of bytes at a
|
|
time, and expect to always read ahead.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): starting address from which to read
|
|
num_bytes (int): number of bytes to read
|
|
|
|
Returns:
|
|
A list of bytes read from the target.
|
|
|
|
Raises:
|
|
JLinkException: if memory could not be read.
|
|
"""
|
|
buf_size = num_bytes
|
|
buf = (ctypes.c_uint8 * buf_size)()
|
|
res = self._dll.JLINKARM_ReadCodeMem(addr, buf_size, buf)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return list(buf)[:res]
|
|
|
|
@connection_required
|
|
def num_memory_zones(self):
|
|
"""Returns the number of memory zones supported by the target.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
An integer count of the number of memory zones supported by the
|
|
target.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
count = self._dll.JLINK_GetMemZones(0, 0)
|
|
if count < 0:
|
|
raise errors.JLinkException(count)
|
|
return count
|
|
|
|
@connection_required
|
|
def memory_zones(self):
|
|
"""Gets all memory zones supported by the current target.
|
|
|
|
Some targets support multiple memory zones. This function provides the
|
|
ability to get a list of all the memory zones to facilate using the
|
|
memory zone routing functions.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
A list of all the memory zones as ``JLinkMemoryZone`` structures.
|
|
|
|
Raises:
|
|
JLinkException: on hardware errors.
|
|
"""
|
|
count = self.num_memory_zones()
|
|
if count == 0:
|
|
return list()
|
|
buf = (structs.JLinkMemoryZone * count)()
|
|
res = self._dll.JLINK_GetMemZones(buf, count)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return list(buf)
|
|
|
|
@connection_required
|
|
def memory_read(self, addr, num_units, zone=None, nbits=None):
|
|
"""Reads memory from a target system or specific memory zone.
|
|
|
|
The optional ``zone`` specifies a memory zone to access to read from,
|
|
e.g. ``IDATA``, ``DDATA``, or ``CODE``.
|
|
|
|
The given number of bits, if provided, must be either ``8``, ``16``, or
|
|
``32``. If not provided, always reads ``num_units`` bytes.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to read from
|
|
num_units (int): number of units to read
|
|
zone (str): optional memory zone name to access
|
|
nbits (int): number of bits to use for each unit
|
|
|
|
Returns:
|
|
List of units read from the target system.
|
|
|
|
Raises:
|
|
JLinkException: if memory could not be read.
|
|
ValueError: if ``nbits`` is not ``None``, and not in ``8``, ``16``,
|
|
or ``32``.
|
|
"""
|
|
buf_size = num_units
|
|
buf = None
|
|
access = 0
|
|
if nbits is None:
|
|
buf = (ctypes.c_uint8 * buf_size)()
|
|
access = 0
|
|
else:
|
|
if nbits == 8:
|
|
buf = (ctypes.c_uint8 * buf_size)()
|
|
access = 1
|
|
else:
|
|
if nbits == 16:
|
|
buf = (ctypes.c_uint16 * buf_size)()
|
|
access = 2
|
|
buf_size = buf_size * access
|
|
else:
|
|
if nbits == 32:
|
|
buf = (ctypes.c_uint32 * buf_size)()
|
|
access = 4
|
|
buf_size = buf_size * access
|
|
else:
|
|
raise ValueError('Given bit size is invalid: %s' % nbits)
|
|
args = [
|
|
addr, buf_size, buf, access]
|
|
method = self._dll.JLINKARM_ReadMemEx
|
|
if zone is not None:
|
|
method = self._dll.JLINKARM_ReadMemZonedEx
|
|
args.append(zone.encode())
|
|
units_read = method(*args)
|
|
if units_read < 0:
|
|
raise errors.JLinkReadException(units_read)
|
|
return buf[:units_read]
|
|
|
|
@connection_required
|
|
def memory_read8(self, addr, num_bytes, zone=None):
|
|
"""Reads memory from the target system in units of bytes.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to read from
|
|
num_bytes (int): number of bytes to read
|
|
zone (str): memory zone to read from
|
|
|
|
Returns:
|
|
List of bytes read from the target system.
|
|
|
|
Raises:
|
|
JLinkException: if memory could not be read.
|
|
"""
|
|
return self.memory_read(addr, num_bytes, zone=zone, nbits=8)
|
|
|
|
@connection_required
|
|
def memory_read16(self, addr, num_halfwords, zone=None):
|
|
"""Reads memory from the target system in units of 16-bits.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to read from
|
|
num_halfwords (int): number of half words to read
|
|
zone (str): memory zone to read from
|
|
|
|
Returns:
|
|
List of halfwords read from the target system.
|
|
|
|
Raises:
|
|
JLinkException: if memory could not be read
|
|
"""
|
|
return self.memory_read(addr, num_halfwords, zone=zone, nbits=16)
|
|
|
|
@connection_required
|
|
def memory_read32(self, addr, num_words, zone=None):
|
|
"""Reads memory from the target system in units of 32-bits.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to read from
|
|
num_words (int): number of words to read
|
|
zone (str): memory zone to read from
|
|
|
|
Returns:
|
|
List of words read from the target system.
|
|
|
|
Raises:
|
|
JLinkException: if memory could not be read
|
|
"""
|
|
return self.memory_read(addr, num_words, zone=zone, nbits=32)
|
|
|
|
@connection_required
|
|
def memory_read64(self, addr, num_long_words):
|
|
"""Reads memory from the target system in units of 64-bits.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to read from
|
|
num_long_words (int): number of long words to read
|
|
|
|
Returns:
|
|
List of long words read from the target system.
|
|
|
|
Raises:
|
|
JLinkException: if memory could not be read
|
|
"""
|
|
buf_size = num_long_words
|
|
buf = (ctypes.c_ulonglong * buf_size)()
|
|
units_read = self._dll.JLINKARM_ReadMemU64(addr, buf_size, buf, 0)
|
|
if units_read < 0:
|
|
raise errors.JLinkException(units_read)
|
|
return buf[:units_read]
|
|
|
|
@connection_required
|
|
def memory_write(self, addr, data, zone=None, nbits=None):
|
|
"""Writes memory to a target system or specific memory zone.
|
|
|
|
The optional ``zone`` specifies a memory zone to access to write to,
|
|
e.g. ``IDATA``, ``DDATA``, or ``CODE``.
|
|
|
|
The given number of bits, if provided, must be either ``8``, ``16``, or
|
|
``32``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to write to
|
|
data (list): list of data units to write
|
|
zone (str): optional memory zone name to access
|
|
nbits (int): number of bits to use for each unit
|
|
|
|
Returns:
|
|
Number of units written.
|
|
|
|
Raises:
|
|
JLinkException: on write hardware failure.
|
|
ValueError: if ``nbits`` is not ``None``, and not in ``8``, ``16`` or
|
|
``32``.
|
|
"""
|
|
buf_size = len(data)
|
|
buf = None
|
|
access = 0
|
|
if nbits is None:
|
|
packed_data = map(lambda d: reversed(binpacker.pack(d))
|
|
, data)
|
|
packed_data = list((itertools.chain)(*packed_data))
|
|
buf_size = len(packed_data)
|
|
buf = (ctypes.c_uint8 * buf_size)(*packed_data)
|
|
access = 0
|
|
else:
|
|
if nbits == 8:
|
|
buf = (ctypes.c_uint8 * buf_size)(*data)
|
|
access = 1
|
|
else:
|
|
if nbits == 16:
|
|
buf = (ctypes.c_uint16 * buf_size)(*data)
|
|
access = 2
|
|
buf_size = buf_size * access
|
|
else:
|
|
if nbits == 32:
|
|
buf = (ctypes.c_uint32 * buf_size)(*data)
|
|
access = 4
|
|
buf_size = buf_size * access
|
|
else:
|
|
raise ValueError('Given bit size is invalid: %s' % nbits)
|
|
args = [
|
|
addr, buf_size, buf, access]
|
|
method = self._dll.JLINKARM_WriteMemEx
|
|
if zone is not None:
|
|
method = self._dll.JLINKARM_WriteMemZonedEx
|
|
args.append(zone.encode())
|
|
units_written = method(*args)
|
|
if units_written < 0:
|
|
raise errors.JLinkWriteException(units_written)
|
|
return units_written
|
|
|
|
@connection_required
|
|
def memory_write8(self, addr, data, zone=None):
|
|
"""Writes bytes to memory of a target system.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to write to
|
|
data (list): list of bytes to write
|
|
zone (str): optional memory zone to access
|
|
|
|
Returns:
|
|
Number of bytes written to target.
|
|
|
|
Raises:
|
|
JLinkException: on memory access error.
|
|
"""
|
|
return self.memory_write(addr, data, zone, 8)
|
|
|
|
@connection_required
|
|
def memory_write16(self, addr, data, zone=None):
|
|
"""Writes half-words to memory of a target system.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to write to
|
|
data (list): list of half-words to write
|
|
zone (str): optional memory zone to access
|
|
|
|
Returns:
|
|
Number of half-words written to target.
|
|
|
|
Raises:
|
|
JLinkException: on memory access error.
|
|
"""
|
|
return self.memory_write(addr, data, zone, 16)
|
|
|
|
@connection_required
|
|
def memory_write32(self, addr, data, zone=None):
|
|
"""Writes words to memory of a target system.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to write to
|
|
data (list): list of words to write
|
|
zone (str): optional memory zone to access
|
|
|
|
Returns:
|
|
Number of words written to target.
|
|
|
|
Raises:
|
|
JLinkException: on memory access error.
|
|
"""
|
|
return self.memory_write(addr, data, zone, 32)
|
|
|
|
@connection_required
|
|
def memory_write64(self, addr, data, zone=None):
|
|
"""Writes long words to memory of a target system.
|
|
|
|
Note:
|
|
This is little-endian.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): start address to write to
|
|
data (list): list of long words to write
|
|
zone (str): optional memory zone to access
|
|
|
|
Returns:
|
|
Number of long words written to target.
|
|
|
|
Raises:
|
|
JLinkException: on memory access error.
|
|
"""
|
|
words = []
|
|
bitmask = 4294967295
|
|
for long_word in data:
|
|
words.append(long_word & bitmask)
|
|
words.append(long_word >> 32 & bitmask)
|
|
|
|
return self.memory_write32(addr, words, zone=zone)
|
|
|
|
@connection_required
|
|
def register_read(self, register_index):
|
|
"""Reads the value from the given register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register_index (int/str): the register to read
|
|
|
|
Returns:
|
|
The value stored in the given register.
|
|
"""
|
|
if isinstance(register_index, six.string_types):
|
|
register_index = self._get_register_index_from_name(register_index)
|
|
return self._dll.JLINKARM_ReadReg(register_index)
|
|
|
|
@connection_required
|
|
def register_read_multiple(self, register_indices):
|
|
"""Retrieves the values from the registers specified.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register_indices (list): list of registers to read
|
|
|
|
Returns:
|
|
A list of values corresponding one-to-one for each of the given
|
|
register indices. The returned list of values are the values in
|
|
order of which the indices were specified.
|
|
|
|
Raises:
|
|
JLinkException: if a given register is invalid or an error occurs.
|
|
"""
|
|
register_indices = register_indices[:]
|
|
num_regs = len(register_indices)
|
|
for idx, indice in enumerate(register_indices):
|
|
if isinstance(indice, six.string_types):
|
|
register_indices[idx] = self._get_register_index_from_name(indice)
|
|
|
|
buf = (ctypes.c_uint32 * num_regs)(*register_indices)
|
|
data = ctypes.c_uint32 * num_regs(0)
|
|
statuses = ctypes.c_uint8 * num_regs(0)
|
|
res = self._dll.JLINKARM_ReadRegs(buf, data, statuses, num_regs)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return list(data)
|
|
|
|
@connection_required
|
|
def register_write(self, reg_index, value):
|
|
"""Writes into an ARM register.
|
|
|
|
Note:
|
|
The data is not immediately written, but is cached before being
|
|
transferred to the CPU on CPU start.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
reg_index (int/str): the ARM register to write to
|
|
value (int): the value to write to the register
|
|
|
|
Returns:
|
|
The value written to the ARM register.
|
|
|
|
Raises:
|
|
JLinkException: on write error.
|
|
"""
|
|
if isinstance(reg_index, six.string_types):
|
|
reg_index = self._get_register_index_from_name(reg_index)
|
|
res = self._dll.JLINKARM_WriteReg(reg_index, value)
|
|
if res != 0:
|
|
raise errors.JLinkException('Error writing to register %d' % reg_index)
|
|
return value
|
|
|
|
@connection_required
|
|
def register_write_multiple(self, register_indices, values):
|
|
"""Writes to multiple CPU registers.
|
|
|
|
Writes the values to the given registers in order. There must be a
|
|
one-to-one correspondence between the values and the registers
|
|
specified.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register_indices (list): list of registers to write to
|
|
values (list): list of values to write to the registers
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
ValueError: if ``len(register_indices) != len(values)``
|
|
JLinkException: if a register could not be written to or on error
|
|
"""
|
|
register_indices = register_indices[:]
|
|
if len(register_indices) != len(values):
|
|
raise ValueError('Must be an equal number of registers and values')
|
|
num_regs = len(register_indices)
|
|
for idx, indice in enumerate(register_indices):
|
|
if isinstance(indice, six.string_types):
|
|
register_indices[idx] = self._get_register_index_from_name(indice)
|
|
|
|
buf = (ctypes.c_uint32 * num_regs)(*register_indices)
|
|
data = (ctypes.c_uint32 * num_regs)(*values)
|
|
statuses = ctypes.c_uint8 * num_regs(0)
|
|
res = self._dll.JLINKARM_WriteRegs(buf, data, statuses, num_regs)
|
|
if res != 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def ice_register_read(self, register_index):
|
|
"""Reads a value from an ARM ICE register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register_index (int): the register to read
|
|
|
|
Returns:
|
|
The value read from the register.
|
|
"""
|
|
return self._dll.JLINKARM_ReadICEReg(register_index)
|
|
|
|
@connection_required
|
|
def ice_register_write(self, register_index, value, delay=False):
|
|
"""Writes a value to an ARM ICE register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
register_index (int): the ICE register to write to
|
|
value (int): the value to write to the ICE register
|
|
delay (bool): boolean specifying if the write should be delayed
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_WriteICEReg(register_index, int(value), int(delay))
|
|
|
|
@connection_required
|
|
def etm_supported(self):
|
|
"""Returns if the CPU core supports ETM.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``True`` if the CPU has the ETM unit, otherwise ``False``.
|
|
"""
|
|
res = self._dll.JLINKARM_ETM_IsPresent()
|
|
if res == 1:
|
|
return True
|
|
info = ctypes.c_uint32(0)
|
|
index = enums.JLinkROMTable.ETM
|
|
res = self._dll.JLINKARM_GetDebugInfo(index, ctypes.byref(info))
|
|
if res == 1:
|
|
return False
|
|
return True
|
|
|
|
@connection_required
|
|
def etm_register_read(self, register_index):
|
|
"""Reads a value from an ETM register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
register_index (int): the register to read.
|
|
|
|
Returns:
|
|
The value read from the ETM register.
|
|
"""
|
|
return self._dll.JLINKARM_ETM_ReadReg(register_index)
|
|
|
|
@connection_required
|
|
def etm_register_write(self, register_index, value, delay=False):
|
|
"""Writes a value to an ETM register.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
register_index (int): the register to write to.
|
|
value (int): the value to write to the register.
|
|
delay (bool): boolean specifying if the write should be buffered.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ETM_WriteReg(int(register_index), int(value), int(delay))
|
|
|
|
@connection_required
|
|
def coresight_read(self, reg, ap=True):
|
|
"""Reads an Ap/DP register on a CoreSight DAP.
|
|
|
|
Wait responses and special handling are both handled by this method.
|
|
|
|
Note:
|
|
``coresight_configure()`` must be called prior to calling this method.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
reg (int): index of DP/AP register to read
|
|
ap (bool): ``True`` if reading from an Access Port register,
|
|
otherwise ``False`` for Debug Port
|
|
|
|
Returns:
|
|
Data read from register.
|
|
|
|
Raises:
|
|
JLinkException: on hardware error
|
|
"""
|
|
data = ctypes.c_uint32()
|
|
ap = 1 if ap else 0
|
|
res = self._dll.JLINKARM_CORESIGHT_ReadAPDPReg(reg, ap, ctypes.byref(data))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return data.value
|
|
|
|
@connection_required
|
|
def coresight_write(self, reg, data, ap=True):
|
|
"""Writes an Ap/DP register on a CoreSight DAP.
|
|
|
|
Note:
|
|
``coresight_configure()`` must be called prior to calling this method.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
reg (int): index of DP/AP register to write
|
|
data (int): data to write
|
|
ap (bool): ``True`` if writing to an Access Port register, otherwise
|
|
``False`` for Debug Port
|
|
|
|
Returns:
|
|
Number of repetitions needed until write request accepted.
|
|
|
|
Raises:
|
|
JLinkException: on hardware error
|
|
"""
|
|
ap = 1 if ap else 0
|
|
res = self._dll.JLINKARM_CORESIGHT_WriteAPDPReg(reg, ap, data)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return res
|
|
|
|
@connection_required
|
|
def enable_reset_pulls_reset(self):
|
|
"""Enables RESET pin toggling on the JTAG bus on resets.
|
|
|
|
When ``.reset()`` is called, it will also toggle the RESET pin on the
|
|
JTAG bus.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ResetPullsRESET(1)
|
|
|
|
@connection_required
|
|
def disable_reset_pulls_reset(self):
|
|
"""Disables RESET pin toggling on the JTAG bus on resets.
|
|
|
|
When ``.reset()`` is called, it will not toggle the RESET pin on the
|
|
JTAG bus.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ResetPullsRESET(0)
|
|
|
|
@connection_required
|
|
def enable_reset_pulls_trst(self):
|
|
"""Enables TRST pin toggling on the JTAG bus on resets.
|
|
|
|
When ``.reset()`` is called, it will also toggle the TRST pin on the
|
|
JTAG bus.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ResetPullsTRST(1)
|
|
|
|
@connection_required
|
|
def disable_reset_pulls_trst(self):
|
|
"""Disables TRST pin toggling on the JTAG bus on resets.
|
|
|
|
When ``.reset()`` is called, it will not toggle the TRST pin on the
|
|
JTAG bus.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_ResetPullsTRST(0)
|
|
|
|
@connection_required
|
|
def enable_reset_inits_registers(self):
|
|
"""Enables CPU register initialization on resets.
|
|
|
|
When ``.reset()`` is called, it will initialize the CPU registers.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if was previously enabled, otherwise ``False``.
|
|
"""
|
|
return bool(self._dll.JLINKARM_SetInitRegsOnReset(1))
|
|
|
|
@connection_required
|
|
def disable_reset_inits_registers(self):
|
|
"""Disables CPU register initialization on resets.
|
|
|
|
When ``.reset()`` is called, the CPU registers will be read and not
|
|
initialized.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if was previously enabled, otherwise ``False``.
|
|
"""
|
|
return bool(self._dll.JLINKARM_SetInitRegsOnReset(0))
|
|
|
|
@connection_required
|
|
def set_little_endian(self):
|
|
"""Sets the target hardware to little endian.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if target was big endian before call, otherwise ``False``.
|
|
"""
|
|
res = self._dll.JLINKARM_SetEndian(0)
|
|
return res == 1
|
|
|
|
@connection_required
|
|
def set_big_endian(self):
|
|
"""Sets the target hardware to big endian.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if target was little endian before call, otherwise ``False``.
|
|
"""
|
|
res = self._dll.JLINKARM_SetEndian(1)
|
|
return res == 0
|
|
|
|
@connection_required
|
|
def set_vector_catch(self, flags):
|
|
"""Sets vector catch bits of the processor.
|
|
|
|
The CPU will jump to a vector if the given vector catch is active, and
|
|
will enter a debug state. This has the effect of halting the CPU as
|
|
well, meaning the CPU must be explicitly restarted.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
res = self._dll.JLINKARM_WriteVectorCatch(flags)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def step(self, thumb=False):
|
|
"""Executes a single step.
|
|
|
|
Steps even if there is a breakpoint.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
thumb (bool): boolean indicating if to step in thumb mode
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
method = self._dll.JLINKARM_Step
|
|
if thumb:
|
|
method = self._dll.JLINKARM_StepComposite
|
|
res = method()
|
|
if res != 0:
|
|
raise errors.JLinkException('Failed to step over instruction.')
|
|
|
|
@connection_required
|
|
def enable_soft_breakpoints(self):
|
|
"""Enables software breakpoints.
|
|
|
|
Note:
|
|
This should be called before calling ``software_breakpoint_set()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_EnableSoftBPs(1)
|
|
|
|
@connection_required
|
|
def disable_soft_breakpoints(self):
|
|
"""Disables software breakpoints.
|
|
|
|
Note:
|
|
After this function is called, ``software_breakpoint_set()`` cannot
|
|
be used without first calling ``enable_soft_breakpoints()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
self._dll.JLINKARM_EnableSoftBPs(0)
|
|
|
|
@connection_required
|
|
def num_active_breakpoints(self):
|
|
"""Returns the number of currently active breakpoints.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The number of breakpoints that are currently set.
|
|
"""
|
|
return self._dll.JLINKARM_GetNumBPs()
|
|
|
|
@connection_required
|
|
def num_available_breakpoints(self, arm=False, thumb=False, ram=False, flash=False, hw=False):
|
|
"""Returns the number of available breakpoints of the specified type.
|
|
|
|
If ``arm`` is set, gets the number of available ARM breakpoint units.
|
|
If ``thumb`` is set, gets the number of available THUMB breakpoint
|
|
units. If ``ram`` is set, gets the number of available software RAM
|
|
breakpoint units. If ``flash`` is set, gets the number of available
|
|
software flash breakpoint units. If ``hw`` is set, gets the number of
|
|
available hardware breakpoint units.
|
|
|
|
If a combination of the flags is given, then
|
|
``num_available_breakpoints()`` returns the number of breakpoints
|
|
specified by the given flags. If no flags are specified, then the
|
|
count of available breakpoint units is returned.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
arm (bool): Boolean indicating to get number of ARM breakpoints.
|
|
thumb (bool): Boolean indicating to get number of THUMB breakpoints.
|
|
ram (bool): Boolean indicating to get number of SW RAM breakpoints.
|
|
flash (bool): Boolean indicating to get number of Flash breakpoints.
|
|
hw (bool): Boolean indicating to get number of Hardware breakpoints.
|
|
|
|
Returns:
|
|
The number of available breakpoint units of the specified type.
|
|
"""
|
|
flags = [
|
|
enums.JLinkBreakpoint.ARM,
|
|
enums.JLinkBreakpoint.THUMB,
|
|
enums.JLinkBreakpoint.SW_RAM,
|
|
enums.JLinkBreakpoint.SW_FLASH,
|
|
enums.JLinkBreakpoint.HW]
|
|
set_flags = [
|
|
arm,
|
|
thumb,
|
|
ram,
|
|
flash,
|
|
hw]
|
|
if not any(set_flags):
|
|
flags = enums.JLinkBreakpoint.ANY
|
|
else:
|
|
flags = list((f for i, f in enumerate(flags) if set_flags[i]))
|
|
flags = functools.reduce(operator.__or__, flags, 0)
|
|
return self._dll.JLINKARM_GetNumBPUnits(flags)
|
|
|
|
@connection_required
|
|
def breakpoint_info(self, handle=0, index=-1):
|
|
"""Returns the information about a set breakpoint.
|
|
|
|
Note:
|
|
Either ``handle`` or ``index`` can be specified. If the ``index``
|
|
is not provided, the ``handle`` must be set, and vice-versa. If
|
|
both ``index`` and ``handle`` are provided, the ``index`` overrides
|
|
the provided ``handle``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
handle (int): option handle of a valid breakpoint
|
|
index (int): optional index of the breakpoint.
|
|
|
|
Returns:
|
|
An instance of ``JLinkBreakpointInfo`` specifying information about
|
|
the breakpoint.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
ValueError: if both the handle and index are invalid.
|
|
"""
|
|
if index < 0:
|
|
if handle == 0:
|
|
raise ValueError('Handle must be provided if index is not set.')
|
|
bp = structs.JLinkBreakpointInfo()
|
|
bp.Handle = int(handle)
|
|
res = self._dll.JLINKARM_GetBPInfoEx(index, ctypes.byref(bp))
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to get breakpoint info.')
|
|
return bp
|
|
|
|
@connection_required
|
|
def breakpoint_find(self, addr):
|
|
"""Returns the handle of a breakpoint at the given address, if any.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): the address to search for the breakpoint
|
|
|
|
Returns:
|
|
A non-zero integer if a breakpoint was found at the given address,
|
|
otherwise zero.
|
|
"""
|
|
return self._dll.JLINKARM_FindBP(addr)
|
|
|
|
@connection_required
|
|
def breakpoint_set(self, addr, thumb=False, arm=False):
|
|
"""Sets a breakpoint at the specified address.
|
|
|
|
If ``thumb`` is ``True``, the breakpoint is set in THUMB-mode, while if
|
|
``arm`` is ``True``, the breakpoint is set in ARM-mode, otherwise a
|
|
normal breakpoint is set.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): the address where the breakpoint will be set
|
|
thumb (bool): boolean indicating to set the breakpoint in THUMB mode
|
|
arm (bool): boolean indicating to set the breakpoint in ARM mode
|
|
|
|
Returns:
|
|
An integer specifying the breakpoint handle. This handle should be
|
|
retained for future breakpoint operations.
|
|
|
|
Raises:
|
|
TypeError: if the given address is not an integer.
|
|
JLinkException: if the breakpoint could not be set.
|
|
"""
|
|
flags = enums.JLinkBreakpoint.ANY
|
|
if thumb:
|
|
flags = flags | enums.JLinkBreakpoint.THUMB
|
|
else:
|
|
if arm:
|
|
flags = flags | enums.JLinkBreakpoint.ARM
|
|
handle = self._dll.JLINKARM_SetBPEx(int(addr), flags)
|
|
if handle <= 0:
|
|
raise errors.JLinkException('Breakpoint could not be set.')
|
|
return handle
|
|
|
|
@connection_required
|
|
def software_breakpoint_set(self, addr, thumb=False, arm=False, flash=False, ram=False):
|
|
"""Sets a software breakpoint at the specified address.
|
|
|
|
If ``thumb`` is ``True``, the breakpoint is set in THUMB-mode, while if
|
|
``arm`` is ``True``, the breakpoint is set in ARM-mode, otherwise a
|
|
normal breakpoint is set.
|
|
|
|
If ``flash`` is ``True``, the breakpoint is set in flash, otherwise if
|
|
``ram`` is ``True``, the breakpoint is set in RAM. If both are
|
|
``True`` or both are ``False``, then the best option is chosen for
|
|
setting the breakpoint in software.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): the address where the breakpoint will be set
|
|
thumb (bool): boolean indicating to set the breakpoint in THUMB mode
|
|
arm (bool): boolean indicating to set the breakpoint in ARM mode
|
|
flash (bool): boolean indicating to set the breakpoint in flash
|
|
ram (bool): boolean indicating to set the breakpoint in RAM
|
|
|
|
Returns:
|
|
An integer specifying the breakpoint handle. This handle should sbe
|
|
retained for future breakpoint operations.
|
|
|
|
Raises:
|
|
TypeError: if the given address is not an integer.
|
|
JLinkException: if the breakpoint could not be set.
|
|
"""
|
|
if flash and not ram:
|
|
flags = enums.JLinkBreakpoint.SW_FLASH
|
|
else:
|
|
if not flash or ram:
|
|
flags = enums.JLinkBreakpoint.SW_RAM
|
|
else:
|
|
flags = enums.JLinkBreakpoint.SW
|
|
if thumb:
|
|
flags = flags | enums.JLinkBreakpoint.THUMB
|
|
else:
|
|
if arm:
|
|
flags = flags | enums.JLinkBreakpoint.ARM
|
|
handle = self._dll.JLINKARM_SetBPEx(int(addr), flags)
|
|
if handle <= 0:
|
|
raise errors.JLinkException('Software breakpoint could not be set.')
|
|
return handle
|
|
|
|
@connection_required
|
|
def hardware_breakpoint_set(self, addr, thumb=False, arm=False):
|
|
"""Sets a hardware breakpoint at the specified address.
|
|
|
|
If ``thumb`` is ``True``, the breakpoint is set in THUMB-mode, while if
|
|
``arm`` is ``True``, the breakpoint is set in ARM-mode, otherwise a
|
|
normal breakpoint is set.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr (int): the address where the breakpoint will be set
|
|
thumb (bool): boolean indicating to set the breakpoint in THUMB mode
|
|
arm (bool): boolean indicating to set the breakpoint in ARM mode
|
|
|
|
Returns:
|
|
An integer specifying the breakpoint handle. This handle should sbe
|
|
retained for future breakpoint operations.
|
|
|
|
Raises:
|
|
TypeError: if the given address is not an integer.
|
|
JLinkException: if the breakpoint could not be set.
|
|
"""
|
|
flags = enums.JLinkBreakpoint.HW
|
|
if thumb:
|
|
flags = flags | enums.JLinkBreakpoint.THUMB
|
|
else:
|
|
if arm:
|
|
flags = flags | enums.JLinkBreakpoint.ARM
|
|
handle = self._dll.JLINKARM_SetBPEx(int(addr), flags)
|
|
if handle <= 0:
|
|
raise errors.JLinkException('Hardware breakpoint could not be set.')
|
|
return handle
|
|
|
|
@connection_required
|
|
def breakpoint_clear(self, handle):
|
|
"""Removes a single breakpoint.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
handle (int): the handle of the breakpoint to be removed
|
|
|
|
Returns:
|
|
``True`` if the breakpoint was cleared, otherwise ``False`` if the
|
|
breakpoint was not valid.
|
|
"""
|
|
return not self._dll.JLINKARM_ClrBPEx(handle)
|
|
|
|
@connection_required
|
|
def breakpoint_clear_all(self):
|
|
"""Removes all breakpoints that have been set.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if they were cleared, otherwise ``False``.
|
|
"""
|
|
return not self._dll.JLINKARM_ClrBPEx(4294967295)
|
|
|
|
@connection_required
|
|
def num_active_watchpoints(self):
|
|
"""Returns the number of currently active watchpoints.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The number of watchpoints that are currently set.
|
|
"""
|
|
return self._dll.JLINKARM_GetNumWPs()
|
|
|
|
@connection_required
|
|
def num_available_watchpoints(self):
|
|
"""Returns the number of available watchpoints.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The number of watchpoints that are available to be set.
|
|
"""
|
|
return self._dll.JLINKARM_GetNumWPUnits()
|
|
|
|
@connection_required
|
|
def watchpoint_info(self, handle=0, index=-1):
|
|
"""Returns information about the specified watchpoint.
|
|
|
|
Note:
|
|
Either ``handle`` or ``index`` can be specified. If the ``index``
|
|
is not provided, the ``handle`` must be set, and vice-versa. If
|
|
both ``index`` and ``handle`` are provided, the ``index`` overrides
|
|
the provided ``handle``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
handle (int): optional handle of a valid watchpoint.
|
|
index (int): optional index of a watchpoint.
|
|
|
|
Returns:
|
|
An instance of ``JLinkWatchpointInfo`` specifying information about
|
|
the watchpoint if the watchpoint was found, otherwise ``None``.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
ValueError: if both handle and index are invalid.
|
|
"""
|
|
if index < 0:
|
|
if handle == 0:
|
|
raise ValueError('Handle must be provided if index is not set.')
|
|
wp = structs.JLinkWatchpointInfo()
|
|
res = self._dll.JLINKARM_GetWPInfoEx(index, ctypes.byref(wp))
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to get watchpoint info.')
|
|
for i in range(res):
|
|
res = self._dll.JLINKARM_GetWPInfoEx(i, ctypes.byref(wp))
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to get watchpoint info.')
|
|
if wp.Handle == handle or wp.WPUnit == index:
|
|
return wp
|
|
|
|
@connection_required
|
|
def watchpoint_set(self, addr, addr_mask=0, data=0, data_mask=0, access_size=None, read=False, write=False, privileged=False):
|
|
"""Sets a watchpoint at the given address.
|
|
|
|
This method allows for a watchpoint to be set on an given address or
|
|
range of addresses. The watchpoint can then be triggered if the data
|
|
at the given address matches the specified ``data`` or range of data as
|
|
determined by ``data_mask``, on specific access size events, reads,
|
|
writes, or privileged accesses.
|
|
|
|
Both ``addr_mask`` and ``data_mask`` are used to specify ranges. Bits
|
|
set to ``1`` are masked out and not taken into consideration when
|
|
comparison against an address or data value. E.g. an ``addr_mask``
|
|
with a value of ``0x1`` and ``addr`` with value ``0xdeadbeef`` means
|
|
that the watchpoint will be set on addresses ``0xdeadbeef`` and
|
|
``0xdeadbeee``. If the ``data`` was ``0x11223340`` and the given
|
|
``data_mask`` has a value of ``0x0000000F``, then the watchpoint would
|
|
trigger for data matching ``0x11223340 - 0x1122334F``.
|
|
|
|
Note:
|
|
If both ``read`` and ``write`` are specified, then the watchpoint
|
|
will trigger on both read and write events to the given address.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
addr_mask (int): optional mask to use for determining which address
|
|
the watchpoint should be set on
|
|
data (int): optional data to set the watchpoint on in order to have
|
|
the watchpoint triggered when the value at the specified address
|
|
matches the given ``data``
|
|
data_mask (int): optional mask to use for determining the range of
|
|
data on which the watchpoint should be triggered
|
|
access_size (int): if specified, this must be one of ``{8, 16, 32}``
|
|
and determines the access size for which the watchpoint should
|
|
trigger
|
|
read (bool): if ``True``, triggers the watchpoint on read events
|
|
write (bool): if ``True``, triggers the watchpoint on write events
|
|
privileged (bool): if ``True``, triggers the watchpoint on privileged
|
|
accesses
|
|
|
|
Returns:
|
|
The handle of the created watchpoint.
|
|
|
|
Raises:
|
|
ValueError: if an invalid access size is given.
|
|
JLinkException: if the watchpoint fails to be set.
|
|
"""
|
|
access_flags = 0
|
|
access_mask_flags = 0
|
|
if access_size is None:
|
|
access_mask_flags = access_mask_flags | enums.JLinkAccessMaskFlags.SIZE
|
|
else:
|
|
if access_size == 8:
|
|
access_flags = access_flags | enums.JLinkAccessFlags.SIZE_8BIT
|
|
else:
|
|
if access_size == 16:
|
|
access_flags = access_flags | enums.JLinkAccessFlags.SIZE_16BIT
|
|
else:
|
|
if access_size == 32:
|
|
access_flags = access_flags | enums.JLinkAccessFlags.SIZE_32BIT
|
|
else:
|
|
raise ValueError('Invalid access size given: %d' % access_size)
|
|
if read and write:
|
|
access_mask_flags = access_mask_flags | enums.JLinkAccessMaskFlags.DIR
|
|
else:
|
|
if read:
|
|
access_flags = access_flags | enums.JLinkAccessFlags.READ
|
|
else:
|
|
if write:
|
|
access_flags = access_flags | enums.JLinkAccessFlags.WRITE
|
|
if privileged:
|
|
access_flags = access_flags | enums.JLinkAccessFlags.PRIV
|
|
else:
|
|
access_mask_flags = access_mask_flags | enums.JLinkAccessMaskFlags.PRIV
|
|
wp = structs.JLinkDataEvent()
|
|
wp.Addr = addr
|
|
wp.AddrMask = addr_mask
|
|
wp.Data = data
|
|
wp.DataMask = data_mask
|
|
wp.Access = access_flags
|
|
wp.AccessMask = access_mask_flags
|
|
handle = ctypes.c_uint32()
|
|
res = self._dll.JLINKARM_SetDataEvent(ctypes.pointer(wp), ctypes.pointer(handle))
|
|
if res < 0:
|
|
raise errors.JLinkDataException(res)
|
|
return handle.value
|
|
|
|
@connection_required
|
|
def watchpoint_clear(self, handle):
|
|
"""Clears the watchpoint with the specified handle.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
handle (int): the handle of the watchpoint
|
|
|
|
Returns:
|
|
``True`` if watchpoint was removed, otherwise ``False``.
|
|
"""
|
|
return not self._dll.JLINKARM_ClrDataEvent(handle)
|
|
|
|
@connection_required
|
|
def watchpoint_clear_all(self):
|
|
"""Removes all watchpoints that have been set.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if they were cleared, otherwise ``False``.
|
|
"""
|
|
return not self._dll.JLINKARM_ClrDataEvent(4294967295)
|
|
|
|
def disassemble_instruction(self, instruction):
|
|
"""Disassembles and returns the assembly instruction string.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
instruction (int): the instruction address.
|
|
|
|
Returns:
|
|
A string corresponding to the assembly instruction string at the
|
|
given instruction address.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
TypeError: if ``instruction`` is not a number.
|
|
"""
|
|
if not util.is_integer(instruction):
|
|
raise TypeError('Expected instruction to be an integer.')
|
|
buf_size = self.MAX_BUF_SIZE
|
|
buf = (ctypes.c_char * buf_size)()
|
|
res = self._dll.JLINKARM_DisassembleInst(ctypes.byref(buf), buf_size, instruction)
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to disassemble instruction.')
|
|
return ctypes.string_at(buf).decode()
|
|
|
|
@connection_required
|
|
def strace_configure(self, port_width):
|
|
"""Configures the trace port width for tracing.
|
|
|
|
Note that configuration cannot occur while STRACE is running.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
port_width (int): the trace port width to use.
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
ValueError: if ``port_width`` is not ``1``, ``2``, or ``4``.
|
|
JLinkException: on error.
|
|
"""
|
|
if port_width not in (1, 2, 4):
|
|
raise ValueError('Invalid port width: %s' % str(port_width))
|
|
config_string = 'PortWidth=%d' % port_width
|
|
res = self._dll.JLINK_STRACE_Config(config_string.encode())
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to configure STRACE port')
|
|
|
|
@connection_required
|
|
def strace_start(self):
|
|
"""Starts the capturing of STRACE data.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
res = self._dll.JLINK_STRACE_Start()
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to start STRACE.')
|
|
|
|
@connection_required
|
|
def strace_stop(self):
|
|
"""Stops the sampling of STRACE data.
|
|
|
|
Any capturing of STRACE data is automatically stopped when the CPU is
|
|
halted.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
res = self._dll.JLINK_STRACE_Stop()
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to stop STRACE.')
|
|
|
|
@connection_required
|
|
def strace_read(self, num_instructions):
|
|
"""Reads and returns a number of instructions captured by STRACE.
|
|
|
|
The number of instructions must be a non-negative value of at most
|
|
``0x10000`` (``65536``).
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
num_instructions (int): number of instructions to fetch.
|
|
|
|
Returns:
|
|
A list of instruction addresses in order from most recently executed
|
|
to oldest executed instructions. Note that the number of
|
|
instructions returned can be less than the number of instructions
|
|
requested in the case that there are not ``num_instructions`` in the
|
|
trace buffer.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
ValueError: if ``num_instructions < 0`` or
|
|
``num_instructions > 0x10000``.
|
|
"""
|
|
if num_instructions < 0 or num_instructions > 65536:
|
|
raise ValueError('Invalid instruction count.')
|
|
buf = (ctypes.c_uint32 * num_instructions)()
|
|
buf_size = num_instructions
|
|
res = self._dll.JLINK_STRACE_Read(ctypes.byref(buf), buf_size)
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to read from STRACE buffer.')
|
|
return list(buf)[:res]
|
|
|
|
@connection_required
|
|
def strace_code_fetch_event(self, operation, address, address_range=0):
|
|
"""Sets an event to trigger trace logic when an instruction is fetched.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
operation (int): one of the operations in ``JLinkStraceOperation``.
|
|
address (int): the address of the instruction that is fetched.
|
|
address_range (int): optional range of address to trigger event on.
|
|
|
|
Returns:
|
|
An integer specifying the trace event handle. This handle should be
|
|
retained in order to clear the event at a later time.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
cmd = enums.JLinkStraceCommand.TRACE_EVENT_SET
|
|
event_info = structs.JLinkStraceEventInfo()
|
|
event_info.Type = enums.JLinkStraceEvent.CODE_FETCH
|
|
event_info.Op = operation
|
|
event_info.Addr = int(address)
|
|
event_info.AddrRangeSize = int(address_range)
|
|
handle = self._dll.JLINK_STRACE_Control(cmd, ctypes.byref(event_info))
|
|
if handle < 0:
|
|
raise errors.JLinkException(handle)
|
|
return handle
|
|
|
|
@connection_required
|
|
def strace_data_access_event(self, operation, address, data, data_mask=None, access_width=4, address_range=0):
|
|
"""Sets an event to trigger trace logic when data access is made.
|
|
|
|
Data access corresponds to either a read or write.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
operation (int): one of the operations in ``JLinkStraceOperation``.
|
|
address (int): the address of the load/store data.
|
|
data (int): the data to be compared the event data to.
|
|
data_mask (int): optional bitmask specifying bits to ignore in
|
|
comparison.
|
|
acess_width (int): optional access width for the data.
|
|
address_range (int): optional range of address to trigger event on.
|
|
|
|
Returns:
|
|
An integer specifying the trace event handle. This handle should be
|
|
retained in order to clear the event at a later time.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
cmd = enums.JLinkStraceCommand.TRACE_EVENT_SET
|
|
event_info = structs.JLinkStraceEventInfo()
|
|
event_info.Type = enums.JLinkStraceEvent.DATA_ACCESS
|
|
event_info.Op = operation
|
|
event_info.AccessSize = int(access_width)
|
|
event_info.Addr = int(address)
|
|
event_info.Data = int(data)
|
|
event_info.DataMask = int(data_mask or 0)
|
|
event_info.AddrRangeSize = int(address_range)
|
|
handle = self._dll.JLINK_STRACE_Control(cmd, ctypes.byref(event_info))
|
|
if handle < 0:
|
|
raise errors.JLinkException(handle)
|
|
return handle
|
|
|
|
@connection_required
|
|
def strace_data_load_event(self, operation, address, address_range=0):
|
|
"""Sets an event to trigger trace logic when data read access is made.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
operation (int): one of the operations in ``JLinkStraceOperation``.
|
|
address (int): the address of the load data.
|
|
address_range (int): optional range of address to trigger event on.
|
|
|
|
Returns:
|
|
An integer specifying the trace event handle. This handle should be
|
|
retained in order to clear the event at a later time.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
cmd = enums.JLinkStraceCommand.TRACE_EVENT_SET
|
|
event_info = structs.JLinkStraceEventInfo()
|
|
event_info.Type = enums.JLinkStraceEvent.DATA_LOAD
|
|
event_info.Op = operation
|
|
event_info.Addr = int(address)
|
|
event_info.AddrRangeSize = int(address_range)
|
|
handle = self._dll.JLINK_STRACE_Control(cmd, ctypes.byref(event_info))
|
|
if handle < 0:
|
|
raise errors.JLinkException(handle)
|
|
return handle
|
|
|
|
@connection_required
|
|
def strace_data_store_event(self, operation, address, address_range=0):
|
|
"""Sets an event to trigger trace logic when data write access is made.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
operation (int): one of the operations in ``JLinkStraceOperation``.
|
|
address (int): the address of the store data.
|
|
address_range (int): optional range of address to trigger event on.
|
|
|
|
Returns:
|
|
An integer specifying the trace event handle. This handle should be
|
|
retained in order to clear the event at a later time.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
cmd = enums.JLinkStraceCommand.TRACE_EVENT_SET
|
|
event_info = structs.JLinkStraceEventInfo()
|
|
event_info.Type = enums.JLinkStraceEvent.DATA_STORE
|
|
event_info.Op = operation
|
|
event_info.Addr = int(address)
|
|
event_info.AddrRangeSize = int(address_range)
|
|
handle = self._dll.JLINK_STRACE_Control(cmd, ctypes.byref(event_info))
|
|
if handle < 0:
|
|
raise errors.JLinkException(handle)
|
|
return handle
|
|
|
|
@connection_required
|
|
def strace_clear(self, handle):
|
|
"""Clears the trace event specified by the given handle.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
handle (int): handle of the trace event.
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
data = ctypes.c_int(handle)
|
|
res = self._dll.JLINK_STRACE_Control(enums.JLinkStraceCommand.TRACE_EVENT_CLR, ctypes.byref(data))
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to clear STRACE event.')
|
|
|
|
@connection_required
|
|
def strace_clear_all(self):
|
|
"""Clears all STRACE events.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
data = 0
|
|
res = self._dll.JLINK_STRACE_Control(enums.JLinkStraceCommand.TRACE_EVENT_CLR_ALL, data)
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to clear all STRACE events.')
|
|
|
|
@connection_required
|
|
def strace_set_buffer_size(self, size):
|
|
"""Sets the STRACE buffer size.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
size = ctypes.c_uint32(size)
|
|
res = self._dll.JLINK_STRACE_Control(enums.JLinkStraceCommand.SET_BUFFER_SIZE, size)
|
|
if res < 0:
|
|
raise errors.JLinkException('Failed to set the STRACE buffer size.')
|
|
|
|
@connection_required
|
|
def trace_start(self):
|
|
"""Starts collecting trace data.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.START
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, 0)
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to start trace.')
|
|
|
|
@connection_required
|
|
def trace_stop(self):
|
|
"""Stops collecting trace data.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.STOP
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, 0)
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to stop trace.')
|
|
|
|
@connection_required
|
|
def trace_flush(self):
|
|
"""Flushes the trace buffer.
|
|
|
|
After this method is called, the trace buffer is empty. This method is
|
|
best called when the device is reset.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.FLUSH
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, 0)
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to flush the trace buffer.')
|
|
|
|
@connection_required
|
|
def trace_sample_count(self):
|
|
"""Retrieves the number of samples in the trace buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
Number of samples in the trace buffer.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_NUM_SAMPLES
|
|
data = ctypes.c_uint32(self.trace_max_buffer_capacity())
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get trace sample count.')
|
|
return data.value
|
|
|
|
@connection_required
|
|
def trace_buffer_capacity(self):
|
|
"""Retrieves the trace buffer's current capacity.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
The current capacity of the trace buffer. This is not necessarily
|
|
the maximum possible size the buffer could be configured with.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_CONF_CAPACITY
|
|
data = ctypes.c_uint32(0)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get trace buffer size.')
|
|
return data.value
|
|
|
|
@connection_required
|
|
def trace_set_buffer_capacity(self, size):
|
|
"""Sets the capacity for the trace buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
size (int): the new capacity for the trace buffer.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.SET_CAPACITY
|
|
data = ctypes.c_uint32(size)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to set trace buffer size.')
|
|
|
|
@connection_required
|
|
def trace_min_buffer_capacity(self):
|
|
"""Retrieves the minimum capacity the trace buffer can be configured with.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
The minimum configurable capacity for the trace buffer.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_MIN_CAPACITY
|
|
data = ctypes.c_uint32(0)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get min trace buffer size.')
|
|
return data.value
|
|
|
|
@connection_required
|
|
def trace_max_buffer_capacity(self):
|
|
"""Retrieves the maximum size the trace buffer can be configured with.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
The maximum configurable capacity for the trace buffer.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_MAX_CAPACITY
|
|
data = ctypes.c_uint32(0)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get max trace buffer size.')
|
|
return data.value
|
|
|
|
@connection_required
|
|
def trace_set_format(self, fmt):
|
|
"""Sets the format for the trace buffer to use.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
fmt (int): format for the trace buffer; this is one of the attributes
|
|
of ``JLinkTraceFormat``.
|
|
|
|
Returns:
|
|
``None``
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.SET_FORMAT
|
|
data = ctypes.c_uint32(fmt)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to set trace format.')
|
|
|
|
@connection_required
|
|
def trace_format(self):
|
|
"""Retrieves the current format the trace buffer is using.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
The current format the trace buffer is using. This is one of the
|
|
attributes of ``JLinkTraceFormat``.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_FORMAT
|
|
data = ctypes.c_uint32(0)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get trace format.')
|
|
return data.value
|
|
|
|
@connection_required
|
|
def trace_region_count(self):
|
|
"""Retrieves a count of the number of available trace regions.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
|
|
Returns:
|
|
Count of the number of available trace regions.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_NUM_REGIONS
|
|
data = ctypes.c_uint32(0)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(data))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get trace region count.')
|
|
return data.value
|
|
|
|
@connection_required
|
|
def trace_region(self, region_index):
|
|
"""Retrieves the properties of a trace region.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
region_index (int): the trace region index.
|
|
|
|
Returns:
|
|
An instance of ``JLinkTraceRegion`` describing the specified region.
|
|
"""
|
|
cmd = enums.JLinkTraceCommand.GET_REGION_PROPS_EX
|
|
region = structs.JLinkTraceRegion()
|
|
region.RegionIndex = int(region_index)
|
|
res = self._dll.JLINKARM_TRACE_Control(cmd, ctypes.byref(region))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to get trace region.')
|
|
return region
|
|
|
|
@connection_required
|
|
def trace_read(self, offset, num_items):
|
|
"""Reads data from the trace buffer and returns it.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance.
|
|
offset (int): the offset from which to start reading from the trace
|
|
buffer.
|
|
num_items (int): number of items to read from the trace buffer.
|
|
|
|
Returns:
|
|
A list of ``JLinkTraceData`` instances corresponding to the items
|
|
read from the trace buffer. Note that this list may have size less
|
|
than ``num_items`` in the event that there are not ``num_items``
|
|
items in the trace buffer.
|
|
|
|
Raises:
|
|
JLinkException: on error.
|
|
"""
|
|
buf_size = ctypes.c_uint32(num_items)
|
|
buf = (structs.JLinkTraceData * num_items)()
|
|
res = self._dll.JLINKARM_TRACE_Read(buf, int(offset), ctypes.byref(buf_size))
|
|
if res == 1:
|
|
raise errors.JLinkException('Failed to read from trace buffer.')
|
|
return list(buf)[:int(buf_size.value)]
|
|
|
|
def swo_enabled(self):
|
|
"""Returns whether or not SWO is enabled.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``True`` if SWO is enabled, otherwise ``False``.
|
|
"""
|
|
return self._swo_enabled
|
|
|
|
@connection_required
|
|
def swo_start(self, swo_speed=9600):
|
|
"""Starts collecting SWO data.
|
|
|
|
Note:
|
|
If SWO is already enabled, it will first stop SWO before enabling it
|
|
again.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
swo_speed (int): the frequency in Hz used by the target to communicate
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
if self.swo_enabled():
|
|
self.swo_stop()
|
|
info = structs.JLinkSWOStartInfo()
|
|
info.Speed = swo_speed
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.START, ctypes.byref(info))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
self._swo_enabled = True
|
|
|
|
@connection_required
|
|
def swo_stop(self):
|
|
"""Stops collecting SWO data.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.STOP, 0)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def swo_enable(self, cpu_speed, swo_speed=9600, port_mask=1):
|
|
"""Enables SWO output on the target device.
|
|
|
|
Configures the output protocol, the SWO output speed, and enables any
|
|
ITM & stimulus ports.
|
|
|
|
This is equivalent to calling ``.swo_start()``.
|
|
|
|
Note:
|
|
If SWO is already enabled, it will first stop SWO before enabling it
|
|
again.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
cpu_speed (int): the target CPU frequency in Hz
|
|
swo_speed (int): the frequency in Hz used by the target to communicate
|
|
port_mask (int): port mask specifying which stimulus ports to enable
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
if self.swo_enabled():
|
|
self.swo_stop()
|
|
res = self._dll.JLINKARM_SWO_EnableTarget(cpu_speed, swo_speed, enums.JLinkSWOInterfaces.UART, port_mask)
|
|
if res != 0:
|
|
raise errors.JLinkException(res)
|
|
self._swo_enabled = True
|
|
|
|
@connection_required
|
|
def swo_disable(self, port_mask):
|
|
"""Disables ITM & Stimulus ports.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
port_mask (int): mask specifying which ports to disable
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
res = self._dll.JLINKARM_SWO_DisableTarget(port_mask)
|
|
if res != 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def swo_flush(self, num_bytes=None):
|
|
"""Flushes data from the SWO buffer.
|
|
|
|
After this method is called, the flushed part of the SWO buffer is
|
|
empty.
|
|
|
|
If ``num_bytes`` is not present, flushes all data currently in the SWO
|
|
buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
num_bytes (int): the number of bytes to flush
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
if num_bytes is None:
|
|
num_bytes = self.swo_num_bytes()
|
|
buf = ctypes.c_uint32(num_bytes)
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.FLUSH, ctypes.byref(buf))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def swo_speed_info(self):
|
|
"""Retrieves information about the supported SWO speeds.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
A ``JLinkSWOSpeedInfo`` instance describing the target's supported
|
|
SWO speeds.
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
info = structs.JLinkSWOSpeedInfo()
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.GET_SPEED_INFO, ctypes.byref(info))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return info
|
|
|
|
@connection_required
|
|
def swo_num_bytes(self):
|
|
"""Retrives the number of bytes in the SWO buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
Number of bytes in the SWO buffer.
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.GET_NUM_BYTES, 0)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return res
|
|
|
|
@connection_required
|
|
def swo_set_host_buffer_size(self, buf_size):
|
|
"""Sets the size of the buffer used by the host to collect SWO data.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
buf_size (int): the new size of the host buffer
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
buf = ctypes.c_uint32(buf_size)
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.SET_BUFFERSIZE_HOST, ctypes.byref(buf))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def swo_set_emu_buffer_size(self, buf_size):
|
|
"""Sets the size of the buffer used by the J-Link to collect SWO data.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
buf_size (int): the new size of the emulator buffer
|
|
|
|
Returns:
|
|
``None``
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
buf = ctypes.c_uint32(buf_size)
|
|
res = self._dll.JLINKARM_SWO_Control(enums.JLinkSWOCommands.SET_BUFFERSIZE_EMU, ctypes.byref(buf))
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
|
|
@connection_required
|
|
def swo_supported_speeds(self, cpu_speed, num_speeds=3):
|
|
"""Retrives a list of SWO speeds supported by both the target and the
|
|
connected J-Link.
|
|
|
|
The supported speeds are returned in order from highest to lowest.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
cpu_speed (int): the target's CPU speed in Hz
|
|
num_speeds (int): the number of compatible speeds to return
|
|
|
|
Returns:
|
|
A list of compatible SWO speeds in Hz in order from highest to lowest.
|
|
"""
|
|
buf_size = num_speeds
|
|
buf = (ctypes.c_uint32 * buf_size)()
|
|
res = self._dll.JLINKARM_SWO_GetCompatibleSpeeds(cpu_speed, 0, buf, buf_size)
|
|
if res < 0:
|
|
raise errors.JLinkException(res)
|
|
return list(buf)[:res]
|
|
|
|
@connection_required
|
|
def swo_read(self, offset, num_bytes, remove=False):
|
|
"""Reads data from the SWO buffer.
|
|
|
|
The data read is not automatically removed from the SWO buffer after
|
|
reading unless ``remove`` is ``True``. Otherwise the callee must
|
|
explicitly remove the data by calling ``.swo_flush()``.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
offset (int): offset of first byte to be retrieved
|
|
num_bytes (int): number of bytes to read
|
|
remove (bool): if data should be removed from buffer after read
|
|
|
|
Returns:
|
|
A list of bytes read from the SWO buffer.
|
|
"""
|
|
buf_size = ctypes.c_uint32(num_bytes)
|
|
buf = ctypes.c_uint8 * num_bytes(0)
|
|
self._dll.JLINKARM_SWO_Read(buf, offset, ctypes.byref(buf_size))
|
|
buf_size = buf_size.value
|
|
if remove:
|
|
self.swo_flush(buf_size)
|
|
return list(buf)[:buf_size]
|
|
|
|
@connection_required
|
|
def swo_read_stimulus(self, port, num_bytes):
|
|
"""Reads the printable data via SWO.
|
|
|
|
This method reads SWO for one stimulus port, which is all printable
|
|
data.
|
|
|
|
Note:
|
|
Stimulus port ``0`` is used for ``printf`` debugging.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
port (int): the stimulus port to read from, ``0 - 31``
|
|
num_bytes (int): number of bytes to read
|
|
|
|
Returns:
|
|
A list of bytes read via SWO.
|
|
|
|
Raises:
|
|
ValueError: if ``port < 0`` or ``port > 31``
|
|
"""
|
|
if port < 0 or port > 31:
|
|
raise ValueError('Invalid port number: %s' % port)
|
|
buf_size = num_bytes
|
|
buf = (ctypes.c_uint8 * buf_size)()
|
|
bytes_read = self._dll.JLINKARM_SWO_ReadStimulus(port, buf, buf_size)
|
|
return list(buf)[:bytes_read]
|
|
|
|
@open_required
|
|
def rtt_start(self):
|
|
"""Starts RTT processing, including background read of target data.
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Raises:
|
|
JLinkRTTException if the underlying JLINK_RTTERMINAL_Control call fails.
|
|
"""
|
|
self.rtt_control(enums.JLinkRTTCommand.START, None)
|
|
|
|
@open_required
|
|
def rtt_stop(self):
|
|
"""Stops RTT on the J-Link and host side.
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Raises:
|
|
JLinkRTTException if the underlying JLINK_RTTERMINAL_Control call fails.
|
|
"""
|
|
self.rtt_control(enums.JLinkRTTCommand.STOP, None)
|
|
|
|
@open_required
|
|
def rtt_get_num_up_buffers(self):
|
|
"""After starting RTT, get the current number of up buffers.
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The number of configured up buffers on the target.
|
|
|
|
Raises:
|
|
JLinkRTTException if the underlying JLINK_RTTERMINAL_Control call fails.
|
|
"""
|
|
cmd = enums.JLinkRTTCommand.GETNUMBUF
|
|
dir = ctypes.c_int(enums.JLinkRTTDirection.UP)
|
|
return self.rtt_control(cmd, dir)
|
|
|
|
@open_required
|
|
def rtt_get_num_down_buffers(self):
|
|
"""After starting RTT, get the current number of down buffers.
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
|
|
Returns:
|
|
The number of configured down buffers on the target.
|
|
|
|
Raises:
|
|
JLinkRTTException if the underlying JLINK_RTTERMINAL_Control call fails.
|
|
"""
|
|
cmd = enums.JLinkRTTCommand.GETNUMBUF
|
|
dir = ctypes.c_int(enums.JLinkRTTDirection.DOWN)
|
|
return self.rtt_control(cmd, dir)
|
|
|
|
@open_required
|
|
def rtt_read(self, buffer_index, num_bytes):
|
|
"""Reads data from the RTT buffer.
|
|
|
|
This method will read at most num_bytes bytes from the specified
|
|
RTT buffer. The data is automatically removed from the RTT buffer.
|
|
If there are not num_bytes bytes waiting in the RTT buffer, the
|
|
entire contents of the RTT buffer will be read.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
buffer_index (int): the index of the RTT buffer to read from
|
|
num_bytes (int): the maximum number of bytes to read
|
|
|
|
Returns:
|
|
A list of bytes read from RTT.
|
|
|
|
Raises:
|
|
JLinkRTTException if the underlying JLINK_RTTERMINAL_Read call fails.
|
|
"""
|
|
buf = (ctypes.c_ubyte * num_bytes)()
|
|
bytes_read = self._dll.JLINK_RTTERMINAL_Read(buffer_index, buf, num_bytes)
|
|
if bytes_read < 0:
|
|
raise errors.JLinkRTTException(bytes_read)
|
|
return list(buf)[:bytes_read]
|
|
|
|
@open_required
|
|
def rtt_write(self, buffer_index, data):
|
|
"""Writes data to the RTT buffer.
|
|
|
|
This method will write at most len(data) bytes to the specified RTT
|
|
buffer.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
buffer_index (int): the index of the RTT buffer to write to
|
|
data (list): the list of bytes to write to the RTT buffer
|
|
|
|
Returns:
|
|
The number of bytes successfully written to the RTT buffer.
|
|
|
|
Raises:
|
|
JLinkRTTException if the underlying JLINK_RTTERMINAL_Write call fails.
|
|
"""
|
|
buf_size = len(data)
|
|
buf = (ctypes.c_ubyte * buf_size)(*bytearray(data))
|
|
bytes_written = self._dll.JLINK_RTTERMINAL_Write(buffer_index, buf, buf_size)
|
|
if bytes_written < 0:
|
|
raise errors.JLinkRTTException(bytes_written)
|
|
return bytes_written
|
|
|
|
@open_required
|
|
def rtt_control(self, command, config):
|
|
"""Issues an RTT Control command.
|
|
|
|
All RTT control is done through a single API call which expects
|
|
specifically laid-out configuration structures.
|
|
|
|
Args:
|
|
self (JLink): the ``JLink`` instance
|
|
command (int): the command to issue (see enums.JLinkRTTCommand)
|
|
config (ctypes type): the configuration to pass by reference.
|
|
|
|
Returns:
|
|
An integer containing the result of the command.
|
|
"""
|
|
config_byref = ctypes.byref(config) if config is not None else None
|
|
res = self._dll.JLINK_RTTERMINAL_Control(command, config_byref)
|
|
if res < 0:
|
|
raise errors.JLinkRTTException(res)
|
|
return res
|
|
|
|
@connection_required
|
|
def cp15_present(self):
|
|
"""Returns whether target has CP15 co-processor.
|
|
|
|
Returns:
|
|
``True`` if the target has CP15 co-processor, otherwise ``False``.
|
|
"""
|
|
result = False
|
|
if self._dll.JLINKARM_CP15_IsPresent() != 0:
|
|
result = True
|
|
return result
|
|
|
|
@open_required
|
|
def cp15_register_read(self, cr_n, op_1, cr_m, op_2):
|
|
"""Reads value from specified coprocessor register.
|
|
|
|
Args:
|
|
cr_n (int): CRn value
|
|
op_1 (int): Op1 value
|
|
cr_m (int): CRm value
|
|
op_2 (int): Op2 value
|
|
|
|
Returns:
|
|
An integer containing the value of coprocessor register
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
value = ctypes.c_uint32(0)
|
|
p_value = ctypes.pointer(value)
|
|
res = self._dll.JLINKARM_CP15_ReadEx(cr_n, cr_m, op_1, op_2, p_value)
|
|
if res != 0:
|
|
raise errors.JLinkException(res)
|
|
else:
|
|
value = value.value
|
|
return value
|
|
|
|
@open_required
|
|
def cp15_register_write(self, cr_n, op_1, cr_m, op_2, value):
|
|
"""Writes value to specified coprocessor register.
|
|
|
|
Args:
|
|
cr_n (int): CRn value
|
|
op_1 (int): Op1 value
|
|
cr_m (int): CRm value
|
|
op_2 (int): Op2 value
|
|
value (int): value to write
|
|
|
|
Returns:
|
|
An integer containing the result of the command
|
|
|
|
Raises:
|
|
JLinkException: on error
|
|
"""
|
|
res = self._dll.JLINKARM_CP15_WriteEx(cr_n, cr_m, op_1, op_2, value)
|
|
if res != 0:
|
|
raise errors.JLinkException(res)
|
|
return res
|
|
# okay decompiling ./pylink/jlink.pyc
|