aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/KicadUtilsConfig.cmake2
-rw-r--r--cmake/kicad_gerber.cmake88
-rw-r--r--cmake/kicad_schematic_plot.cmake46
-rw-r--r--examples/CMakeLists.txt3
-rwxr-xr-xpy/kicad_gerber.py145
-rwxr-xr-xpy/kicad_pcb_plot.py33
6 files changed, 300 insertions, 17 deletions
diff --git a/cmake/KicadUtilsConfig.cmake b/cmake/KicadUtilsConfig.cmake
index a2e6419..f8b91b7 100644
--- a/cmake/KicadUtilsConfig.cmake
+++ b/cmake/KicadUtilsConfig.cmake
@@ -1,5 +1,7 @@
set(kicad_generate_header_cmd KicadUtils::generate-header)
include("${CMAKE_CURRENT_LIST_DIR}/kicad_generate_header.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/kicad_pcb_plot.cmake")
+#include("${CMAKE_CURRENT_LIST_DIR}/kicad_schematic_plot.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/kicad_gerber.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/KicadUtilsTargets.cmake")
set(KicadUtilsPyDir "${CMAKE_CURRENT_LIST_DIR}/../../../share/kicad-utils/py")
diff --git a/cmake/kicad_gerber.cmake b/cmake/kicad_gerber.cmake
new file mode 100644
index 0000000..330c5bd
--- /dev/null
+++ b/cmake/kicad_gerber.cmake
@@ -0,0 +1,88 @@
+function(kicad_gerber)
+ set(options ALL)
+ set(one_value_args TARGET PCB_FILE DIR ZIP_FILE NAMING_STYLE)
+ set(multi_value_args)
+ cmake_parse_arguments(ARGS "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
+
+ if (NOT ARGS_PCB_FILE)
+ message(SEND_ERROR "Missing required argument: PCB_FILE")
+ return()
+ endif ()
+
+ if (NOT ARGS_NAMING_STYLE)
+ set(ARGS_NAMING_STYLE MODERN)
+ endif ()
+
+ if (ARGS_NAMING_STYLE STREQUAL MODERN)
+ elseif (ARGS_NAMING_STYLE STREQUAL PROTEL)
+ set(protel --protel-extension)
+ else ()
+ message(SEND_ERROR "Unsupported NAMING_STYLE: ${ARGS_NAMING_STYLE}")
+ return()
+ endif ()
+
+ set(pcb_file "${ARGS_PCB_FILE}")
+ get_filename_component(pcb_file "${ARGS_PCB_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ get_filename_component(basename "${pcb_file}" NAME_WE)
+
+ if (NOT ARGS_TARGET)
+ set(target "${basename}-gerber")
+ else ()
+ set(target "${ARGS_TARGET}")
+ endif ()
+
+ if (NOT ARGS_DIR)
+ message(SEND_ERROR "Missing required argument: DIR")
+ return()
+ endif ()
+
+ set(out_dir "${ARGS_DIR}")
+ set(prefix "${out_dir}/${basename}")
+
+ execute_process(
+ COMMAND "${KicadUtilsPyDir}/kicad_gerber.py" --pcb "${pcb_file}" --output-directory "${out_dir}" ${protel} --detect-files-only
+ OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${target}-gerber-index.txt
+ OUTPUT_VARIABLE out
+ ERROR_VARIABLE err
+ RESULT_VARIABLE res)
+
+ file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/${target}-gerber-index.txt outputs)
+
+ if (NOT res EQUAL 0)
+ message(SEND_ERROR "kicad_gerber.py failed: ${out} ${err}")
+ return()
+ endif ()
+
+# foreach (o ${out})
+# list(APPEND outputs ${prefix}${o})
+# endforeach ()
+
+ # message("out=${out}")
+ message("outputs=${outputs}")
+ add_custom_command(
+ OUTPUT ${outputs}
+ COMMAND cmake -E make_directory "${out_dir}"
+ COMMAND "${KicadUtilsPyDir}/kicad_gerber.py" --pcb "${pcb_file}" --output-directory "${out_dir}" ${protel}
+ MAIN_DEPENDENCY "${pcb_file}")
+
+ if (ARGS_ALL)
+ set(all ALL)
+ endif ()
+
+ if (ARGS_ZIP_FILE)
+ if (NOT IS_ABSOLUTE ARGS_ZIP_FILE)
+ set(ARGS_ZIP_FILE ${CMAKE_CURRENT_BINARY_DIR}/${ARGS_ZIP_FILE})
+ endif ()
+
+ add_custom_command(
+ OUTPUT ${ARGS_ZIP_FILE}
+ MAIN_DEPENDENCY "${pcb_file}"
+ DEPENDS ${outputs}
+ COMMAND cmake -E remove -f ${ARGS_ZIP_FILE}
+ COMMAND zip -q ${ARGS_ZIP_FILE} -j ${outputs})
+ endif ()
+
+ add_custom_target(
+ ${target} ${all}
+ DEPENDS ${outputs} ${ARGS_ZIP_FILE})
+endfunction()
diff --git a/cmake/kicad_schematic_plot.cmake b/cmake/kicad_schematic_plot.cmake
new file mode 100644
index 0000000..d4b77f9
--- /dev/null
+++ b/cmake/kicad_schematic_plot.cmake
@@ -0,0 +1,46 @@
+function(kicad_schematic_plot)
+ set(options ALL)
+ set(one_value_args TARGET SCHEMATIC_FILE DIR)
+ set(multi_value_args)
+ cmake_parse_arguments(kicad_schematic_plot "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
+
+ if (NOT kicad_schematic_plot_SCHEMATIC_FILE)
+ message(SEND_ERROR "Missing required argument: SCHEMATIC_FILE")
+ return()
+ endif ()
+
+ set(schematic_file "${kicad_schematic_plot_SCHEMATIC_FILE}")
+ get_filename_component(schematic_file "${kicad_schematic_plot_SCHEMATIC_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ get_filename_component(basename "${schematic_file}" NAME_WE)
+
+ if (NOT kicad_schematic_plot_TARGET)
+ set(target "${basename}-plots")
+ else ()
+ set(target "${kicad_schematic_plot_TARGET}")
+ endif ()
+
+ if (NOT kicad_schematic_plot_DIR)
+ message(SEND_ERROR "Missing required argument: DIR")
+ return()
+ endif ()
+
+ set(out_dir "${kicad_schematic_plot_DIR}")
+ set(pdf_prefix "${out_dir}/${basename}")
+
+ set(outputs
+ "${pdf_prefix}.pdf")
+
+ add_custom_command(
+ OUTPUT ${outputs}
+ COMMAND cmake -E make_directory "${out_dir}"
+ COMMAND "${KicadUtilsPyDir}/kicad_schematic_plot.py" "${schematic_file}" "${out_dir}"
+ MAIN_DEPENDENCY "${schematic_file}")
+
+ if (kicad_schematic_plot_ALL)
+ set(all ALL)
+ endif ()
+
+ add_custom_target(
+ ${target} ${all}
+ DEPENDS ${outputs})
+endfunction()
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index daa2b4d..7d45496 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -9,7 +9,10 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "The KicadUtils CMake package was not found. Did you pass the correct value for KicadUtils_DIR?\nIt should probably be something like KicadUtils_DIR=$HOME/opt/kicad-utils/lib/cmake/KicadUtils")
endif ()
else ()
+ set(KicadUtilsPyDir "${CMAKE_CURRENT_LIST_DIR}/../py")
include(../cmake/kicad_generate_header.cmake)
+ include(../cmake/kicad_pcb_plot.cmake)
+# include(../cmake/kicad_schematic_plot.cmake)
list(APPEND KICAD_GEN_TEMPLATE_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/../templates)
set(kicad_generate_header_cmd generate-header)
endif ()
diff --git a/py/kicad_gerber.py b/py/kicad_gerber.py
new file mode 100755
index 0000000..41ae3af
--- /dev/null
+++ b/py/kicad_gerber.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+import sys
+import os
+import argparse
+from pcbnew import *
+
+parser = argparse.ArgumentParser(description='KiCAD PCB to GERBER converter')
+
+parser.add_argument('--pcb',
+ required=True,
+ dest='pcb',
+ action='store',
+ help='A foo.kicad_pcb file')
+
+parser.add_argument('--output-directory',
+ required=True,
+ dest='output_directory',
+ action='store',
+ help='Directory to store output files')
+
+parser.add_argument('--detect-files-only',
+ dest='detect_files_only',
+ action='store_true',
+ help='Don\'t create the GERBER files, just list the files to be created')
+
+parser.add_argument('--create-drill-map-file',
+ dest='create_drill_map_file',
+ action='store_true',
+ help='Create drill map file')
+
+parser.add_argument('--protel-extensions',
+ dest='protel_extensions',
+ action='store_true',
+ help='Use Protel filename extensions')
+
+args = parser.parse_args()
+
+filename = args.pcb
+
+board = LoadBoard(filename)
+
+plot_plan = [
+ ("GTO", board.GetLayerName(F_SilkS), F_SilkS, "Silk front"),
+ ("GTS", board.GetLayerName(F_Mask), F_Mask, "Mask front"),
+ ("GBO", board.GetLayerName(B_SilkS), B_SilkS, "Silk bottom"),
+ ("GBS", board.GetLayerName(B_Mask), B_Mask, "Mask bottom"),
+ ("GBR", board.GetLayerName(Edge_Cuts), Edge_Cuts, "Edges"),
+]
+
+layers = board.GetEnabledLayers()
+for i in layers.CuStack():
+ name = board.GetLayerName(i)
+ plot_plan.append(("", name, i, "Copper Layer " + name))
+
+pctl = PLOT_CONTROLLER(board)
+popt = pctl.GetPlotOptions()
+popt.SetOutputDirectory(args.output_directory)
+
+# A nasty hack to get the base filename
+pctl.SetLayer(F_Cu)
+pctl.OpenPlotfile("", PLOT_FORMAT_GERBER, "")
+filename = pctl.GetPlotFileName()
+try:
+ os.remove(filename)
+except:
+ pass
+pctl.ClosePlot()
+
+basename = filename.replace('.gbr', '')
+drlFile = basename + ".drl"
+drlFileProtel = basename + ".txt"
+
+if args.protel_extensions:
+ popt.SetUseGerberProtelExtensions(True)
+
+if args.detect_files_only:
+ for layer_info in plot_plan:
+ filenamePostfix = layer_info[1]
+ layer_num = layer_info[2]
+ pctl.SetLayer(layer_num)
+
+ pctl.OpenPlotfile(filenamePostfix, PLOT_FORMAT_GERBER, layer_info[3])
+ filename = pctl.GetPlotFileName()
+ print filename
+ try:
+ os.remove(filename)
+ except:
+ pass
+
+ pctl.ClosePlot()
+ if args.protel_extensions:
+ print drlFileProtel
+ else:
+ print drlFile
+ sys.exit(0)
+
+# 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)
+
+for layer_info in plot_plan:
+ filenamePostfix = layer_info[1]
+ layer_num = layer_info[2]
+ pctl.SetLayer(layer_num)
+
+ pctl.OpenPlotfile(filenamePostfix, PLOT_FORMAT_GERBER, layer_info[3])
+ pctl.PlotLayer()
+ pctl.ClosePlot()
+
+popt.SetDrillMarksType(PCB_PLOT_PARAMS.FULL_DRILL_SHAPE)
+
+drlwriter = EXCELLON_WRITER(board)
+# drlwriter.SetMapFileFormat(PLOT_FORMAT_PDF)
+drlwriter.SetMapFileFormat(PLOT_FORMAT_GERBER)
+
+mirror = False
+minimalHeader = False
+offset = wxPoint(0, 0)
+# False to generate 2 separate drill files (one for plated holes, one for non plated holes)
+# True to generate only one drill file
+mergeNPTH = False
+drlwriter.SetOptions(mirror, minimalHeader, offset, mergeNPTH)
+
+metricFmt = True
+drlwriter.SetFormat(metricFmt)
+
+genDrl = True
+genMap = args.create_drill_map_file
+
+drlwriter.CreateDrillandMapFilesSet(pctl.GetPlotDirName(), genDrl, genMap)
+
+if args.protel_extensions:
+ os.rename(drlFile, basename + ".txt")
+ pass
diff --git a/py/kicad_pcb_plot.py b/py/kicad_pcb_plot.py
index ef62cb2..d6f123d 100755
--- a/py/kicad_pcb_plot.py
+++ b/py/kicad_pcb_plot.py
@@ -53,7 +53,8 @@ PLOT_FORMAT_GERBER
import sys
from pcbnew import *
-filename=sys.argv[1] #e.g left-main/left-main.kicad_pcb
+
+filename = sys.argv[1] # e.g left-main/left-main.kicad_pcb
board = LoadBoard(filename)
@@ -64,8 +65,6 @@ popt = pctl.GetPlotOptions()
# popt.SetOutputDirectory("plot/")
popt.SetOutputDirectory(sys.argv[2])
-
-
# Set some important plot options:
popt.SetPlotFrameRef(False)
popt.SetLineWidth(FromMM(0.35))
@@ -102,16 +101,16 @@ pctl.PlotLayer()
# 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" ),
+ ("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:
@@ -180,7 +179,7 @@ pctl.SetLayer(Cmts_User)
pctl.PlotLayer()
# Bottom mask as lines only, in red
-#popt.SetMode(LINE)
+# popt.SetMode(LINE)
popt.SetColor(RED)
pctl.SetLayer(B_Mask)
pctl.PlotLayer()
@@ -192,7 +191,7 @@ pctl.PlotLayer()
# Top paste in light blue, filled
popt.SetColor(BLUE)
-#popt.SetMode(FILLED)
+# popt.SetMode(FILLED)
pctl.SetLayer(F_Paste)
pctl.PlotLayer()
@@ -229,7 +228,7 @@ popt.SetReferenceColor(19)
popt.SetValueColor(21)
popt.SetColor(0)
-#popt.SetMode(LINE)
+# popt.SetMode(LINE)
pctl.SetLayer(B_SilkS)
pctl.PlotLayer()
popt.SetColor(14)
@@ -258,7 +257,7 @@ pctl.PlotLayer()
# better anyway...
popt.SetColor(17)
-#popt.SetMode(FILLED)
+# popt.SetMode(FILLED)
popt.SetDrillMarksType(PCB_PLOT_PARAMS.FULL_DRILL_SHAPE)
pctl.SetLayer(B_Cu)
pctl.PlotLayer()