Skip to content

Commit c779d98

Browse files
committed
v7 backpart
1 parent 826bd6c commit c779d98

File tree

2 files changed

+180
-43
lines changed

2 files changed

+180
-43
lines changed

Makefile

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,20 @@ OUTDIR=$(abspath ${DIR})
2020
# Tools & Tool Paths, change these if your path is different
2121
#===============================================================
2222
# kicad-cli
23-
KICADCLI=kicad-cli
23+
#KICADCLI=kicad-cli
2424
# flatpak
2525
# KICADCLI=flatpak run --command=kicad-cli org.kicad.KiCad
2626
# snap
2727
# KICADCLI=/snap/bin/kicad.kicad-cli
2828
# docker
29-
#KICADCLI=docker run -v /tmp/.X11-unix:/tmp/.X11-unix -v ${HOME}:${HOME} -it --rm -e DISPLAY=:0 --name kicad-cli kicad/kicad:8.0 kicad-cli
29+
KICADCLI=docker run -v /tmp/.X11-unix:/tmp/.X11-unix -v ${HOME}:${HOME} -it --rm -e DISPLAY=:0 --name kicad-cli kicad/kicad:7.0 kicad-cli
3030
IBOM_SCRIPT=generate_interactive_bom
3131
BOARD2PDF_SCRIPT=board2pdf
32+
PYTHON=python3
33+
KICAD_PYTHON_PATH=/usr/lib/kicad/lib/python3/dist-packages
34+
BOM_SCRIPT="${ROOT_DIR}/bom_csv_grouped_by_value.py"
35+
PCBNEW_DO=pcbnew_do # Kiauto
36+
KIKIT=kikit
3237
#===============================================================
3338

3439
SCH_DRAWING_SHEET=S{ROOT_DIR}/SchDrawingSheet.kicad_wks
@@ -53,10 +58,8 @@ PCB=${_DIR}/${PROJECT}.kicad_pcb
5358
PCBBASE=$(basename $(notdir ${PCB}))
5459
SCHBASE=$(basename $(notdir ${SCH}))
5560

61+
XMLBOM=${ASSEMBLY_DIR}/${SCHBASE}_${VERSION}_BOM.xml
5662
BOM=${ASSEMBLY_DIR}/${SCHBASE}_${VERSION}_BOM.csv
57-
LCSCBOM=${ASSEMBLY_DIR}/${SCHBASE}_${VERSION}_LCSC_BOM.csv
58-
ERC=${LOGS_DIR}/erc.rpt
59-
DRC=${LOGS_DIR}/drc.rpt
6063

6164
# Visualizations
6265
PDFSCH=${_OUTDIR}/${SCHBASE}_${VERSION}.pdf
@@ -71,7 +74,6 @@ JLC_CENTROID=${ASSEMBLY_DIR}/jlc-centroid.csv
7174
# Manufacturing Files
7275
DRILL=${MANUFACTURING_DIR}/gerbers/drill.drl
7376
FABZIP=${_OUTDIR}/${PCBBASE}_${VERSION}.zip
74-
IPC2581=${_OUTDIR}/IPC2581_${PCBBASE}_${VERSION}.xml
7577

7678
# MECHANICAL
7779
MECH_DIR=${_OUTDIR}/mechanical
@@ -82,9 +84,9 @@ OUTLINE=${MECH_DIR}/board-outline.svg
8284
release: ${MECH_DIR} ${ASSEMBLY_DIR} manufacturing fabzip
8385

8486
.PHONY: release manufacturing no-drc clean
85-
release: erc drc manufacturing fabzip
87+
release: manufacturing fabzip
8688

87-
manufacturing: ${GERBER_DIR} ${MECH_DIR} ${ASSEMBLY_DIR} schematic boms gerberpdf ibom step gerbers board ipc2581
89+
manufacturing: ${GERBER_DIR} ${MECH_DIR} ${ASSEMBLY_DIR} schematic boms gerberpdf ibom step gerbers board
8890

8991
no-drc: manufacturing fabzip
9092

