Skip to content
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

Bugfix/issue#266 cmdjlink permission denied #295

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,11 @@ recipe.size.regex.data=^(?:\.data|\.VENEER_Code|\.ram_code|\.bss|\.no_init|\Stac
tools.xmcflasher.path={runtime.platform.path}/tools
tools.xmcflasher.cmd.path={path}/xmc-flasher.py
tools.xmcflasher.erase.params=-d XMC{build.board.version}-{build.board.v} -p {serial.port}
tools.xmcflasher.erase.pattern=python {cmd.path} erase {upload.params}
tools.xmcflasher.erase.pattern=python3 {cmd.path} erase {erase.params}
tools.xmcflasher.erase.pattern.windows=python {cmd.path} erase {erase.params}
tools.xmcflasher.upload.protocol=
tools.xmcflasher.upload.params.verbose=
tools.xmcflasher.upload.params.verbose=--verbose
tools.xmcflasher.upload.params.quiet=
tools.xmcflasher.upload.params=-d XMC{build.board.version}-{build.board.v} -p {serial.port} -f {build.path}/{build.project_name}.hex
tools.xmcflasher.upload.pattern=python {cmd.path} upload {upload.params}
tools.xmcflasher.upload.params=-d XMC{build.board.version}-{build.board.v} -p {serial.port} -f {build.path}/{build.project_name}.hex {upload.verbose}
tools.xmcflasher.upload.pattern=python3 {cmd.path} upload {upload.params}
tools.xmcflasher.upload.pattern.windows=python {cmd.path} upload {upload.params}
75 changes: 50 additions & 25 deletions tools/xmc-flasher.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import argparse, subprocess, os, sys, re, warnings
import argparse, subprocess, os, sys, re, warnings, tempfile
from serial.tools.list_ports import comports
from xmc_data import xmc_master_data

version = '0.1.1'
version = '0.1.2'

jlinkexe = ''

# Set temporary file for jlink command file and output file
cmd_jlink = os.path.join(tempfile.gettempdir(), 'cmd.jlink')
console_out = os.path.join(tempfile.gettempdir(), 'console.output')

def check_python_version():
major = sys.version_info.major
minor = sys.version_info.minor
Expand All @@ -31,9 +35,7 @@ def set_environment():
elif sys.platform == 'win32' or sys.platform == 'cygwin':
jlinkexe = rf"{get_jlink_install_path()}\jlink.exe"
elif sys.platform == 'darwin':
jlinkexe = 'jlink'
print('warning: mac os not validated')
#raise Exception('mac os not supported?')
jlinkexe = 'JLinkExe'

def discover_devices():
ports = comports()
Expand All @@ -46,21 +48,18 @@ def discover_devices():
def get_device_serial_number(port):
port_sn_list = discover_devices()
for device in port_sn_list:
if device[0] == port:
return device[1]

if device[0] == port and device[0] != None:
return device[1]
return None

def create_jlink_loadbin_command_file(binfile):
cmd_jlink = 'cmd.jlink'
cmd_load_bin = 'loadbin ' + binfile + ' 0x0\n'
with open(cmd_jlink,'w') as f:
f.writelines(['r\n', 'h\n', cmd_load_bin, 'r\n', 'g\n', 'exit\n'])

return cmd_jlink

def create_jlink_mem_read_command_file(addr, bytes):
cmd_jlink = 'cmd.jlink'
#cmd_log_enable
cmd_mem_read = 'mem ' + addr +', '+ bytes + '\n' # todo: store register maps, bytes in file
with open(cmd_jlink,'w') as f:
Expand All @@ -69,7 +68,6 @@ def create_jlink_mem_read_command_file(addr, bytes):
return cmd_jlink

def create_jlink_erase_command_file():
cmd_jlink = 'cmd.jlink'
with open(cmd_jlink,'w') as f:
f.writelines(['r\n', 'h\n', 'erase\n', 'exit\n'])

Expand All @@ -93,7 +91,7 @@ def jlink_commander(device, serial_num, cmd_file, console_output=False):
jlink_proc = subprocess.Popen(jlink_cmd, stdout=subprocess.PIPE, universal_newlines=True)
if console_output is True:
out, err = jlink_proc.communicate()
with open('console.output', 'w') as f:
with open(console_out, 'w') as f:
f.write(out)
else:
for line in jlink_proc.stdout:
Expand All @@ -103,26 +101,33 @@ def jlink_commander(device, serial_num, cmd_file, console_output=False):
raise Exception("jlink error")

def process_console_output(string):
with open('console.output','r') as f:
with open(console_out,'r') as f:
lines = f.readlines()
lines[0].split('\n')

for line in lines :
if string in line and '=' in line:
print(line)

def check_serial_number(serial_num):
if serial_num == None:
raise Exception("Device not found! Please check the serial port")

def get_mem_contents(addr, bytes, device, port):

serial_num = get_device_serial_number(port)
try:
serial_num = get_device_serial_number(port)
check_serial_number(serial_num)
except ValueError as e:
print(e)
jlink_cmd_file = create_jlink_mem_read_command_file(addr, bytes) # todo: comes from proper metafile
jlink_commander(device, serial_num, jlink_cmd_file, True)
remove_jlink_command_file(jlink_cmd_file)

with open('console.output','r') as f:
with open(console_out,'r') as f:
lines = f.readlines()
lines[0].split('\n')

remove_console_output_file('console.output')
remove_console_output_file(console_out)

reg_contents = ""
for line in lines :
Expand Down Expand Up @@ -151,14 +156,13 @@ def check_device(device, port):
device_value_masked = f'{device_value_masked:x}'
device_value_masked = device_value_masked.zfill(int(master_data[device]['IDCHIP']['size'])*2)

print(f"Device is: {device.split('-')[0]}")
print(f"Device is: {device.split('-')[0]}.")

#compare with stored master data
if not device_value_masked == master_data[device]['IDCHIP']['value']:
raise Exception("Device connected does not match the selected device to flash")



def check_mem(device, port):

if "XMC1" in device:
Expand All @@ -170,7 +174,7 @@ def check_mem(device, port):
flash_size = (device_value-1)*4 #flash size given by (ADDR-1)*4
flash_size = str(flash_size).zfill(4)

print(f"Flash size is: {int(flash_size)}kB")
print(f"Flash size is: {int(flash_size)}kB.")

# special case for XMC2GO-32kB variant, bypass check
if "XMC1100" in device and int(flash_size) == 32:
Expand All @@ -194,10 +198,10 @@ def check_mem(device, port):
raise Exception("Memory size of device connected does not match that of the selected device to flash")


def upload(device, port, binfile):
def upload(device, port, binfile, enable_jlink_log):
serial_num = get_device_serial_number(port)
jlink_cmd_file = create_jlink_loadbin_command_file(binfile)
jlink_commander(device, serial_num, jlink_cmd_file)
jlink_commander(device, serial_num, jlink_cmd_file, console_output=not enable_jlink_log) # console_output = true will store the log to file instead of printing
remove_jlink_command_file(jlink_cmd_file)

def erase(device, port):
Expand All @@ -217,7 +221,21 @@ def main_parser_func(args):
def parser_upload_func(args):
check_device(args.device, args.port)
check_mem(args.device, args.port)
upload(args.device, args.port, args.binfile)
upload(args.device, args.port, args.binfile, args.verbose)
# remove console output file if verbose is not enabled
if not args.verbose:
# check if upload was successful by parsing the console output
with open(console_out, 'r') as f:
found_loadbin = False
for line in f:
if "J-Link>loadbin" in line:
found_loadbin = True
elif found_loadbin and "O.K." in line:
print("Upload successful.")
break
else:
print("Upload failed.")
remove_console_output_file(console_out)

def parser_erase_func(args):
erase(args.device, args.port)
Expand All @@ -242,9 +260,10 @@ def __call__(self, parser, namespace, values, option_string, **kwargs):
required_upload.add_argument('-d','--device', type=str, help='jlink device name', required=True)
required_upload.add_argument('-p','--port', type=str, help='serial port', required=True)
required_upload.add_argument('-f','--binfile', type=str, help='binary file to upload', required=True)
required_upload.add_argument('--verbose', action='store_true', help='Enable verbose logging')
parser_upload.set_defaults(func=parser_upload_func)

# Debug parser
# Erase parser
parser_erase = subparser.add_parser('erase', description='erase command')
required_erase = parser_erase.add_argument_group('required arguments')
required_erase.add_argument('-d','--device', type=str, help='jlink device name', required=True)
Expand All @@ -254,8 +273,14 @@ def __call__(self, parser, namespace, values, option_string, **kwargs):
# debug_parser.
# TBD in future

# Parser call
# Parse arguments
args = parser.parse_args()
# Set traceback limit based on the --verbose argument
if args.verbose:
sys.tracebacklimit = None # Enable full traceback
else:
sys.tracebacklimit = 0 # Disable traceback
# Parser call
args.func(args)

if __name__ == "__main__":
Expand Down
Loading