From 381be4eccb0a1369140025b7733492e7e40830dd Mon Sep 17 00:00:00 2001 From: Pat Deegan Date: Sun, 5 Feb 2023 11:14:06 -0500 Subject: [PATCH] Added support for arbitrary/custom fields in part description, along with an example. --- docs/example-with-customfields.csv | 29 +++++++++++++++++++++ kipart/common.py | 34 +++++++++++++++++++++++-- kipart/generic_reader.py | 7 ++--- kipart/kipart.py | 41 ++++++++++++++++++++++++++++++ kipart/lattice_reader.py | 4 ++- kipart/xilinx6s_reader.py | 4 +-- kipart/xilinx6v_reader.py | 5 ++-- kipart/xilinx7_reader.py | 5 ++-- kipart/xilinxultra_reader.py | 5 ++-- 9 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 docs/example-with-customfields.csv diff --git a/docs/example-with-customfields.csv b/docs/example-with-customfields.csv new file mode 100644 index 0000000..2699939 --- /dev/null +++ b/docs/example-with-customfields.csv @@ -0,0 +1,29 @@ +SEDFXTP_4,U,,sedfxtp_4,https://skywater-pdk.readthedocs.io/en/main/contents/libraries.html,sky130_fd_sc_hd__sedfxtp_4,"Spice_Primitive=X +Spice_Model=sky130_fd_sc_hd__sedfxtp_4 +Spice_Netlist_Enabled=Y +Spice_Lib_File=sky130_fd_sc_hd.spice" +Pin,Name,Type,Style,Side +1,CLK,input,clock,left +2,D,input,line,left +3,DE,input,line,left +4,SCD,input,line,left +5,SCE,input,line,left +6,VGND,power_in,line,bottom +7,VNB,power_in,line,bottom +8,VPB,power_in,line,top +9,VPWR,power_in,line,top +10,Q,output,line,right + +XOR3_1,U,,xor3_1,https://skywater-pdk.readthedocs.io/en/main/contents/libraries.html,sky130_fd_sc_hd__xor3_1,"Spice_Primitive=X +Spice_Model=sky130_fd_sc_hd__xor3_1 +Spice_Netlist_Enabled=Y +Spice_Lib_File=sky130_fd_sc_hd.spice" +Pin,Name,Type,Style,Side +1,A,input,line,left +2,B,input,line,left +3,C,input,line,left +4,VGND,power_in,line,bottom +5,VNB,power_in,line,bottom +6,VPB,power_in,line,top +7,VPWR,power_in,line,top +8,X,output,line,right diff --git a/kipart/common.py b/kipart/common.py index a4af70e..4d325f7 100644 --- a/kipart/common.py +++ b/kipart/common.py @@ -80,6 +80,30 @@ def get_nonblank_row(csv_reader): return [] + +def parse_part_customfields(customfieldsstr): + """ allows you to have a cell in the csv with multiple arbitrary entries. + Distinct entries seperated by ";" or newline. + Key=Value pairs seperated by "=" or tab. + + So an entry could be + Booya=base; + Funky=Fresh + Sloppy=Joe + which would create 3 custom fields (Booya, Funky and Sloppy) + """ + pairsFound = [] + for custfpair in re.split(r'\r\n|\r|\n|;|\|', customfieldsstr): + if custfpair is None or not len(custfpair): + continue + mtchs = re.search(r'([^=\t]+)(=|\t)([^=\t]+)', custfpair) + if mtchs is None: + continue + + pairsFound.append([mtchs[1], mtchs[3]]) + + return pairsFound + def get_part_info(csv_reader): """Get the part number, ref prefix, footprint, MPN, datasheet link, and description from a row of the CSV file.""" @@ -91,12 +115,17 @@ def get_part_info(csv_reader): part_manf_num, part_datasheet, part_desc, - ) = list(get_nonblank_row(csv_reader) + [None] * 6)[:6] + custom_fields, + ) = list(get_nonblank_row(csv_reader) + [None] * 7)[:7] # Put in the default part reference identifier if it isn't present. if part_ref_prefix in (None, "", " "): part_ref_prefix = "U" - + + part_customfields = [] + if custom_fields is not None and len(custom_fields): + part_customfields = parse_part_customfields(custom_fields) + # Check to see if the row with the part identifier is missing. if part_num and part_num.lower() in list(COLUMN_NAMES.keys()): issue("Row with part number is missing in CSV file.", "error") @@ -108,6 +137,7 @@ def get_part_info(csv_reader): part_manf_num, part_datasheet, part_desc, + part_customfields, ) diff --git a/kipart/generic_reader.py b/kipart/generic_reader.py index 5f7556f..7935574 100644 --- a/kipart/generic_reader.py +++ b/kipart/generic_reader.py @@ -76,6 +76,7 @@ def generic_reader(part_data_file, part_data_file_name, part_data_file_type): part_manf_num, part_datasheet, part_desc, + part_cust_fields, ) = get_part_info(csv_reader) if part_num is None: break @@ -126,7 +127,7 @@ def generic_reader(part_data_file, part_data_file_name, part_data_file_type): # Place all the like-named pins into a list under their common name. # We'll unbundle them later, if necessary. pin_data[pin.unit][pin.side.lower()][pin.name].append(pin) - - yield part_num, part_ref_prefix, part_footprint, part_manf_num, part_datasheet, part_desc, pin_data # Return the dictionary of pins extracted from the CSV file. - + + yield part_num, part_ref_prefix, part_footprint, part_manf_num, part_datasheet, part_desc, pin_data, part_cust_fields # Return the dictionary of pins extracted from the CSV file. + part_data_file.close() diff --git a/kipart/kipart.py b/kipart/kipart.py index 7b4e23b..edb8e2e 100644 --- a/kipart/kipart.py +++ b/kipart/kipart.py @@ -103,6 +103,15 @@ PART_DESC_SIZE = 50 # Font size. PART_DESC_Y_OFFSET = -500 + +# Part custom fields +PART_CUSTFIELD_SIZE = 25 +PART_CUSTFIELD_Y_OFFSET = -550 +PART_CUSTFIELD_Y_INCREMENT = -50 + + + + # Mapping from understandable pin orientation name to the orientation # indicator used in the KiCad part library. This mapping looks backward, # but if pins are placed on the left side of the symbol, you actually @@ -232,6 +241,9 @@ DATASHEET_FIELD = 'F3 "{datasheet}" {x} {y} {font_size} H I {text_justification} CNN\n' MPN_FIELD = 'F4 "{manf_num}" {x} {y} {font_size} H I {text_justification} CNN "manf#"\n' DESC_FIELD = 'F5 "{desc}" {x} {y} {font_size} H I {text_justification} CNN "desc"\n' +PARTCUSTOM_FIELD_STARTFIELDID=6 +PARTCUSTOM_FIELD = 'F{fieldid} "{customcontents}" {x} {y} {font_size} H I {text_justification} CNN "{customfieldname}"\n' + START_DRAW = "DRAW\n" END_DRAW = "ENDDRAW\n" @@ -534,6 +546,7 @@ def draw_symbol( part_datasheet, part_desc, pin_data, + part_customfields, sort_type, reverse, fuzzy_match, @@ -774,6 +787,32 @@ def draw_symbol( text_justification=text_justification, font_size=PART_DESC_SIZE, ) + + + if part_customfields and len(part_customfields): + curFieldId = PARTCUSTOM_FIELD_STARTFIELDID + curYOffest = PART_CUSTFIELD_Y_OFFSET + for field in part_customfields: + fieldname = field[0] + fieldvalue = field[1] + if fieldname is None or not len(fieldname): + continue + + if fieldvalue is None: + fieldvalue = '' + part_defn += PARTCUSTOM_FIELD.format( + fieldid=curFieldId, + customcontents=fieldvalue, + customfieldname=fieldname, + + x=XO + horiz_offset, + y=YO + curYOffest + vert_offset, + text_justification=text_justification, + font_size=PART_DESC_SIZE, + + ) + curYOffest += PART_CUSTFIELD_Y_INCREMENT + curFieldId += 1 # Start the section of the part definition that holds the part's units. part_defn += START_DRAW @@ -912,6 +951,7 @@ def kipart( part_datasheet, part_desc, pin_data, + part_customfields ) in part_reader(part_data_file, part_data_file_name, part_data_file_type): # Handle retaining/overwriting parts that are already in the library. @@ -933,6 +973,7 @@ def kipart( part_datasheet=part_datasheet, part_desc=part_desc, pin_data=pin_data, + part_customfields=part_customfields, sort_type=sort_type, reverse=reverse, fuzzy_match=fuzzy_match, diff --git a/kipart/lattice_reader.py b/kipart/lattice_reader.py index fb2faf8..ae85dbc 100644 --- a/kipart/lattice_reader.py +++ b/kipart/lattice_reader.py @@ -174,7 +174,9 @@ def lattice_reader(part_data_file, part_data_file_name, part_data_file_type=".cs pin.num = row[p] pin_data[p][pin.unit][pin.side][pin.name].append(copy.copy(pin)) + part_custom_fields = None # just a placeholder in case wish to implement + for p in package: yield part_num + "_" + p, "U", "", part_num, "", "", pin_data[ p - ] # Return the dictionary of pins for the package p + ], part_custom_fields # Return the dictionary of pins for the package p diff --git a/kipart/xilinx6s_reader.py b/kipart/xilinx6s_reader.py index 7685410..6a18e2d 100644 --- a/kipart/xilinx6s_reader.py +++ b/kipart/xilinx6s_reader.py @@ -122,5 +122,5 @@ def xilinx6s_reader(part_data_file, part_data_file_name, part_data_file_type=".t # Place all the like-named pins into a list under their common name. # We'll unbundle them later, if necessary. pin_data[pin.unit][pin.side][pin.name].append(pin) - - yield part_num, "U", "", "", "", part_num, pin_data # Return the dictionary of pins extracted from the TXT file. + part_custom_fields = None # just a placeholder in case wish to implement + yield part_num, "U", "", "", "", part_num, pin_data, part_custom_fields # Return the dictionary of pins extracted from the TXT file. diff --git a/kipart/xilinx6v_reader.py b/kipart/xilinx6v_reader.py index 00e15da..c1afd7c 100644 --- a/kipart/xilinx6v_reader.py +++ b/kipart/xilinx6v_reader.py @@ -136,5 +136,6 @@ def xilinx6v_reader(part_data_file, part_data_file_name, part_data_file_type=".t # Place all the like-named pins into a list under their common name. # We'll unbundle them later, if necessary. pin_data[pin.unit][pin.side][pin.name].append(pin) - - yield part_num, "U", "", "", "", part_num, pin_data # Return the dictionary of pins extracted from the TXT file. + + part_custom_fields = None # just a placeholder in case wish to implement + yield part_num, "U", "", "", "", part_num, pin_data, part_custom_fields # Return the dictionary of pins extracted from the TXT file. diff --git a/kipart/xilinx7_reader.py b/kipart/xilinx7_reader.py index 7f16f27..0031eb2 100644 --- a/kipart/xilinx7_reader.py +++ b/kipart/xilinx7_reader.py @@ -170,5 +170,6 @@ def xilinx7_reader(part_data_file, part_data_file_name, part_data_file_type=".cs # Place all the like-named pins into a list under their common name. # We'll unbundle them later, if necessary. pin_data[pin.unit][pin.side][pin.name].append(pin) - - yield part_num, "U", "", "", "", part_num, pin_data # Return the dictionary of pins extracted from the CVS file. + + part_custom_fields = None # just a placeholder in case wish to implement + yield part_num, "U", "", "", "", part_num, pin_data, part_custom_fields # Return the dictionary of pins extracted from the CVS file. diff --git a/kipart/xilinxultra_reader.py b/kipart/xilinxultra_reader.py index 0b2d3be..641bc67 100644 --- a/kipart/xilinxultra_reader.py +++ b/kipart/xilinxultra_reader.py @@ -201,5 +201,6 @@ def xilinxultra_reader(part_data_file, part_data_file_name, part_data_file_type= # Place all the like-named pins into a list under their common name. # We'll unbundle them later, if necessary. pin_data[pin.unit][pin.side][pin.name].append(pin) - - yield part_num, "U", "", "", "", part_num, pin_data # Return the dictionary of pins extracted from the CVS file. + + part_custom_fields = None # just a placeholder in case wish to implement + yield part_num, "U", "", "", "", part_num, pin_data, part_custom_fields # Return the dictionary of pins extracted from the CVS file.