@@ -102,31 +104,22 @@ clean:
102104
-rm ${OUTLINE}
103105
-rm ${LOGS_DIR}/*.log
104106
-rm ${LOGS_DIR}/*.rpt
105-
-rm ${LCSCBOM}
106-
-rm ${IPC2581}
107+
-rm ${XMLBOM}
107108
-rm -r ${GERBER_DIR}
108109
-rmdir ${MECH_DIR}
109110
-rmdir ${GERBER_DIR} ${ASSEMBLY_DIR} ${MANUFACTURING_DIR} ${GERBER_PDF_DIR} ${LOGS_DIR}
110111

111112

112-
# Move the log file to the final location if the command succeeds so it doesn't rerun
113-
${DRC}: ${PCB} ${ERC} | ${LOGS_DIR}
114-
${KICADCLI} pcb drc --exit-code-violations "$<" -o ${LOGS_DIR}/drc-out.log
115-
mv ${LOGS_DIR}/drc-out.log "$@"
116-
117-
${ERC}: ${SCH} | ${LOGS_DIR}
118-
${KICADCLI} sch erc --exit-code-violations "$<" -o ${LOGS_DIR}/erc-out.log
119-
mv ${LOGS_DIR}/erc-out.log "$@"
120-
121113
# Generates schematic
122114
${PDFSCH} : ${SCH} | ${_OUTDIR}
123-
${KICADCLI} sch export pdf --black-and-white --drawing-sheet ${SCH_DRAWING_SHEET} "$<" -o "$@"
115+
${KICADCLI} sch export pdf --black-and-white "$<" -o "$@"
124116

125-
${BOM}: ${SCH} | ${ASSEMBLY_DIR}
126-
${KICADCLI} sch export bom "$<" --fields "Reference,Value,Footprint,\$${QUANTITY},\$${DNP},MPN,LCSC,Notes" --group-by="\$${DNP},Value,Footprint" --ref-range-delimiter="" -o "$@"
117+
# Generate python-BOM
118+
${XMLBOM}: ${SCH} ${TMP}
119+
${KICADCLI} sch export python-bom "$<" -o "$@"
127120

128-
${LCSCBOM}: ${SCH} | ${ASSEMBLY_DIR}
129-
${KICADCLI} sch export bom "$<" --fields="Reference,Value,Footprint,LCSC,\$${QUANTITY},\$${DNP}" --labels="Ref Des,Value,Footprint,JLCPCB Part #,QUANTITY,DNP" --group-by="LCSC,\$${DNP},Value,Footprint" --ref-range-delimiter="" -o "$@"
121+
${BOM}: ${XMLBOM} | ${ASSEMBLY_DIR}
122+
${PYTHON} ${BOM_SCRIPT} "$<" "$@" > "$@"
130123

131124
${LOGS_DIR}: | ${_OUTDIR}
132125
mkdir -p "$@"
@@ -148,7 +141,7 @@ ${_OUTDIR}:
148141

149142
# Complains about output needing to be a directory, work around this
150143
${DRILL}: ${PCB} | ${GERBER_DIR}
151-
${KICADCLI} pcb export drill --drill-origin plot --excellon-units mm "$<" -o ${GERBER_DIR}
144+
${KICADCLI} pcb export drill --drill-origin plot --excellon-units mm "$<" -o ${GERBER_DIR}/
152145
mv ${GERBER_DIR}/${PCBBASE}.drl "$@"
153146

154147
${CENTROID_CSV}: ${PCB} | ${ASSEMBLY_DIR}
@@ -168,7 +161,7 @@ ${IBOM}: ${PCB} | ${ASSEMBLY_DIR}
168161
xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" ${IBOM_SCRIPT} "$<" \
169162
--dnp-field DNP --group-fields "Value,Footprint" --blacklist "X1,MH*" \
170163
--include-nets --normalize-field-case --no-browser --dest-dir ./ \
171-
--name-format "$(basename $@ .html)"
164+
--name-format "$(basename $@)"
172165

173166
${FABZIP}: ${GERBER_DIR}
174167
zip -rj "$@" "$<"
@@ -182,22 +175,11 @@ ${GERBERPDF}: ${PCB} | ${_OUTDIR}
182175
${_OUTDIR}/${PCBBASE}_${VERSION}_Render_%.png: ${PCB} | ${_OUTDIR}
183176
${KICADCLI} pcb render --side $(shell echo $* | tr A-Z a-z) --background transparent --quality high "$<" -o "$@"
184177

185-
${IPC2581}: ${PCB} | ${_OUTDIR}
186-
${KICADCLI} pcb export ipc2581 "$<" -o "$@"
187-
188178
gerbers: ${PCB} | ${GERBER_DIR}
189179
${KICADCLI} pcb export gerbers --use-drill-file-origin "$<" -o ${GERBER_DIR}
190180

191-
ipc2581: ${IPC2581}
192-
193181
fabzip: ${FABZIP}
194182

195-
drc: ${DRC}
196-
197-
erc: ${ERC}
198-
199-
LCSCBOM: ${LCSCBOM}
200-
201183
zip: ${FABZIP}
202184

203185
step: ${STEP}
@@ -206,7 +188,7 @@ ibom: ${IBOM}
206188

207189
schematic: ${PDFSCH}
208190

209-
boms: ${ASSEMBLY_DIR} ${BOM} ${LCSCBOM} ${ASSEMBLY_BOM} ibom
191+
boms: ${ASSEMBLY_DIR} ${BOM} ${XMLBOM} ${ASSEMBLY_BOM} ibom
210192

211193
board: gerbers ${DRILL} ${CENTROID_CSV} ${JLC_CENTROID} boms ${OUTLINE}
212194

@@ -216,8 +198,4 @@ gerberpdf: ${GERBERPDF}
216198

217199
centroid: ${CENTROID} ${JLC_CENTROID}
218200

219-
erc: ${ERC}
220-
221-
drc: ${DRC}
222-
223-
.PHONY: gerbers ipc2581 fabzip drc erc LCSCBOM zip step ibom schematic boms board setup gerberpdf centroid erc drc
201+
.PHONY: gerbers fabzip XMLBOM zip step ibom schematic boms board setup gerberpdf centroid

bom_csv_grouped_by_value.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#
2+
# Example python script to generate a BOM from a KiCad generic netlist
3+
#
4+
# Example: Sorted and Grouped CSV BOM
5+
#
6+
7+
"""
8+
@package
9+
Output: CSV (comma-separated)
10+
Grouped By: Value, Symbol Name, Footprint, DNP
11+
Sorted By: Ref
12+
Fields: Item, Qty, Reference(s), Value, LibPart, Footprint, Datasheet, DNP, all additional symbol fields
13+
14+
Outputs ungrouped components first, then outputs grouped components.
15+
16+
Command line:
17+
python "pathToFile/bom_csv_grouped_by_value.py" "%I" "%O.csv"
18+
"""
19+
20+
from __future__ import print_function
21+
22+
# Import the KiCad python helper module and the csv formatter
23+
import kicad_netlist_reader
24+
import kicad_utils
25+
import csv
26+
import sys
27+
28+
# A helper function to filter/convert a string read in netlist
29+
#currently: do nothing
30+
def fromNetlistText( aText ):
31+
return aText
32+
33+
def myEqu(self, other):
34+
"""myEqu is a more advanced equivalence function for components which is
35+
used by component grouping. Normal operation is to group components based
36+
on their value and footprint.
37+
38+
In this example of a custom equivalency operator we compare the
39+
value, the part name and the footprint.
40+
"""
41+
result = True
42+
if self.getValue() != other.getValue():
43+
result = False
44+
elif self.getPartName() != other.getPartName():
45+
result = False
46+
elif self.getFootprint() != other.getFootprint():
47+
result = False
48+
elif self.getDNP() != other.getDNP():
49+
result = False
50+
51+
return result
52+
53+
# Override the component equivalence operator - it is important to do this
54+
# before loading the netlist, otherwise all components will have the original
55+
# equivalency operator.
56+
kicad_netlist_reader.comp.__eq__ = myEqu
57+
58+
if len(sys.argv) != 3:
59+
print("Usage ", __file__, "<generic_netlist.xml> <output.csv>", file=sys.stderr)
60+
sys.exit(1)
61+
62+
63+
# Generate an instance of a generic netlist, and load the netlist tree from
64+
# the command line option. If the file doesn't exist, execution will stop
65+
net = kicad_netlist_reader.netlist(sys.argv[1])
66+
67+
# Open a file to write to, if the file cannot be opened output to stdout
68+
# instead
69+
canOpenFile = True
70+
try:
71+
f = kicad_utils.open_file_writeUTF8(sys.argv[2], 'w')
72+
except IOError:
73+
e = "Can't open output file for writing: " + sys.argv[2]
74+
print( __file__, ":", e, sys.stderr )
75+
f = sys.stdout
76+
canOpenFile = False
77+
78+
# subset the components to those wanted in the BOM, controlled
79+
# by <configure> block in kicad_netlist_reader.py
80+
components = net.getInterestingComponents( excludeBOM=True )
81+
82+
compfields = net.gatherComponentFieldUnion(components)
83+
partfields = net.gatherLibPartFieldUnion()
84+
85+
# remove Reference, Value, Datasheet, and Footprint, they will come from 'columns' below
86+
partfields -= set( ['Reference', 'Value', 'Datasheet', 'Footprint'] )
87+
88+
columnset = compfields | partfields # union
89+
90+
# prepend an initial 'hard coded' list and put the enchillada into list 'columns'
91+
hardcoded_columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet', 'DNP']
92+
columns = hardcoded_columns + sorted(list(columnset))
93+
94+
# Create a new csv writer object to use as the output formatter
95+
out = csv.writer( f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL )
96+
97+
# override csv.writer's writerow() to support encoding conversion (initial encoding is utf8):
98+
def writerow( acsvwriter, columns ):
99+
utf8row = []
100+
for col in columns:
101+
utf8row.append( fromNetlistText( str(col) ) )
102+
acsvwriter.writerow( utf8row )
103+
104+
# Output a set of rows as a header providing general information
105+
writerow( out, ['Source:', net.getSource()] )
106+
writerow( out, ['Date:', net.getDate()] )
107+
writerow( out, ['Tool:', net.getTool()] )
108+
writerow( out, ['Generator:', sys.argv[0]] )
109+
writerow( out, ['Component Count:', len(components)] )
110+
writerow( out, [] )
111+
112+
writerow( out, ['Collated Components:'] )
113+
writerow( out, [] ) # blank line
114+
writerow( out, columns ) # reuse same columns
115+
116+
row=[]
117+
118+
# Get all of the components in groups of matching parts + values
119+
# (see kicad_netlist_reader.py)
120+
grouped = net.groupComponents(components)
121+
122+
123+
# Output component information organized by group, aka as collated:
124+
item = 0
125+
for group in grouped:
126+
del row[:]
127+
refs = ""
128+
refs_l = []
129+
130+
# Add the reference of every component in the group and keep a reference
131+
# to the component so that the other data can be filled in once per group
132+
for component in group:
133+
refs_l.append( component.getRef() )
134+
c = component
135+
136+
refs = ", ".join(refs_l)
137+
138+
# Fill in the component groups common data
139+
# columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet', 'DNP'] + sorted(list(columnset))
140+
item += 1
141+
row.append( item )
142+
row.append( len(group) )
143+
row.append( refs );
144+
row.append( c.getValue() )
145+
row.append( c.getLibName() + ":" + c.getPartName() )
146+
row.append( net.getGroupFootprint(group) )
147+
row.append( net.getGroupDatasheet(group) )
148+
row.append( c.getDNPString() )
149+
150+
# add user fields by name
151+
for field in columns[len(hardcoded_columns):]:
152+
row.append( net.getGroupField(group, field) );
153+
154+
writerow( out, row )
155+
156+
f.close()
157+
158+
if not canOpenFile:
159+
sys.exit(1)

0 commit comments

Comments
 (0)