From a3da99e22540c026e4acf7bdc735aa221a4dd752 Mon Sep 17 00:00:00 2001
From: Trygve Laugstøl <trygvis@inamo.no>
Date: Thu, 7 Sep 2017 21:41:39 +0200
Subject: o Adding two kicad tools from my kicad-utils repo.

---
 src/ee/tools/kicad_gerber.py   | 230 ++++++++++++++++++++++++++++++++++
 src/ee/tools/kicad_pcb_plot.py | 273 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 503 insertions(+)
 create mode 100755 src/ee/tools/kicad_gerber.py
 create mode 100755 src/ee/tools/kicad_pcb_plot.py

(limited to 'src')

diff --git a/src/ee/tools/kicad_gerber.py b/src/ee/tools/kicad_gerber.py
new file mode 100755
index 0000000..e8604b8
--- /dev/null
+++ b/src/ee/tools/kicad_gerber.py
@@ -0,0 +1,230 @@
+#!/usr/bin/env python
+import sys
+import os
+import argparse
+from pcbnew import *
+
+
+def layer_name_parser(s):
+    parts = s.split('=')
+    if len(parts) != 2:
+        raise argparse.ArgumentTypeError("Invalid layer renaming: " + s)
+    else:
+        return parts
+
+
+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 instead of .gbr')
+
+parser.add_argument('--uppercase-extensions',
+                    action='store_true',
+                    help='Uppercase all extensions')
+
+parser.add_argument('--layer-extension',
+                    dest='layer_extensions',
+                    metavar='LAYER_AND_EXTENSION',
+                    action='append',
+                    type=layer_name_parser,
+                    help='Set the file extension of a KiCAD layer. Format: <KiCAD Layer>=<extension>, example: F.SilkS=GSILK')
+
+args = parser.parse_args()
+# print "args: " + str(args)
+# print "args.name_layer: " + str(args.name_layers)
+
+renames = {}
+if args.layer_extensions is not None:
+    for s in args.layer_extensions:
+        renames[s[0]] = s[1]
+# print("renames: " + str(renames))
+
+board = LoadBoard(args.pcb)
+
+
+class Plan:
+    def __init__(self, layerNum, layerName, description):
+        self.layerNum = layerNum
+        self.layerName = layerName
+        self.description = description
+        self.postfix = ""
+        self.ext = None
+
+    @staticmethod
+    def standard(layerNum, description):
+        layerName = board.GetLayerName(layerNum)
+        return Plan(layerNum, layerName, description)
+
+    @staticmethod
+    def copper(layerNum):
+        layerName = board.GetLayerName(layerNum)
+        description = "Copper Layer " + layerName
+        return Plan(layerNum, layerName, description)
+
+
+plot_plan = [Plan.standard(layerNum, description) for (layerNum, description) in [
+    (F_SilkS, "Silk front"),
+    (F_Mask, "Mask front"),
+    (F_Paste, "Paste front"),
+    (B_SilkS, "Silk bottom"),
+    (B_Mask, "Mask bottom"),
+    (B_Paste, "Paste bottom"),
+    (Edge_Cuts, "Edges")]]
+
+layers = board.GetEnabledLayers()
+for layerNum in layers.CuStack():
+    plot_plan.append(Plan.copper(layerNum))
+
+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()
+
+if args.protel_extensions:
+    popt.SetUseGerberProtelExtensions(True)
+
+basename = os.path.splitext(filename)[0]
+
+drlFileOut = drlFile = basename + ".drl"
+drlNpthFileOut = drlNpthFile = basename + "-NPTH.drl"
+
+if args.protel_extensions:
+    n, e = os.path.splitext(drlFileOut)
+    drlFileOut = n + ".txt"
+
+if args.uppercase_extensions:
+    n, e = os.path.splitext(drlFileOut)
+    drlFileOut = n + e.upper()
+    n, e = os.path.splitext(drlNpthFileOut)
+    drlNpthFileOut = n + e.upper()
+
+values = vars(args)
+for plan in plot_plan:
+    pctl.SetLayer(plan.layerNum)
+    pctl.OpenPlotfile("", PLOT_FORMAT_GERBER, plan.description)
+    filename = pctl.GetPlotFileName()
+    pctl.ClosePlot()
+    # By opening and closing the plot we create an empty plot file.
+    try:
+        os.remove(filename)
+    except:
+        pass
+
+    filename, ext = os.path.splitext(filename)
+    if args.uppercase_extensions:
+        ext = ext.upper()
+
+    if plan.layerName in renames:
+        ext = "." + renames[plan.layerName]
+
+    # if plan.arg is not None:
+    #     newExt = values[plan.arg]
+    #     if newExt is not None:
+    #         ext = "." + newExt
+
+    # if not args.protel_extensions:
+    plan.postfix = plan.layerName
+    plan.filename = basename + "-" + plan.postfix + ext
+
+    # print "filename = " + plan.filename + ", postfix=" + plan.postfix
+    # print "filename: " + plan.filename
+
+if args.detect_files_only:
+    for plan in plot_plan:
+        print plan.filename
+
+    if args.protel_extensions:
+        print drlFileOut
+        print drlNpthFileOut
+    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.SetScale(1)
+popt.SetUseAuxOrigin(True)
+
+# This by gerbers only (also the name is truly horrid!)
+popt.SetSubtractMaskFromSilk(False)
+
+for plan in plot_plan:
+    pctl.SetLayer(plan.layerNum)
+
+    # print "filename = " + plan.filename + ", postfix=" + plan.postfix
+    pctl.OpenPlotfile(plan.postfix, PLOT_FORMAT_GERBER, plan.description)
+
+    actualFilename = pctl.GetPlotFileName()
+    expectedFilename = plan.filename
+
+    if expectedFilename != actualFilename:
+        os.rename(actualFilename, expectedFilename)
+
+    pctl.PlotLayer()
+    pctl.ClosePlot()
+
+popt.SetDrillMarksType(PCB_PLOT_PARAMS.FULL_DRILL_SHAPE)
+
+drlwriter = EXCELLON_WRITER(board)
+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 drlFile != drlFileOut:
+    os.rename(drlFile, drlFileOut)
+    pass
+
+if drlFile != drlNpthFileOut:
+    os.rename(drlNpthFile, drlNpthFileOut)
+    pass
diff --git a/src/ee/tools/kicad_pcb_plot.py b/src/ee/tools/kicad_pcb_plot.py
new file mode 100755
index 0000000..d6f123d
--- /dev/null
+++ b/src/ee/tools/kicad_pcb_plot.py
@@ -0,0 +1,273 @@
+#!/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