# 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/library.py from . import util import ctypes import ctypes.util as ctypes_util import os, sys, tempfile class Library(object): __doc__ = 'Wrapper to provide easy access to loading the J-Link SDK DLL.\n\n This class provides a convenience for finding and loading the J-Link DLL\n across multiple platforms, and accounting for the inconsistencies between\n Windows and nix-based platforms.\n\n Attributes:\n _standard_calls_: list of names of the methods for the API calls that\n must be converted to standard calling convention on the Windows\n platform.\n JLINK_SDK_NAME: name of the J-Link DLL on nix-based platforms.\n WINDOWS_JLINK_SDK_NAME: name of the J-Link DLL on Windows platforms.\n ' _standard_calls_ = [ 'JLINK_Configure', 'JLINK_DownloadFile', 'JLINK_GetAvailableLicense', 'JLINK_GetPCode', 'JLINK_PrintConfig', 'JLINK_EraseChip', 'JLINK_SPI_Transfer', 'JLINK_GetpFunc', 'JLINK_GetMemZones', 'JLINK_ReadMemZonedEx', 'JLINK_SetHookUnsecureDialog', 'JLINK_WriteMemZonedEx', 'JLINK_DIALOG_Configure', 'JLINK_DIALOG_ConfigureEx', 'JLINK_EMU_GPIO_GetProps', 'JLINK_EMU_GPIO_GetState', 'JLINK_EMU_GPIO_SetState', 'JLINK_EMU_AddLicense', 'JLINK_EMU_EraseLicenses', 'JLINK_EMU_GetLicenses', 'JLINK_HSS_GetCaps', 'JLINK_HSS_Start', 'JLINK_HSS_Stop', 'JLINK_HSS_Read', 'JLINK_POWERTRACE_Control', 'JLINK_POWERTRACE_Read', 'JLINK_RTTERMINAL_Control', 'JLINK_RTTERMINAL_Read', 'JLINK_RTTERMINAL_Write', 'JLINK_STRACE_Config', 'JLINK_STRACE_Control', 'JLINK_STRACE_Read', 'JLINK_STRACE_Start', 'JLINK_STRACE_Stop', 'JLINK_SWD_GetData', 'JLINK_SWD_GetU8', 'JLINK_SWD_GetU16', 'JLINK_SWD_GetU32', 'JLINK_SWD_StoreGetRaw', 'JLINK_SWD_StoreRaw', 'JLINK_SWD_SyncBits', 'JLINK_SWD_SyncBytes', 'JLINK_SetFlashProgProgressCallback'] JLINK_SDK_NAME = 'libjlinkarm' WINDOWS_32_JLINK_SDK_NAME = 'JLinkARM' WINDOWS_64_JLINK_SDK_NAME = 'JLink_x64' @classmethod def get_appropriate_windows_sdk_name(cls): """Returns the appropriate JLink SDK library name on Windows depending on 32bit or 64bit Python variant. SEGGER delivers two variants of their dynamic library on Windows: - ``JLinkARM.dll`` for 32-bit platform - ``JLink_x64.dll`` for 64-bit platform Args: cls (Library): the ``Library`` class Returns: The name of the library depending on the platform this module is run on. """ if sys.maxsize == 9223372036854775807: return Library.WINDOWS_64_JLINK_SDK_NAME return Library.WINDOWS_32_JLINK_SDK_NAME @classmethod def find_library_windows(cls): r"""Loads the SEGGER DLL from the windows installation directory. On Windows, these are found either under: - ``C:\Program Files\SEGGER\JLink`` - ``C:\Program Files (x86)\SEGGER\JLink``. Args: cls (Library): the ``Library`` class Returns: The paths to the J-Link library files in the order that they are found. """ dll = cls.get_appropriate_windows_sdk_name() + '.dll' root = 'C:\\' for d in os.listdir(root): dir_path = os.path.join(root, d) if d.startswith('Program Files'): if os.path.isdir(dir_path): dir_path = os.path.join(dir_path, 'SEGGER') if not os.path.isdir(dir_path): continue else: ds = filter(lambda x: x.startswith('JLink') , os.listdir(dir_path)) for jlink_dir in ds: lib_path = os.path.join(dir_path, jlink_dir, dll) if os.path.isfile(lib_path): yield lib_path @classmethod def find_library_linux(cls): """Loads the SEGGER DLL from the root directory. On Linux, the SEGGER tools are installed under the ``/opt/SEGGER`` directory with versioned directories having the suffix ``_VERSION``. Args: cls (Library): the ``Library`` class Returns: The paths to the J-Link library files in the order that they are found. """ dll = Library.JLINK_SDK_NAME root = os.path.join('/', 'opt', 'SEGGER') for directory_name, subdirs, files in os.walk(root): fnames = [] x86_found = False for f in files: path = os.path.join(directory_name, f) if os.path.isfile(path): if f.startswith(dll): fnames.append(f) if '_x86' in path: x86_found = True for fname in fnames: fpath = os.path.join(directory_name, fname) if util.is_os_64bit(): if '_x86' not in fname: yield fpath else: if x86_found: if '_x86' in fname: yield fpath else: yield fpath @classmethod def find_library_darwin(cls): r"""Loads the SEGGER DLL from the installed applications. This method accounts for the all the different ways in which the DLL may be installed depending on the version of the DLL. Always uses the first directory found. SEGGER's DLL is installed in one of three ways dependent on which which version of the SEGGER tools are installed: ======== ============================================================ Versions Directory ======== ============================================================ < 5.0.0 ``/Applications/SEGGER/JLink\ NUMBER`` < 6.0.0 ``/Applications/SEGGER/JLink/libjlinkarm.major.minor.dylib`` >= 6.0.0 ``/Applications/SEGGER/JLink/libjlinkarm`` ======== ============================================================ Args: cls (Library): the ``Library`` class Returns: The path to the J-Link library files in the order they are found. """ dll = Library.JLINK_SDK_NAME root = os.path.join('/', 'Applications', 'SEGGER') if not os.path.isdir(root): return for d in os.listdir(root): dir_path = os.path.join(root, d) if os.path.isdir(dir_path): if d.startswith('JLink'): files = list((f for f in os.listdir(dir_path) if os.path.isfile(os.path.join(dir_path, f)))) if dll + '.dylib' in files: yield os.path.join(dir_path, dll + '.dylib') else: for f in files: if f.startswith(dll): yield os.path.join(dir_path, f) def __init__(self, dllpath=None): """Initializes an instance of a ``Library``. Loads the default J-Link DLL if ``dllpath`` is ``None``, otherwise loads the DLL specified by the given ``dllpath``. Args: self (Library): the ``Library`` instance dllpath (str): the DLL to load into the library Returns: ``None`` """ self._lib = None self._winlib = None self._path = None self._windows = sys.platform.startswith('win') self._cygwin = sys.platform.startswith('cygwin') self._temp = None if self._windows or self._cygwin: self._sdk = self.get_appropriate_windows_sdk_name() else: self._sdk = self.JLINK_SDK_NAME if dllpath is not None: self.load(dllpath) else: self.load_default() def __del__(self): """Cleans up the temporary DLL file created when the lib was loaded. Args: self (Library): the ``Library`` instance Returns: ``None`` """ self.unload() def load_default(self): """Loads the default J-Link SDK DLL. The default J-Link SDK is determined by first checking if ``ctypes`` can find the DLL, then by searching the platform-specific paths. Args: self (Library): the ``Library`` instance Returns: ``True`` if the DLL was loaded, otherwise ``False``. """ path = ctypes_util.find_library(self._sdk) if not path is None or self._windows or self._cygwin: path = next(self.find_library_windows(), None) else: if sys.platform.startswith('linux'): path = next(self.find_library_linux(), None) else: if sys.platform.startswith('darwin'): path = next(self.find_library_darwin(), None) if path is not None: return self.load(path) return False def load(self, path=None): """Loads the specified DLL, if any, otherwise re-loads the current DLL. If ``path`` is specified, loads the DLL at the given ``path``, otherwise re-loads the DLL currently specified by this library. Note: This creates a temporary DLL file to use for the instance. This is necessary to work around a limitation of the J-Link DLL in which multiple J-Links cannot be accessed from the same process. Args: self (Library): the ``Library`` instance path (path): path to the DLL to load Returns: ``True`` if library was loaded successfully. Raises: OSError: if there is no J-LINK SDK DLL present at the path. See Also: `J-Link Multi-session `_. """ self.unload() self._path = path or self._path if self._windows or self._cygwin: suffix = '.dll' else: if sys.platform.startswith('darwin'): suffix = '.dylib' else: suffix = '.so' tf = tempfile.NamedTemporaryFile(delete=False, suffix=suffix) with open(tf.name, 'wb') as outputfile: with open(self._path, 'rb') as inputfile: outputfile.write(inputfile.read()) tf.close() self._temp = tf self._lib = ctypes.cdll.LoadLibrary(tf.name) if self._windows: self._winlib = ctypes.windll.LoadLibrary(tf.name) for stdcall in self._standard_calls_: if hasattr(self._winlib, stdcall): setattr(self._lib, stdcall, getattr(self._winlib, stdcall)) return True def unload(self): """Unloads the library's DLL if it has been loaded. This additionally cleans up the temporary DLL file that was created when the library was loaded. Args: self (Library): the ``Library`` instance Returns: ``True`` if the DLL was unloaded, otherwise ``False``. """ unloaded = False if self._lib is not None: if self._winlib is not None: ctypes.windll.kernel32.FreeLibrary.argtypes = ( ctypes.c_void_p,) ctypes.windll.kernel32.FreeLibrary(self._lib._handle) ctypes.windll.kernel32.FreeLibrary(self._winlib._handle) self._lib = None self._winlib = None unloaded = True else: del self._lib self._lib = None unloaded = True if self._temp is not None: os.remove(self._temp.name) self._temp = None return unloaded def dll(self): """Returns the DLL for the underlying shared library. Args: self (Library): the ``Library`` instance Returns: A ``ctypes`` DLL instance if one was loaded, otherwise ``None``. """ return self._lib # okay decompiling ./pylink/library.pyc