PICkit 5 support (#1863)

This commit is contained in:
MX682X
2024-08-14 19:01:04 +02:00
committed by GitHub
parent 418e45492d
commit beaebd989c
12 changed files with 3386 additions and 2 deletions

View File

@@ -229,6 +229,10 @@ set(SOURCES
pgm_type.c
pickit2.c
pickit2.h
pickit5_updi_lut.c
pickit5_lut.h
pickit5.c
pickit5.h
pindefs.c
ppi.c
ppi.h

View File

@@ -156,6 +156,10 @@ libavrdude_la_SOURCES = \
pgm_type.c \
pickit2.c \
pickit2.h \
pickit5_updi_lut.c \
pickit5_lut.h \
pickit5.c \
pickit5.h \
pindefs.c \
ppi.c \
ppi.h \

View File

@@ -2948,9 +2948,8 @@ programmer # powerdebugger_tpi
# pickit4 / pickit4_jtag
#------------------------------------------------------------
# Microchip PICkit 4. See
# Microchip PICkit 4. For details see
# https://www.microchip.com/en-us/development-tool/pg164140
# for details.
#
# The PICkit 4 supports the following programming modes
# using different programmer names:
@@ -3055,6 +3054,44 @@ programmer # pickit4_tpi
usbpid = 0x2177, 0x2178, 0x2179;
;
# Microchip PICkit 5. For details, see
# https://www.microchip.com/en-us/development-tool/PG164150
#
# Currently -c pickit5 only supports UPDI programming
#
# PIN UPDI
# > 1 !RST(*)
# 2 VCC
# 3 GND
# 4 UPDI(*)
# 5
# 6
# 7
# 8
#
# (*): The PICkit5 can generate a High-Voltage (12V) Pulse on this pins
# to restore the UPDI Pin functionality, if it was changed through fuses.
# AVRDUDE automatically selects the correct pin, if the HV pulse is
# enabled through the '-x hvupdi' flag.
#------------------------------------------------------------
# pickit5 /pickit5_updi
#------------------------------------------------------------
programmer # pickit5_updi
id = "pickit5_updi";
desc = "MPLAB(R) PICkit 5, PICkit 4 and SNAP (PIC mode)";
type = "pickit5_updi";
prog_modes = PM_UPDI;
extra_features = HAS_VTARG_READ;
connection_type = usb;
baudrate = 200000; # UPDI default clock
usbvid = 0x04d8;
usbpid = 0x9036, 0x9012, 0x9018; # PK5, PK4 (pic mode), snap (pic mode)
hvupdi_support = 0, 1, 2;
;
#------------------------------------------------------------
# snap /snap_jtag
#------------------------------------------------------------

View File

@@ -325,6 +325,7 @@ See below for some hints about FLIP version 1 protocol behaviour.
The MPLAB(R) PICkit 4 and MPLAB(R) SNAP are supported in JTAG, TPI, ISP, PDI and UPDI mode.
The Curiosity Nano board is supported in UPDI mode. It is dubbed ``PICkit on
Board'', thus the name @code{pkobn_updi}.
The MPLAB(R) PICkit 5 is currently only supported in UPDI mode.
SerialUPDI programmer implementation is based on Microchip's
@emph{pymcuprog} (@url{https://github.com/microchip-pic-avr-tools/pymcuprog})
@@ -1305,6 +1306,27 @@ for switching to PIC mode.
Show help menu and exit.
@end table
@cindex Option @code{-x} PICkit 5
@item PICkit 5
@item PICkit 4 (PIC Mode)
The PICkit 5 and PICkit 4 (PIC Mode) programmer can accept following extended parameters
@table @code
@item @samp{vtarg=VALUE}
Specify a voltage between 1.8 and 5.5@w{ }V that the programmer should supply
to the target. If there is already a valid voltage applied to the VTG Pin,
this setting will be ignored. When AVRDUDE detects an external voltage outside
of this range, it will terminate the operation. You can disable this by
setting the voltage to 0@w{ }V.
@item @samp{hvupdi}
High-voltage UPDI programming is used to enable a UPDI pin that has previously
been set to RESET or GPIO mode. Use @samp{-x hvupdi} to enable high-voltage UPDI
initialization for supported targets. Depending on the target, the HV pulse will
be applied either on the RST pin, or the UPDI pin.
@item @samp{help}
Show help menu and exit.
@end table
@cindex Option @code{-x} Xplained Mini
@item Xplained Mini
@@ -2220,6 +2242,7 @@ Valid programmers for part AVR32EA32 are:
jtag2updi = JTAGv2 to UPDI bridge via UPDI
jtag3updi = Atmel AVR JTAGICE3 via UPDI
pickit4_updi = MPLAB(R) PICkit 4 via UPDI
pickit5_updi = MPLAB(R) PICkit 5, PICkit 4 and SNAP (PIC mode) via UPDI
pkobn_updi = Curiosity nano (nEDBG) via UPDI
powerdebugger_updi = Atmel PowerDebugger (ARM/AVR) via UPDI
serialupdi = SerialUPDI via UPDI

View File

@@ -1545,6 +1545,9 @@ skipopen:
else
imsg_error(" - use -B to set lower the bit clock frequency, e.g. -B 125kHz\n");
if (str_starts(pgm->type, "pickit5"))
imsg_error(" - reset the programmer by unplugging it");
if (!ovsigck) {
imsg_error(" - use -F to override this check\n");
exitrc = 1;

View File

@@ -46,6 +46,7 @@
#include "micronucleus.h"
#include "par.h"
#include "pickit2.h"
#include "pickit5.h"
#include "ppi.h"
#include "serbb.h"
#include "serialupdi.h"
@@ -99,6 +100,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th
{"micronucleus", micronucleus_initpgm, micronucleus_desc}, // "micronucleus" or "Micronucleus V2.0"
{"par", par_initpgm, par_desc}, // "PPI"
{"pickit2", pickit2_initpgm, pickit2_desc}, // "pickit2"
{"pickit5_updi", pickit5_initpgm, pickit5_desc}, // "pickit5"
{"serbb", serbb_initpgm, serbb_desc}, // "SERBB"
{"serialupdi", serialupdi_initpgm, serialupdi_desc}, // "serialupdi"
{"serprog", serprog_initpgm, serprog_desc}, // "serprog"

1410
src/pickit5.c Normal file

File diff suppressed because it is too large Load Diff

32
src/pickit5.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2024 MX682X
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pickit5_h
#define pickit5_h
#ifdef __cplusplus
extern "C" {
#endif
extern const char pickit5_desc[];
void pickit5_initpgm(PROGRAMMER *pgm);
#ifdef __cplusplus
}
#endif
#endif

83
src/pickit5_lut.h Normal file
View File

@@ -0,0 +1,83 @@
/* This file was auto-generated by scripts_decoder.py, any changes will be overwritten */
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2024 MX682X
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pickit5_lut_h
#define pickit5_lut_h
#ifdef __cplusplus
extern "C" {
#endif
struct avr_script_lut {
const unsigned char *EnterProgMode;
unsigned int EnterProgMode_len;
const unsigned char *EnterProgModeHvSp;
unsigned int EnterProgModeHvSp_len;
const unsigned char *EnterProgModeHvSpRst;
unsigned int EnterProgModeHvSpRst_len;
const unsigned char *EnterProgModeHvUpt;
unsigned int EnterProgModeHvUpt_len;
const unsigned char *ExitProgMode;
unsigned int ExitProgMode_len;
const unsigned char *SetSpeed;
unsigned int SetSpeed_len;
const unsigned char *GetDeviceID;
unsigned int GetDeviceID_len;
const unsigned char *EraseChip;
unsigned int EraseChip_len;
const unsigned char *WriteProgmem;
unsigned int WriteProgmem_len;
const unsigned char *ReadProgmem;
unsigned int ReadProgmem_len;
const unsigned char *WriteDataEEmem;
unsigned int WriteDataEEmem_len;
const unsigned char *ReadDataEEmem;
unsigned int ReadDataEEmem_len;
const unsigned char *WriteCSreg;
unsigned int WriteCSreg_len;
const unsigned char *ReadCSreg;
unsigned int ReadCSreg_len;
const unsigned char *WriteMem8;
unsigned int WriteMem8_len;
const unsigned char *ReadMem8;
unsigned int ReadMem8_len;
const unsigned char *WriteConfigmem;
unsigned int WriteConfigmem_len;
const unsigned char *ReadConfigmem;
unsigned int ReadConfigmem_len;
const unsigned char *WriteIDmem;
unsigned int WriteIDmem_len;
const unsigned char *ReadIDmem;
unsigned int ReadIDmem_len;
const unsigned char *ReadSIB;
unsigned int ReadSIB_len;
};
typedef struct avr_script_lut SCRIPT;
const unsigned char * get_devid_script_by_nvm_ver(unsigned char version);
int get_pickit_updi_script(SCRIPT *scr, const char *partdesc);
#ifdef __cplusplus
}
#endif
#endif // pickit5_lut_h

1110
src/pickit5_updi_lut.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@
#define USB_DEVICE_PICKIT4_AVR_MODE 0x2177
#define USB_DEVICE_PICKIT4_PIC_MODE 0x9012
#define USB_DEVICE_PICKIT4_PIC_MODE_BL 0x9017 // PICkit4 in bootloader mode
#define USB_DEVICE_PICKIT5 0x9036
#define USB_DEVICE_SNAP_AVR_MODE 0x2180
#define USB_DEVICE_SNAP_PIC_MODE 0x9018
#define USB_DEVICE_SNAP_PIC_MODE_BL 0x9019 // SNAP in bootloader mode

675
tools/scripts_decoder.py Normal file
View File

@@ -0,0 +1,675 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# avrdude - A Downloader/Uploader for AVR device programmers
# Copyright (C) 2024 MX682X
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# this is a small python sketch that tries to find the PICkit5_TP folder
# created by MPLAB X that contains the scripts.xml file.
# Works on Windows and Linux (MacOS untested), as long as the default installation
# folder was not changed. If it was changed, and the program is unable to locate
# the scripts.xml file, you should be promted to enter a path. You can
# either provide the path to the file, or to the directory providing the file.
#
# This file contains some functions that were used in initial develeopment
# but are not needed anymore. However, they might provide useful, thus they
# can be enabled by setting "user_input" to 1.
#
# The idea behind this program is to extract the sub-programs defined in the
# script.xml. The original file has a size of about 300MB, containing a lot of
# redundand information as well as sub-programs for chips avrdude doesn't
# support, like ARM MCUs.
# This python scripts iterates through all functions, removing identical ones,
# and indexes those. The index is then used to connect the MCUs with those functions
# so that the correct array pointers can be loaded.
# Warning: If you run this python program, the previously generated files will be
# overwritten without warning.
#
# As the XML file is fairly large, a machine with at least 16GB RAM is recommended
import os, fnmatch, mmap
from pathlib import Path
from xml.etree import ElementTree as ET
user_input = 0
# The list of functions, as a Python Dictionary, that will be used by avr-dude
# The complete list of available functions can be found below
c_dict = {
"EnterProgMode" : [],
"EnterProgModeHvSp" : [], # High Voltage Pulse on UPDI line
"EnterProgModeHvSpRst" : [], # High Voltage Pulse on Reset Pin
"EnterProgModeHvUpt" : [],
"ExitProgMode" : [],
"SetSpeed" : [],
"GetDeviceID" : [],
"EraseChip" : [],
"WriteProgmem" : [],
"ReadProgmem" : [],
"WriteDataEEmem" : [],
"ReadDataEEmem" : [],
"WriteCSreg" : [],
"ReadCSreg" : [],
"WriteMem8" : [],
"ReadMem8" : [],
"WriteConfigmem" : [],
"ReadConfigmem" : [],
"WriteIDmem" : [],
"ReadIDmem" : [],
"ReadSIB" : [],
}
# List of MCUs that should not end up in the lookup-table,
# preferably only those that are known not be released in the future
mcu_blacklist = [
"AVR16DV14", "AVR16DV20"
]
# A complete list of Functions defined in the scripts.xml
# This string was used to generate an intermediate python file
dict_header = \
'''
func_dict = {
"EnterProgMode" : [],
"EnterProgModeHvSp" : [],
"EnterProgModeHvSpRst" : [],
"EnterProgModeHvUpt" : [],
"ExitProgMode" : [],
"SetSpeed" : [],
"GetDeviceID" : [],
"EraseChip" : [],
"WriteProgmem" : [],
"ReadProgmem" : [],
"WriteDataEEmem" : [],
"ReadDataEEmem" : [],
"WriteConfigmem" : [],
"WriteConfigmemFuse" : [],
"WriteConfigmemLock" : [],
"ReadConfigmem" : [],
"ReadConfigmemFuse" : [],
"ReadConfigmemLock" : [],
"WriteIDmem" : [],
"ReadIDmem" : [],
"WriteCSreg" : [],
"ReadCSreg" : [],
"WriteMem8" : [],
"WriteMem16" : [],
"ReadMem8" : [],
"ReadMem16" : [],
"ReadSIB" : [],
"HoldInReset" : [],
"ReleaseFromReset" : [],
"EnterDebugMode" : [],
"EnterDebugModeHvSp" : [],
"EnterDebugModeHvSpRst" : [],
"EnterDebugModeHvUpt" : [],
"ExitDebugMode" : [],
"SetPC" : [],
"GetPC" : [],
"Run" : [],
"Halt" : [],
"DebugReset" : [],
"GetHaltStatus" : [],
"SingleStep" : [],
"SetHWBP" : [],
"ClearHWBP" : [],
}\n
'''
import platform
work_dir = os.path.abspath(os.getcwd())
cache_dir = os.path.join(work_dir, "scripts_cache")
print(work_dir)
print(cache_dir)
# Tries to locate the xml file in a known location
def find_xml():
home_dir = str(Path.home())
print("Home Path: {0}".format(home_dir))
if home_dir == None:
return
home_dir = os.path.join(home_dir, ".mchp_packs", "Microchip")
home_dir_A = os.path.join(home_dir, "PICkit5_TP")
result = []
for root, dirs, files in os.walk(home_dir_A):
for name in files:
if fnmatch.fnmatch(name, "scripts.xml"):
result.append(os.path.join(root, name))
print("List of scripts.xml files:")
print(result)
return result[-1]
# EOF
# extracts only the functions from the scripts.xml that end with "UPDI"
def cache_xml(file):
if file == None:
return
print("Opening file {0}".format(file))
global cache_dir
origin_tree = ET.parse(file)
origin_root = origin_tree.getroot()
work_root = ET.Element("scripts")
old_chip_name = ""
print("List of UPDI MCUs:")
for script in origin_root.findall('script'):
function_name = script[0].text # the function name is always on the first place
if (function_name.endswith("UPDI")):
chip_name = script[1].text
if (old_chip_name != chip_name):
print(chip_name)
old_chip_name = chip_name
work_root.append(script) # copy UPDI entries to our working element
work_tree = ET.ElementTree(work_root)
work_tree.write(os.path.join(cache_dir, "scripts_updi.xml"))
# EOF
# generates a python file out of the reduced scripts.xml file
def decode_xml_cache(xml_path):
global cache_dir
dict_path = os.path.join(cache_dir, "scripts_dict.py")
xml_tree = ET.parse(xml_path)
xml_root = xml_tree.getroot()
if (os.path.exists(dict_path)):
os.remove(dict_path)
with open(dict_path, 'w') as dict_file:
dict_list = []
dict_iterator = -1
old_chip_name = ""
old_function_name = ""
for script in xml_root:
function_string = ""
function_name = script[0].text
chip_name = script[1].text
if (old_chip_name != chip_name):
if (dict_iterator >= 0):
dict_list[dict_iterator] += " },\n" # trailing bracket
print("{0} generated".format(old_chip_name))
dict_iterator += 1
dict_list.append("")
dict_list[dict_iterator] = " \"{0}\" : ".format(chip_name) # thisdict : {
dict_list[dict_iterator] += "{\n"
old_chip_name = chip_name
if (old_function_name != function_name):
dict_list[dict_iterator] += " \"{0}\" : ".format(function_name[0:-5]) # "function_name" :
old_function_name = function_name
scrbytes = script[3]
for bytes in scrbytes:
function_string += bytes.text
function_string += ", "
dict_list[dict_iterator] += "[{0}],\n".format(function_string[0:-2]) # "function string",
dict_file.write(dict_header)
dict_file.write("scripts = {\n")
for x in range (dict_iterator):
dict_file.write(dict_list[x]) # store decoded dictionary
dict_file.write("}")
# tries to reduce file size, reuires the previous function to be executed
# in order to provide the python file
def optimize_dict():
import scripts_cache.scripts_dict as dict
global cache_dir
for chip_name in dict.scripts: # Go through every chip
for func_name in dict.scripts[chip_name]: # Go through every function for each chip
if func_name in dict.func_dict: # Only handle the function if we care
func_array = dict.func_dict[func_name] # Use the array
position = -1
for x in range (len(func_array)): # go through
if func_array[x] == dict.scripts[chip_name][func_name]:
position = x
break
if position >= 0:
dict.scripts[chip_name][func_name] = position
else:
func_array.append(dict.scripts[chip_name][func_name])
dict.scripts[chip_name][func_name] = position + 1
lut_path = os.path.join(cache_dir, "scripts_lut.py")
if (os.path.exists(lut_path)):
os.remove(lut_path)
with open(lut_path, 'w') as lut_file: # Create file
lut_file.write("func_dict = {\n") # start with function look-up Table
for func in dict.func_dict:
lut_file.write(" \"{0}\" : [\n".format(func)) # function start
func_array = dict.func_dict[func]
for array_elem in func_array: # function list start
func_string = " ["
for i in array_elem: # iterate through the sub-function elements
func_string += "0x{0:02X}, ".format(i) # format for readability
func_string += "],\n" # end of sub-function
lut_file.write(func_string) # write to file
lut_file.write(" ],\n") # end of function
lut_file.write("}\n\n\n") # end of lut
lut_file.write("scripts = {\n")
for chip_name in dict.scripts: # Go through every chip
lut_file.write(" \""+ chip_name + "\" : {\n")
for func_name in dict.scripts[chip_name]: # Go through every function for each chip
lut_file.write(" \"{0}\" : {1},\n".format(func_name, dict.scripts[chip_name][func_name]))
lut_file.write(" },\n")
lut_file.write("}") # close dict
print("done")
#EOF
# Beginning of C and H Files
common_header = \
'''/* This file was auto-generated by scripts_decoder.py, any changes will be overwritten */
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2024 MX682X
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'''
# generates the h-file. generates the struct definition
def generate_h_file(c_dict, file_dir):
h_header = \
'''
#ifndef pickit5_lut_h
#define pickit5_lut_h
#ifdef __cplusplus
extern "C" {
#endif
struct avr_script_lut {
'''
h_trailer = \
'''
};
typedef struct avr_script_lut SCRIPT;
const unsigned char * get_devid_script_by_nvm_ver(unsigned char version);
int get_pickit_updi_script(SCRIPT *scr, const char *partdesc);
#ifdef __cplusplus
}
#endif
#endif // pickit5_lut_h
'''
global common_header
if file_dir is None:
return
h_lut_path = os.path.join(file_dir, "pickit5_lut.h") # first - handle defining the structure
if (os.path.exists(h_lut_path)):
os.remove(h_lut_path)
with open(h_lut_path, 'w') as h_file:
h_file.write(common_header)
h_file.write(h_header)
for func_name in c_dict:
h_file.write(" const unsigned char *{0};\n unsigned int {0}_len;\n".format(func_name))
h_file.write(h_trailer)
print("h-File generated")
#EOF
# generates the c-file out of a previously generated python file
def generate_c_file(c_dict, file_dir):
import scripts_cache.scripts_lut as lut
if file_dir is None:
return
c_lut_path = os.path.join(file_dir, "pickit5_lut.c")
if (os.path.exists(c_lut_path)):
os.remove(c_lut_path)
with open(c_lut_path, 'w') as c_file:
non_unique_func = []
c_file.write("/* this file was auto-generated */\n")
c_file.write("#include <ac_cfg.h>\n")
c_file.write("#include <stddef.h>\n")
c_file.write("#include <string.h>\n")
c_file.write("#include \"pickit5_lut.h\"\n\n\n")
struct_init_func = ""
struct_init_len = ""
for func_name in lut.func_dict: # for each function in our database
if func_name in c_dict: # if the function exists in our c-list
function = lut.func_dict[func_name] # load data associated with the function
array_iterator = 0
for array in function: # for each array in function
array_str = "const unsigned char {0}_{1}[{2}]".format(func_name, array_iterator, len(array))
array_str += " = {\n " # begin array
for i in range (len(array)): # go through every byte
array_str += "0x{0:02x}, ".format(array[i]) # and generate String
array_str += "\n};\n" # complete array
array_iterator += 1
c_file.write(array_str)
if array_iterator == 1:
struct_init_func += " .{0} = {0}_0,\n".format(func_name)
struct_init_len += " .{0}_len = sizeof({0}_0),\n".format(func_name)
else:
struct_init_func += " .{0} = NULL,\n".format(func_name)
struct_init_len += " .{0}_len = 0,\n".format(func_name)
non_unique_func.append(func_name)
c_file.write("\n\n\nstruct avr_script_lut avr_scripts = {\n")
c_file.write(struct_init_func)
c_file.write(struct_init_len)
c_file.write("};\n\n\n")
chip_lut_str = "const char *chip_lut[] = {\n "
chip_name_iterator = 0
for chip_name in lut.scripts:
chip_lut_str += "\""
chip_lut_str += chip_name
chip_lut_str += "\", "
chip_name_iterator += 1
if chip_name_iterator % 8 == 0:
chip_lut_str += "\n "
chip_lut_str += "\n};\n\n\n"
c_file.write(chip_lut_str)
c_func_str = "struct avr_script_lut* get_pickit_script(const char* partdesc) { \n"
c_func_str += " int namepos = -1;\n"
c_func_str += " for (int i = 0; i < {0}; i++)".format(chip_name_iterator)
c_func_str += " {\n"
c_func_str += " if (strncmp(chip_lut[i], partdesc, 10) == 0) {\n"
c_func_str += " namepos = i;\n break;\n }\n }\n"
c_func_str += " if (namepos == -1) {\n return NULL;\n }\n"
c_file.write(c_func_str)
switch_iterator = 0
c_file.write(" switch (namepos) {\n")
for chip_name in lut.scripts:
case_str = " case {0}:\n".format(switch_iterator)
chip_func = lut.scripts[chip_name]
for func_lut in chip_func:
if func_lut in non_unique_func:
case_str += " avr_scripts.{0} = {0}_{1};\n".format(func_lut, chip_func[func_lut])
case_str += " avr_scripts.{0}_len = sizeof({0}_{1});\n".format(func_lut, chip_func[func_lut])
case_str += " break;\n"
switch_iterator += 1
c_file.write(case_str)
c_file.write(" }\n return &avr_scripts;\n }")
print("c-File generated")
#EOF
def convert_to_c(c_dict, file_dir):
generate_h_file(c_dict, file_dir)
generate_c_file(c_dict, file_dir)
#EOF
# A sum of the previous functions, generating the c/h files
# without needing any intermediate files
def convert_xml(xml_path, c_dict):
if xml_path == None:
print("No Path to XML file provided")
return
mcu_dict = dict()
# Prepare directories
parent_dir = os.getcwd()
src_dir = os.path.join(parent_dir, "src")
print("Opening file {0}".format(xml_path))
print("Parent Dir: {0}".format(parent_dir))
print("Src directory: {0}".format(src_dir))
# open XML file
origin_tree = ET.parse(xml_path)
origin_root = origin_tree.getroot()
work_root = ET.Element("scripts")
print ("XML File loaded")
# scan scripts file
for script in origin_root.findall('script'):
function_name = script[0].text # the function name is always on the first place
if (function_name.endswith("UPDI")): # We're only intrested in UPDI functions
function_name = function_name[0:-5] # remove "_UPDI" from function name
if (function_name in c_dict): # filter out unneded functions
chip_name = script[1].text # get chip name
if (chip_name in mcu_blacklist): # filter out chips in blacklist
continue
if (chip_name not in mcu_dict):
mcu_dict[chip_name] = dict()
if (function_name not in mcu_dict[chip_name]):
mcu_dict[chip_name][function_name] = []
scrbytes = script[3]
for bytes in scrbytes:
mcu_dict[chip_name][function_name].append(int(bytes.text, 16))
# the mcu dict has following layout "mcu_name" : "function1" : [], "function2" : []
print("XML File processed")
# reorder mcu_dict to a func_dict
func_dict = dict()
for mcu_name in mcu_dict: # Go through every MCU
for function_name in mcu_dict[mcu_name]: # Go through every Function for every CPU
if (function_name not in func_dict):
func_dict[function_name] = []
funct_bytes = mcu_dict[mcu_name][function_name] # get Function bytes
entries = len(func_dict[function_name])
for x in range (entries + 1): # try to find an existing entry
if x == entries: # if we reached the end
func_dict[function_name].append(funct_bytes) # add an entry to our dict
mcu_dict[mcu_name][function_name] = x # remember the postion in dict
break
if func_dict[function_name][x] == funct_bytes: # if match found
mcu_dict[mcu_name][function_name] = x # remember the postion
break
# the funct dict has following layout: "function1" : [[], []], "function2" : [[], []],
# the mcu dict has following layout "mcu_name" : "function1" : 1, "function2" : 0
# create h-File
generate_h_file(c_dict, src_dir)
# create c-File
global common_header
c_lut_path = os.path.join(src_dir, "pickit5_updi_lut.c")
if (os.path.exists(c_lut_path)):
os.remove(c_lut_path)
with open(c_lut_path, 'w') as c_file:
non_unique_func = []
c_file.write(common_header)
c_file.write("#include <ac_cfg.h>\n")
c_file.write("#include <stddef.h>\n")
c_file.write("#include <string.h>\n")
c_file.write("#include \"pickit5_lut.h\"\n\n\n")
# Generate the arrays for the functions
struct_init_func = ""
struct_init_len = ""
for func_name in func_dict: # for each function in our database
function = func_dict[func_name] # load data associated with the function
array_iterator = 0
for array in function: # for each array in function
array_str = "const unsigned char {0}_{1}[{2}]".format(func_name, array_iterator, len(array))
array_str += " = {" # begin array
for i in range (len(array)): # go through every byte
if (i % 16 == 0):
array_str += "\n " # new line after 16 bytes
array_str += "0x{0:02x}, ".format(array[i]) # and generate String
array_str += "\n};\n\n" # complete array
array_iterator += 1
c_file.write(array_str)
if array_iterator == 1:
struct_init_func += " scr->{0} = {0}_0;\n".format(func_name)
struct_init_len += " scr->{0}_len = sizeof({0}_0);\n".format(func_name)
else:
struct_init_func += " scr->{0} = NULL;\n".format(func_name)
struct_init_len += " scr->{0}_len = 0;\n".format(func_name)
non_unique_func.append(func_name)
c_file.write("\n\n\nstatic void pickit_updi_script_init(SCRIPT *scr);\n") # declaration
c_file.write("static void pickit_updi_script_init(SCRIPT *scr) {\n") # definition
c_file.write(struct_init_func)
c_file.write("\n") # improve readability
c_file.write(struct_init_len)
c_file.write("}\n\n\n")
# Lookup Table for Chip Names
chip_lut_str = "const char * const pickit5_updi_chip_lut[] = {\n "
chip_name_iterator = 0
for chip_name in mcu_dict:
chip_lut_str += "\""
chip_lut_str += chip_name
chip_lut_str += "\", "
chip_name_iterator += 1
if chip_name_iterator % 8 == 0:
chip_lut_str += "\n "
chip_lut_str += "\n};\n\n\n"
c_file.write(chip_lut_str)
# Provide a way to get the DevID Script by NVM Version stored in SIB
devid_str = "const unsigned char * get_devid_script_by_nvm_ver(unsigned char version) {\n"
devid_str += " if (version >= '0') version -= '0'; // allow chars\n"
devid_str += " if (version > 9) return NULL; // Not a valid number\n"
devid_str += " if (version <= 3) // tiny, mega, DA, DB, DD, EA\n"
devid_str += " return GetDeviceID_0;\n"
devid_str += " else // DU, EB\n"
devid_str += " return GetDeviceID_1;\n}\n\n"
c_file.write(devid_str)
# Main Function to load the data into the structure
c_func_str = "int get_pickit_updi_script(SCRIPT *scr, const char* partdesc) { \n"
c_func_str += " if ((scr == NULL) || (partdesc == NULL))\n return -1;\n\n"
c_func_str += " int namepos = -1;\n"
c_func_str += " for (int i = 0; i < {0}; i++)".format(chip_name_iterator)
c_func_str += " {\n"
c_func_str += " if (strncmp(pickit5_updi_chip_lut[i], partdesc, 10) == 0) {\n"
c_func_str += " namepos = i;\n break;\n }\n }\n"
c_func_str += " if (namepos == -1) {\n return -2;\n }\n\n"
c_func_str += " pickit_updi_script_init(scr); // load common functions\n\n"
c_file.write(c_func_str)
switch_iterator = 0
c_file.write(" switch (namepos) {\n")
case_str_list = []
break_str_list = []
for chip_name in mcu_dict:
case_str_list.append("")
break_str_list.append("")
case_str_list[switch_iterator] = " case {0}: /* {1} */\n".format(switch_iterator, chip_name)
chip_func = mcu_dict[chip_name]
for func_lut in chip_func:
if func_lut in non_unique_func:
break_str_list[switch_iterator] += " scr->{0} = {0}_{1};\n".format(func_lut, chip_func[func_lut])
break_str_list[switch_iterator] += " scr->{0}_len = sizeof({0}_{1});\n".format(func_lut, chip_func[func_lut])
break_str_list[switch_iterator] += " break;\n"
switch_iterator += 1
for x in range (0, switch_iterator):
if (case_str_list[x] != ""): # ignore already "filtered" out cases
file_str = case_str_list[x] # start with a case
temp_str = break_str_list[x] # buffer the content of the case
for y in range(x + 1, switch_iterator): # go through all future entries
if temp_str == break_str_list[y]: # if we find one that is identical
file_str += case_str_list[y] # add it to the case at the beginning
case_str_list[y] = "" # clear case entry
break_str_list[y] = "" # clear content entry to speed up filtering
file_str += temp_str # add the content of the case
c_file.write(file_str)
c_file.write(" }\n return 0;\n}")
print("c-File generated")
pass
if not user_input:
xml_path = find_xml()
if xml_path == None:
print("Unable to find scripts.xml in the default location.")
print("Please Enter a Path to the File or Directory:")
xml_path = input(">")
if (os.path.isdir(xml_path)):
os.path.join(xml_path, "scripts.xml")
if (os.path.exists(xml_path) == False):
print("File not found, exiting")
quit()
convert_xml(xml_path, c_dict)
quit()
while user_input:
user_in = input(">")
if (user_in == "cache"):
xml_path = find_xml()
cache_xml(xml_path)
elif (user_in == "decode"):
xml_path = os.path.join(cache_dir, "scripts_updi.xml")
decode_xml_cache(xml_path)
elif (user_in == "optimize"):
optimize_dict()
elif (user_in == "cfy"):
convert_to_c(c_dict, cache_dir)
elif (user_in == "dude"):
xml_path = find_xml()
if xml_path == None:
print("Unable to find scripts.xml in the default location.")
print("Please Enter a Path to the File or Directory:")
xml_path = input(">")
if (os.path.isdir(xml_path)):
os.path.join(xml_path, "scripts.xml")
if (os.path.exists(xml_path) == False):
print("File not found, exiting")
quit()
convert_xml(xml_path, c_dict)
quit()
pass