diff --git a/.gitignore b/.gitignore index 7cee81b..01aeac2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ !/mykicadws2.kicad_wks !/mypower.kicad_sym !/my.kicad_sym +!/makefile-pcb-release \ No newline at end of file diff --git a/makefile-pcb-release b/makefile-pcb-release new file mode 100644 index 0000000..e36fd46 --- /dev/null +++ b/makefile-pcb-release @@ -0,0 +1,376 @@ +PRO="your_project.kicad_pro" +PRO_DIR=$(dir ${PRO}) +NAME=$(basename $(notdir ${PRO})) +SCHFILE=${PRO_DIR}/${NAME}.kicad_sch +PCBFILE=${PRO_DIR}/${NAME}.kicad_pcb +REV=$(shell sed -En 's/.*\(rev "(.*)"\).*/\1/p' "${SCHFILE}") + +KICAD_VER=7.0 +PYTHON=python +IBOM_SCRIPT_WIN=${USERPROFILE}/Documents/KiCad/${KICAD_VER}/3rdparty/plugins/org_openscopeproject_InteractiveHtmlBom/generate_interactive_bom.py +IBOM_SCRIPT_NIX=${HOME}/.local/share/kicad/${KICAD_VER}/3rdparty/plugins/org_openscopeproject_InteractiveHtmlBom/generate_interactive_bom.py +IBOM_SCRIPT=$(if $(wildcard ${IBOM_SCRIPT_NIX}),${IBOM_SCRIPT_NIX},${IBOM_SCRIPT_WIN}) +COLORS_DIR_WIN=${USERPROFILE}/AppData/Roaming/kicad/${KICAD_VER}/colors +COLORS_DIR_NIX=${HOME}/.config/kicad/${KICAD_VER}/colors +COLORS_DIR=$(if $(wildcard ${COLORS_DIR_NIX}),${COLORS_DIR_NIX},${COLORS_DIR_WIN}) + +.PHONY: all clean gerber pdf ibom +.FORCE: +all: gerber pdf ibom + +clean: + rm -rf "${PRO_DIR}/out/" + + +%/gerber.zip: .FORCE + rm -rf $@ "$(@D)/gerber/" + mkdir -p "$(@D)/gerber/" + kicad-cli pcb export drill --output "$(@D)/gerber/" \ + --format excellon \ + --drill-origin absolute \ + --excellon-units mm \ + --excellon-separate-th \ + --excellon-zeros-format decimal \ + --generate-map \ + --map-format gerberx2 \ + "${PCBFILE}" + kicad-cli pcb export gerbers --output "$(@D)/gerber/" \ + --layers F.Cu,B.Cu,In1.Cu,In2.Cu,F.Silkscreen,B.Silkscreen,F.Mask,B.Mask,F.Paste,B.Paste,Edge.Cuts \ + --no-protel-ext \ + --no-x2 \ + --disable-aperture-macros \ + "${PCBFILE}" + zip -rj $@ "$(@D)/gerber/" + rm -rf "$(@D)/gerber/" + +gerber: ${PRO_DIR}/out/gerber.zip + + +%/bom_interactive.html: .FORCE + mkdir -p "$(@D)" + ${PYTHON} "${IBOM_SCRIPT}" "${PCBFILE}" \ + --dnp-field DNP \ + --group-fields "Value,Footprint" \ + --include-nets \ + --normalize-field-case \ + --no-browser \ + --dest-dir "$(abspath $(@D))" \ + --name-format "$(@F)" + +ibom: ${PRO_DIR}/out/bom_interactive.html + + +%/schematic.pdf: + mkdir -p $(@D) + $(file >${COLORS_DIR}/pdf_export.json,${pdf_export_json}) + kicad-cli sch export pdf --theme pdf_export --output "$@" --no-background-color "${SCHFILE}" + rm "${COLORS_DIR}/pdf_export.json" + + +define LAYERS + {'file': "F_Edge_Cuts", 'name': "Edge.Cuts", 'mirror': False, 'border': True}, + {'file': "F_Cu", 'name': "F.Cu", 'mirror': False, 'border': False}, + {'file': "F_Paste", 'name': "F.Paste", 'mirror': False, 'border': False}, + {'file': "F_Fab", 'name': "F.Fab", 'mirror': False, 'border': False}, + {'file': "User_Drawings", 'name': "User.Drawings", 'mirror': False, 'border': False}, + {'file': "User_Eco1", 'name': "User.Eco1", 'mirror': False, 'border': False}, + {'file': "B_Edge_Cuts", 'name': "Edge.Cuts", 'mirror': True, 'border': True}, + {'file': "B_Cu", 'name': "B.Cu", 'mirror': True, 'border': False}, + {'file': "B_Paste", 'name': "B.Paste", 'mirror': True, 'border': False}, + {'file': "B_Fab", 'name': "B.Fab", 'mirror': True, 'border': False}, +endef +%/assembly_f.pdf %/assembly_b.pdf: + mkdir -p $(@D) + $(file >${COLORS_DIR}/pdf_export.json,${pdf_export_json}) + $(file >$(@D)/plot.py,${plot_py}) + ${PYTHON} "$(@D)/plot.py" "${PCBFILE}" + qpdf "$(@D)/${NAME}-F_Edge_Cuts.pdf" --overlay "$(@D)/${NAME}-F_Cu.pdf" -- "$(@D)/assembly_f.pdf" + qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-F_Paste.pdf" -- + qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-F_Fab.pdf" -- + qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-User_Drawings.pdf" -- + qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-User_Eco1.pdf" -- + qpdf "$(@D)/${NAME}-B_Edge_Cuts.pdf" --overlay "$(@D)/${NAME}-B_Cu.pdf" -- "$(@D)/assembly_b.pdf" + qpdf --replace-input "$(@D)/assembly_b.pdf" --overlay "$(@D)/${NAME}-B_Paste.pdf" -- + qpdf --replace-input "$(@D)/assembly_b.pdf" --overlay "$(@D)/${NAME}-B_Fab.pdf" -- + rm "${COLORS_DIR}/pdf_export.json" "$(@D)/plot.py" "$(@D)/${NAME}-F_Edge_Cuts.pdf" "$(@D)/${NAME}-F_Cu.pdf" "$(@D)/${NAME}-F_Paste.pdf" "$(@D)/${NAME}-F_Fab.pdf" "$(@D)/${NAME}-User_Drawings.pdf" "$(@D)/${NAME}-User_Eco1.pdf" "$(@D)/${NAME}-B_Edge_Cuts.pdf" "$(@D)/${NAME}-B_Cu.pdf" "$(@D)/${NAME}-B_Paste.pdf" "$(@D)/${NAME}-B_Fab.pdf" + + +%/bom.pdf: + mkdir -p "$(@D)" + kicad-cli sch export python-bom --output "$(@D)/bom.xml" "${SCHFILE}" + $(file >$(@D)/bom2csv.xsl,${bom2csv_xsl}) + xsltproc -o "$(@D)/bom.csv" "$(@D)/bom2csv.xsl" "$(@D)/bom.xml" + $(file >$(@D)/bom.rst,${bom_rst}) + $(file >$(@D)/bom.rst.style,${bom_rst_style}) + rst2pdf -s "$(@D)/bom.rst.style" "$(@D)/bom.rst" "$@" + rm "$(@D)/bom2csv.xsl" "$(@D)/bom.rst" "$(@D)/bom.rst.style" "$(@D)/bom.csv" "$(@D)/bom.xml" + + +# Current KiCad version cannot automatically export 3D or VRML file, so you need to manually do it and save result to out/*_3d.png +%_3d.jpg: %_3d.png + convert "$<" -quality 90 "$@" +%_3d.pdf: %_3d.jpg + convert "$<" -density 250 "$@" + + +PC := % +.SECONDEXPANSION: +%/pcb.pdf: $$(@D)/schematic.pdf $$(@D)/assembly_f.pdf $$(@D)/assembly_b.pdf $$(@D)/bom.pdf $$(patsubst $${PC}.png,$${PC}.pdf,$$(wildcard $$(@D)/*_3d.png)) + qpdf --empty --pages $+ -- "$@" + rm $+ + +pdf: ${PRO_DIR}/out/pcb.pdf + + + +define plot_py +import os, pcbnew, sys +layers = [ ${LAYERS} ] +board = pcbnew.LoadBoard(sys.argv[1]) +settings_manager = pcbnew.GetSettingsManager() +color_settings = settings_manager.GetColorSettings('pdf_export') +plot_controller = pcbnew.PLOT_CONTROLLER(board) +plot_controller.SetColorMode(True) +plot_options = plot_controller.GetPlotOptions() +plot_options.SetOutputDirectory(os.path.dirname(os.path.abspath(__file__))) +plot_options.SetPlotInvisibleText(False) +# plot_options.SetPlotPadsOnSilkLayer(False) +plot_options.SetUseAuxOrigin(False) +plot_options.SetScale(1.0) +plot_options.SetAutoScale(False) +# plot_options.SetPlotMode(PLOT_MODE) +# plot_options.SetLineWidth(2000) +plot_options.SetNegative(False) +plot_options.SetPlotValue(True) +plot_options.SetPlotReference(True) +plot_options.SetPlotViaOnMaskLayer(True) +plot_options.SetColorSettings(color_settings) +plot_options.SetBlackAndWhite(False) +for layer in layers: + layer_id = board.GetLayerID(layer['name']) + if pcbnew.IsCopperLayer(layer_id): + plot_options.SetDrillMarksType(pcbnew.DRILL_MARKS_FULL_DRILL_SHAPE) + else: + plot_options.SetDrillMarksType(pcbnew.DRILL_MARKS_NO_DRILL_SHAPE) + plot_options.SetPlotFrameRef(layer['border']) + plot_options.SetMirror(layer['mirror']) + plot_controller.SetLayer(layer_id) + plot_controller.OpenPlotfile(layer['file'], pcbnew.PLOT_FORMAT_PDF, '') + plot_controller.PlotLayer() +endef + + +define pdf_export_json +{ + "3d_viewer": { + "background_bottom": "rgb(102, 102, 128)", + "background_top": "rgb(204, 204, 230)", + "board": "rgba(51, 43, 23, 0.902)", + "copper": "rgb(179, 156, 0)", + "silkscreen_bottom": "rgb(230, 230, 230)", + "silkscreen_top": "rgb(230, 230, 230)", + "soldermask_bottom": "rgba(20, 51, 36, 0.831)", + "soldermask_top": "rgba(20, 51, 36, 0.831)", + "solderpaste": "rgb(128, 128, 128)", + "use_board_stackup_colors": true + }, + "board": { + "anchor": "rgb(255, 38, 226)", + "aux_items": "rgb(255, 255, 255)", + "b_adhes": "rgb(0, 0, 132)", + "b_crtyd": "rgb(38, 233, 255)", + "b_fab": "rgb(0, 0, 0)", + "b_mask": "rgba(0, 132, 0, 0.300)", + "b_paste": "rgba(0, 132, 0, 0.300)", + "b_silks": "rgb(255, 0, 0)", + "background": "rgb(255, 255, 255)", + "cmts_user": "rgb(89, 148, 220)", + "conflicts_shadow": "rgba(255, 0, 5, 0.502)", + "copper": { + "b": "rgba(0, 132, 0, 0.100)", + "f": "rgba(0, 132, 0, 0.100)", + "in1": "rgb(127, 200, 127)", + "in10": "rgb(237, 124, 51)", + "in11": "rgb(91, 195, 235)", + "in12": "rgb(247, 111, 142)", + "in13": "rgb(167, 165, 198)", + "in14": "rgb(40, 204, 217)", + "in15": "rgb(232, 178, 167)", + "in16": "rgb(242, 237, 161)", + "in17": "rgb(237, 124, 51)", + "in18": "rgb(91, 195, 235)", + "in19": "rgb(247, 111, 142)", + "in2": "rgb(206, 125, 44)", + "in20": "rgb(167, 165, 198)", + "in21": "rgb(40, 204, 217)", + "in22": "rgb(232, 178, 167)", + "in23": "rgb(242, 237, 161)", + "in24": "rgb(237, 124, 51)", + "in25": "rgb(91, 195, 235)", + "in26": "rgb(247, 111, 142)", + "in27": "rgb(167, 165, 198)", + "in28": "rgb(40, 204, 217)", + "in29": "rgb(232, 178, 167)", + "in3": "rgb(79, 203, 203)", + "in30": "rgb(242, 237, 161)", + "in4": "rgb(219, 98, 139)", + "in5": "rgb(167, 165, 198)", + "in6": "rgb(40, 204, 217)", + "in7": "rgb(232, 178, 167)", + "in8": "rgb(242, 237, 161)", + "in9": "rgb(141, 203, 129)" + }, + "cursor": "rgb(255, 255, 255)", + "dwgs_user": "rgb(0, 0, 0)", + "eco1_user": "rgb(0, 0, 0)", + "eco2_user": "rgb(0, 0, 72)", + "edge_cuts": "rgb(72, 72, 0)", + "f_adhes": "rgb(132, 0, 132)", + "f_crtyd": "rgb(255, 38, 226)", + "f_fab": "rgb(0, 0, 0)", + "f_mask": "rgba(0, 132, 0, 0.300)", + "f_paste": "rgba(0, 132, 0, 0.300)", + "f_silks": "rgb(255, 0, 0)", + "footprint_text_invisible": "rgb(132, 132, 132)", + "grid": "rgb(194, 194, 194)", + "grid_axes": "rgb(72, 72, 72)", + "locked_shadow": "rgba(255, 38, 226, 0.502)", + "margin": "rgb(255, 38, 226)", + "pad_plated_hole": "rgb(194, 194, 0)", + "pad_through_hole": "rgb(227, 183, 46)", + "page_limits": "rgb(132, 132, 132)", + "plated_hole": "rgb(26, 196, 210)", + "ratsnest": "rgba(0, 248, 255, 0.349)", + "user_1": "rgb(194, 194, 194)", + "user_2": "rgb(89, 148, 220)", + "user_3": "rgb(180, 219, 210)", + "user_4": "rgb(216, 200, 82)", + "user_5": "rgb(194, 194, 194)", + "user_6": "rgb(89, 148, 220)", + "user_7": "rgb(180, 219, 210)", + "user_8": "rgb(216, 200, 82)", + "user_9": "rgb(232, 178, 167)", + "via_blind_buried": "rgb(187, 151, 38)", + "via_hole": "rgb(227, 183, 46)", + "via_micro": "rgb(0, 132, 132)", + "via_through": "rgb(236, 236, 236)", + "worksheet": "rgb(200, 114, 171)" + }, + "meta": { + "name": "pdf_export", + "version": 5 + }, + "schematic": { + "anchor": "rgb(0, 0, 255)", + "aux_items": "rgb(0, 0, 0)", + "background": "rgb(245, 244, 239)", + "brightened": "rgb(255, 0, 255)", + "bus": "rgb(0, 0, 132)", + "bus_junction": "rgb(0, 0, 132)", + "component_body": "rgb(255, 255, 194)", + "component_outline": "rgb(132, 0, 0)", + "cursor": "rgb(15, 15, 15)", + "fields": "rgb(132, 0, 132)", + "grid": "rgb(181, 181, 181)", + "grid_axes": "rgb(0, 0, 132)", + "hidden": "rgb(94, 194, 194)", + "hovered": "rgb(0, 0, 255)", + "junction": "rgb(0, 150, 0)", + "label_global": "rgb(132, 0, 0)", + "label_hier": "rgb(114, 86, 0)", + "label_local": "rgb(15, 15, 15)", + "netclass_flag": "rgb(72, 72, 72)", + "no_connect": "rgb(0, 0, 132)", + "note": "rgb(0, 0, 194)", + "note_background": "rgba(0, 0, 0, 0.000)", + "override_item_colors": false, + "page_limits": "rgb(181, 181, 181)", + "pin": "rgb(132, 0, 0)", + "pin_name": "rgb(0, 100, 100)", + "pin_number": "rgb(169, 0, 0)", + "private_note": "rgb(72, 72, 255)", + "reference": "rgb(0, 100, 100)", + "shadow": "rgba(102, 179, 255, 0.800)", + "sheet": "rgb(132, 0, 0)", + "sheet_background": "rgba(255, 255, 255, 0.000)", + "sheet_fields": "rgb(132, 0, 132)", + "sheet_filename": "rgb(114, 86, 0)", + "sheet_label": "rgb(0, 100, 100)", + "sheet_name": "rgb(0, 100, 100)", + "value": "rgb(0, 100, 100)", + "wire": "rgb(0, 150, 0)", + "worksheet": "rgb(132, 0, 0)" + } +} +endef + + +define bom2csv_xsl + + + +]> + + + + + + + + References, Value, Footprint, Qty + + + + + + + + &nl; + + + + + , + + , + , + + + + +endef + + +define bom_rst +Bill Of Materials +----------------- +.. csv-table:: + :file: bom.csv + :header-rows: 1 + :widths: 4,4,5,1 +.. footer:: ${NAME} rev.${REV} BOM page ###Page###/###Total### +endef + +define bom_rst_style +pageSetup: + spacing-footer: 0mm + spacing-header: 0mm + margin-bottom: 5mm + margin-gutter: 0mm + margin-left: 7mm + margin-right: 7mm + margin-top: 5mm +styles: + base + fontSize: 9 + table-heading: + fontName: stdBold +endef + + +export PATH:=/cygdrive/c/Program Files/KiCad/${KICAD_VER}/bin:/cygdrive/c/Program Files/qpdf/bin:${PATH}