blflashcommand/pylink/jlink.py
2023-04-20 11:46:51 -07:00

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