Skip to content

Add unlock IDCODE support using indirect API #231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

JeremiahGillis
Copy link

This PR adds support for unlock IDCODE which is one of J-Link indirect API functions. A number of Renesas devices can restrict debug access using a hexadecimal code known as an IDCODE. When a device is locked, the J-Link driver will provide a dialog to enter an IDCODE when connecting to the device:

image

With this PR, a user can set the IDCODE which will automatically unlock the device when connecting. There will be no dialog prompt.

Usage Example:

jlink.open()
jlink.set_tif(pylink.enums.JLinkInterfaces.SWD)
jlink.set_unlock_idcode('00112233445566778899AABBCCDDEEFF')
jlink.connect('R7FS3A77C')

# Do something

jlink.close() # This causes unlock IDCODE hook to be reset back to the J-Link dialog prompt.

When jlink.set_unlock_idcode() is omitted, the user will get the default J-Link dialog prompt.

This was validated on a Renesas S3A7 device using Windows 11 x64 with J-Link V8.12f and an Intel macOS Sequoia with J-Link V8.14.

I tried to follow the contribution guidelines as best I could. I am all ears if you would like something changed. I ended up using a global string to store the IDCODE due to the hook callback. I didn't know how else to handle it.

Development was performed in Windows. I noticed a few issues with testing:

setuptools must be 71.1.0 or older. Otherwise I see

(.venv) C:\Users\jerem\Source\Repos\pylink-gui\libraries\pylink>python setup.py test
c:\Users\jerem\Source\Repos\pylink-gui\libraries\pylink\.venv\Lib\site-packages\setuptools\_distutils\dist.py:268: UserWarning: Unknown distribution option: 'test_suite'
  warnings.warn(msg)
c:\Users\jerem\Source\Repos\pylink-gui\libraries\pylink\.venv\Lib\site-packages\setuptools\_distutils\dist.py:268: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: setup.py --help [cmd1 cmd2 ...]
   or: setup.py --help-commands
   or: setup.py cmd --help

error: invalid command 'test'

coverage must be 4.5.2 or newer to show actual coverage. With current version 4.4.1, coverage isn't detected correctly. For example, pylink\unlockers\unlock_idcode.py is 36%. 4.5.2 is 96%.

@CLAassistant
Copy link

CLAassistant commented Mar 26, 2025

CLA assistant check
All committers have signed the CLA.

@hkpeprah hkpeprah self-requested a review March 27, 2025 19:56
Copy link
Contributor

@hkpeprah hkpeprah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! Left some comments when you have a chance to take a look.

callback_override = ctypes.CFUNCTYPE(None, ctypes.c_void_p)
function = ctypes.cast(function_ptr, callback_override)
function(self.unlock_idcode_cb)
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return

NIT: No need for the return at the very end.

import ctypes

# Global variable to store the ID code
global_id_code = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A global won't play well with multiple instances (e.g. if someone is debugging two chips at the same time). It looks like we need it for the callback in the dialog. Could we pass a partial function instead? That would allow us to prepopulate the id_code:

import functools


def set_unloock_idcode(self, id_code):
    partial = functools.partial(unlock_idcode_hook_dialog, id_code)
    unlock_idcode_cb = enums.JLinkFunctions.UNLOCK_IDCODE_HOOK_PROTOTYPE(partial)

global_id_code = None


def set_unlock_idcode(self, id_code):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename the self -> jlink like in unlock_kinetis?

global_id_code = id_code

self._dll.JLINK_GetpFunc.restype = ctypes.c_void_p
self.unlock_idcode_cb = enums.JLinkFunctions.UNLOCK_IDCODE_HOOK_PROTOTYPE(unlock_idcode_hook_dialog)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to bind the callback to the passed instance? It looks like we pass the value to the SET_HOOK_DIALOG function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants