From 84b38921ee2cc79ed46287c03133b5eb92597748 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Mon, 15 Aug 2016 23:33:46 +0200 Subject: o Adding new command: kicad_pcb_plot to plot a PCB. --- README.md | 2 +- cli/CMakeLists.txt | 5 + cmake/KicadUtilsConfig.cmake | 2 + cmake/kicad_generate_header.cmake | 24 +++- cmake/kicad_pcb_plot.cmake | 65 +++++++++ py/kicad_pcb_plot.py | 274 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 365 insertions(+), 7 deletions(-) create mode 100644 cmake/kicad_pcb_plot.cmake create mode 100755 py/kicad_pcb_plot.py diff --git a/README.md b/README.md index af174b6..b9a1bdf 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ For example the `nodemcu-arduino` template will assume that the part follows the will look like this: namespace schematic { - + ... static const int AD0 = D0; ... } diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 6cad70c..2bd80fc 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -20,6 +20,11 @@ install(DIRECTORY ../templates/ FILES_MATCHING PATTERN *.py PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) +install(DIRECTORY ../py/ + DESTINATION share/kicad-utils/py + FILES_MATCHING PATTERN *.py + PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + install(DIRECTORY ../cmake/ DESTINATION lib/cmake/KicadUtils) diff --git a/cmake/KicadUtilsConfig.cmake b/cmake/KicadUtilsConfig.cmake index 2302fe2..1cb682d 100644 --- a/cmake/KicadUtilsConfig.cmake +++ b/cmake/KicadUtilsConfig.cmake @@ -1,2 +1,4 @@ include("${CMAKE_CURRENT_LIST_DIR}/kicad_generate_header.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/kicad_pcb_plot.cmake") include("${CMAKE_CURRENT_LIST_DIR}/KicadUtilsTargets.cmake") +set(KicadUtilsPyDir "${CMAKE_CURRENT_LIST_DIR}/../../../share/kicad-utils/py") diff --git a/cmake/kicad_generate_header.cmake b/cmake/kicad_generate_header.cmake index 930c5ed..85b1f9b 100644 --- a/cmake/kicad_generate_header.cmake +++ b/cmake/kicad_generate_header.cmake @@ -1,6 +1,6 @@ function(kicad_generate_header) - set(options IN_SOURCE) - set(oneValueArgs OUTPUT NET REF OUTPUT_DIR TEMPLATE TEMPLATE_LIB_LIST) + set(options IN_SOURCE ALL) + set(oneValueArgs OUTPUT NET REF OUTPUT_DIR TEMPLATE TEMPLATE_LIB_LIST TARGET) cmake_parse_arguments(kicad_gen "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -42,16 +42,28 @@ function(kicad_generate_header) endif () set(lib "-l;${CMAKE_CURRENT_SOURCE_DIR}") - foreach(l IN LISTS kicad_gen_TEMPLATE_LIB_LIST) - list(APPEND lib -l) - list(APPEND lib "${l}") + foreach (l IN LISTS kicad_gen_TEMPLATE_LIB_LIST) + list(APPEND lib -l "${l}") endforeach () - set(output_file "${output_dir}/${output}") + set(output_file "${output_dir}/${output}") file(RELATIVE_PATH output_file_rel "${output_rel_dir}" ${output_file}) + message("kicad_generate_header: output_file=${output_file}") + message("kicad_generate_header: output_file_rel=${output_file_rel}") + add_custom_command(OUTPUT "${output_file}" COMMAND KicadUtils::generate-header -n ${NET} -r ${REF} -o ${output_file} ${t} ${template} ${lib} MAIN_DEPENDENCY ${NET} COMMENT "Generating ${output_file_rel}") + + if (kicad_gen_TARGET) + set(target "${kicad_gen_TARGET}") + if (kicad_gen_ALL) + set(all ALL) + endif () + + add_custom_target("${target}" ${all} DEPENDS ${output_file}) + endif () + endfunction() diff --git a/cmake/kicad_pcb_plot.cmake b/cmake/kicad_pcb_plot.cmake new file mode 100644 index 0000000..562004e --- /dev/null +++ b/cmake/kicad_pcb_plot.cmake @@ -0,0 +1,65 @@ +function(kicad_pcb_plot) + set(options ALL) + set(one_value_args TARGET PCB_FILE DIR) + set(multi_value_args) + cmake_parse_arguments(kicad_pcb_plot "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) + + if (NOT kicad_pcb_plot_PCB_FILE) + message(SEND_ERROR "Missing required argument: PCB_FILE") + return() + endif () + + set(pcb_file "${kicad_pcb_plot_PCB_FILE}") + get_filename_component(pcb_file "${kicad_pcb_plot_PCB_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(basename "${pcb_file}" NAME_WE) + + if (NOT kicad_pcb_plot_TARGET) + set(target "${basename}-plots") + else () + set(target "${kicad_pcb_plot_TARGET}") + endif () + + if (NOT kicad_pcb_plot_DIR) + message(SEND_ERROR "Missing required argument: DIR") + return() + endif () + + set(out_dir "${kicad_pcb_plot_DIR}") + set(pdf_prefix "${out_dir}/${basename}") + + set(outputs + "${pdf_prefix}-Assembly.pdf" + "${pdf_prefix}-AssyOutlinesTop.pdf" + "${pdf_prefix}-AssyTop.pdf" + "${pdf_prefix}-CuBottom.pdf" + "${pdf_prefix}-CuTop.pdf" + "${pdf_prefix}-EdgeCuts.pdf" + "${pdf_prefix}-Layout.pdf" + "${pdf_prefix}-MaskBottom.pdf" + "${pdf_prefix}-MaskTop.pdf" + "${pdf_prefix}-PasteBottom.pdf" + "${pdf_prefix}-PasteTop.pdf" + "${pdf_prefix}-SilkBottom.pdf" + "${pdf_prefix}-Silk.pdf" + "${pdf_prefix}-SilkTop.pdf") + + # message(STATUS "kicad_pcb_plot: pcb_file: ${pcb_file}") + # message(STATUS "kicad_pcb_plot: out_dir: ${out_dir}") + # message(STATUS "kicad_pcb_plot: pdf_prefix: ${pdf_prefix}") + # message(STATUS "kicad_pcb_plot: outputs: ${outputs}") + # message(STATUS "kicad_pcb_plot: target: ${target}") + + add_custom_command( + OUTPUT ${outputs} + COMMAND cmake -E make_directory "${out_dir}" + COMMAND "${KicadUtilsPyDir}/kicad_pcb_plot.py" "${pcb_file}" "${out_dir}" + MAIN_DEPENDENCY "${pcb_file}") + + if (kicad_pcb_plot_ALL) + set(all ALL) + endif () + + add_custom_target( + ${target} ${all} + DEPENDS ${outputs}) +endfunction() diff --git a/py/kicad_pcb_plot.py b/py/kicad_pcb_plot.py new file mode 100755 index 0000000..ef62cb2 --- /dev/null +++ b/py/kicad_pcb_plot.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python +''' +Heavily borrowed from this location: https://github.com/blairbonnett-mirrors/kicad/blob/master/demos/python_scripts_examples/plot_board.py + +Parameters + +Takes 2 parameters +1. Path to kicad file +2. Location of where to save pdfs + + A python script example to create various plot files from a board: + Fab files + Doc files + Gerber files + + Important note: + this python script does not plot frame references. + the reason is it is not yet possible from a python script because plotting + plot frame references needs loading the corresponding page layout file + (.wks file) or the default template. + + This info (the page layout template) is not stored in the board, and therefore + not available. + + Do not try to change SetPlotFrameRef(False) to SetPlotFrameRef(true) + the result is the pcbnew lib will crash if you try to plot + the unknown frame references template. + + +Usage + + There are 4 main lines that generate a file. e.g.. + + pctl.SetLayer(F_SilkS) + pctl.OpenPlotfile("Silk", PLOT_FORMAT_PDF, "Assembly guide") + pctl.PlotLayer() + pctl.ClosePlot() + + +The first line takes the F.Silks layer +The second line takes 3 parameters (file-name-append, file type, unknown) +The third line actually plots the layer +The forth line reads the temp file and writes it out to a pdf + +You can write to the following formats + +PLOT_FORMAT_SVG +PLOT_FORMAT_PDF +PLOT_FORMAT_GERBER + + +''' +import sys + +from pcbnew import * +filename=sys.argv[1] #e.g left-main/left-main.kicad_pcb + +board = LoadBoard(filename) + +pctl = PLOT_CONTROLLER(board) + +popt = pctl.GetPlotOptions() + +# popt.SetOutputDirectory("plot/") +popt.SetOutputDirectory(sys.argv[2]) + + + +# Set some important plot options: +popt.SetPlotFrameRef(False) +popt.SetLineWidth(FromMM(0.35)) + +popt.SetAutoScale(False) +popt.SetScale(1) +popt.SetMirror(False) +popt.SetUseGerberAttributes(True) +popt.SetExcludeEdgeLayer(False); +popt.SetScale(1) +popt.SetUseAuxOrigin(True) + +# This by gerbers only (also the name is truly horrid!) +popt.SetSubtractMaskFromSilk(False) + +pctl.SetLayer(F_SilkS) +pctl.OpenPlotfile("Silk", PLOT_FORMAT_PDF, "Assembly guide") +pctl.PlotLayer() + +######################### +#### CuBottom.gbr #### +#### CuTop.gbr #### +#### EdgeCuts.gbr #### +#### MaskBottom.gbr #### +#### MaskTop.gbr #### +#### PasteBottom.gbr #### +#### PasteTop.gbr #### +#### SilkBottom.gbr #### +#### SilkTop.gbr #### +######################### + +# Once the defaults are set it become pretty easy... +# I have a Turing-complete programming language here: I'll use it... +# param 0 is a string added to the file base name to identify the drawing +# param 1 is the layer ID +plot_plan = [ + ( "F.Cu", F_Cu, "Front layer" ), + ( "B.Cu", B_Cu, "Bottom layer" ), + ( "F.Paste", F_Paste, "Paste front" ), + ( "B.Paste", B_Paste, "Paste bottom" ), + ( "F.Silk", F_SilkS, "Silk front" ), + ( "B.Silk", B_SilkS, "Silk bottom" ), + ( "F.Mask", F_Mask, "Mask front" ), + ( "B.Mask", B_Mask, "Mask bottom" ), + ( "Edge.Cuts", Edge_Cuts, "Edges" ), + ( "Cmts.User", Cmts_User, "User comments" ), +] + +for layer_info in plot_plan: + pctl.SetLayer(layer_info[1]) + pctl.OpenPlotfile(layer_info[0], PLOT_FORMAT_PDF, layer_info[2]) + pctl.PlotLayer() + +###################### +#### AssyTop.pdf ##### +###################### + +# Our fabricators want two additional gerbers: +# An assembly with no silk trim and all and only the references +# (you'll see that even holes have designators, obviously) +popt.SetSubtractMaskFromSilk(False) +popt.SetPlotReference(True) +popt.SetPlotValue(False) +popt.SetPlotInvisibleText(True) + +pctl.SetLayer(F_SilkS) +pctl.OpenPlotfile("AssyTop", PLOT_FORMAT_PDF, "Assembly top") +pctl.PlotLayer() + +############################### +#### AssyOutlinesTop.pdf ##### +############################### + +# And a gerber with only the component outlines (really!) +popt.SetPlotReference(False) +popt.SetPlotInvisibleText(False) +pctl.SetLayer(F_SilkS) +pctl.OpenPlotfile("AssyOutlinesTop", PLOT_FORMAT_PDF, "Assembly outline top") +pctl.PlotLayer() + +###################### +#### Layout.pdf ##### +###################### + +# The same could be done for the bottom side, if there were components +popt.SetUseAuxOrigin(False) + +## For documentation we also want a general layout PDF +## I usually use a shell script to merge the ps files and then distill the result +## Now I can do it with a control file. As a bonus I can have references in a +## different colour, too. + +popt.SetPlotReference(True) +popt.SetPlotValue(True) +popt.SetPlotInvisibleText(False) +# Remember that the frame is always in color 0 (BLACK) and should be requested +# before opening the plot +popt.SetPlotFrameRef(False) +pctl.SetLayer(Dwgs_User) + +pctl.OpenPlotfile("Layout", PLOT_FORMAT_PDF, "General layout") +pctl.PlotLayer() + +# Do the PCB edges in yellow +popt.SetColor(YELLOW) +pctl.SetLayer(Edge_Cuts) +pctl.PlotLayer() + +## Comments in, uhmm... green +popt.SetColor(GREEN) +pctl.SetLayer(Cmts_User) +pctl.PlotLayer() + +# Bottom mask as lines only, in red +#popt.SetMode(LINE) +popt.SetColor(RED) +pctl.SetLayer(B_Mask) +pctl.PlotLayer() + +# Top mask as lines only, in blue +popt.SetColor(BLUE) +pctl.SetLayer(F_Mask) +pctl.PlotLayer() + +# Top paste in light blue, filled +popt.SetColor(BLUE) +#popt.SetMode(FILLED) +pctl.SetLayer(F_Paste) +pctl.PlotLayer() + +# Top Silk in cyan, filled, references in dark cyan +popt.SetReferenceColor(DARKCYAN) +popt.SetColor(CYAN) +pctl.SetLayer(F_SilkS) +pctl.PlotLayer() + +######################## +#### Assembly.svg ##### +######################## + +popt.SetTextMode(PLOTTEXTMODE_STROKE) +pctl.SetLayer(F_Mask) +pctl.OpenPlotfile("Assembly", PLOT_FORMAT_PDF, "Master Assembly") +pctl.SetColorMode(True) + +# We want *everything* +popt.SetPlotReference(True) +popt.SetPlotValue(True) +popt.SetPlotInvisibleText(True) + +# Remember than the DXF driver assigns colours to layers. This means that +# we will be able to turn references on and off simply using their layers +# Also most of the layer are now plotted in 'line' mode, because DXF handles +# fill mode almost like sketch mode (this is to keep compatibility with +# most CAD programs; most of the advanced primitive attributes required are +# handled only by recent autocads...); also the entry level cads (qcad +# and derivatives) simply don't handle polyline widths... +# +# Here I'm using numbers for colors and layers, I'm too lazy too look them up:P +popt.SetReferenceColor(19) +popt.SetValueColor(21) + +popt.SetColor(0) +#popt.SetMode(LINE) +pctl.SetLayer(B_SilkS) +pctl.PlotLayer() +popt.SetColor(14) +pctl.SetLayer(F_SilkS) +pctl.PlotLayer() +popt.SetColor(2) +pctl.SetLayer(B_Mask) +pctl.PlotLayer() +popt.SetColor(4) +pctl.SetLayer(F_Mask) +pctl.PlotLayer() +popt.SetColor(1) +pctl.SetLayer(B_Paste) +pctl.PlotLayer() +popt.SetColor(9) +pctl.SetLayer(F_Paste) +pctl.PlotLayer() +popt.SetColor(3) +pctl.SetLayer(Edge_Cuts) +pctl.PlotLayer() + +# Export the copper layers too... exporting one of them in filled mode with +# drill marks will put the marks in the WHITE later (since it tries to blank +# the pads...); these will be obviously great reference points for snap +# and stuff in the cad. A pctl function to only plot them would be +# better anyway... + +popt.SetColor(17) +#popt.SetMode(FILLED) +popt.SetDrillMarksType(PCB_PLOT_PARAMS.FULL_DRILL_SHAPE) +pctl.SetLayer(B_Cu) +pctl.PlotLayer() +popt.SetColor(20) +popt.SetDrillMarksType(PCB_PLOT_PARAMS.NO_DRILL_SHAPE) +pctl.SetLayer(F_Cu) +pctl.PlotLayer() + +# At the end you have to close the last plot, otherwise you don't know when +# the object will be recycled! +pctl.ClosePlot() + +# We have just generated 21 plotfiles with a single script -- cgit v1.2.3