You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
5.6 KiB
Python

#!/usr/bin/env kipy
__copyright__ = 'Copyright 2020 ALT-TEKNIK LLC'
from argparse import ArgumentParser
from os import path, rename
from os.path import dirname, realpath
from pcbnew import B_Cu, B_Mask, Edge_Cuts, EXCELLON_WRITER, F_Cu, F_Mask, \
FILLED, FromMils, LoadBoard, PCB_PLOT_PARAMS, PLOT_CONTROLLER, \
PLOT_FORMAT_GERBER, PLOT_FORMAT_PDF, TEXTE_PCB
from uuid import uuid1
_BOARD_NAME = '2x10-dip-adapter'
_VERSION_TOKEN = 'X.Y.Z'
_GERBER_EXT_OVERRIDES = {Edge_Cuts: 'gko'}
class _Layer:
def __init__(self, num, descr, **kwargs):
self.__num = num
self.__descr = descr
if kwargs.get('is_pdf'):
self.__use_aux_origin = False
self.__fmt = PLOT_FORMAT_PDF
self.__fmt_descr = 'PDF'
else:
self.__use_aux_origin = True
self.__fmt = PLOT_FORMAT_GERBER
self.__fmt_descr = 'Gerber'
scale = kwargs.get('scale')
self.__scale = 1.0 if not scale else scale
suffix = kwargs.get('suffix')
self.__suffix = '' if suffix is None else suffix
def plot(self, board_file, output_dir, version=None):
# Append the suffix for Gerber layers with file extension overrides to
# ease renaming after plotting
suffix = self.__suffix
override_gerber_ext = (self.__fmt == PLOT_FORMAT_GERBER and
self.__num in _GERBER_EXT_OVERRIDES)
if override_gerber_ext:
uuid = str(uuid1())
suffix = '{}-{}'.format(suffix, uuid) if suffix else uuid
# Indicate status
print('Plotting {} {}...'.format(self.__descr, self.__fmt_descr))
# Load the board
board = LoadBoard(board_file)
# Replace version text
if version is not None:
for drawing in board.GetDrawings():
if (drawing.IsOnLayer(self.__num) and
isinstance(drawing, TEXTE_PCB)):
text = drawing.GetText()
if _VERSION_TOKEN in text:
drawing.SetText(text.replace(_VERSION_TOKEN, version))
print(' Replaced version text')
# Create a plot controller
controller = PLOT_CONTROLLER(board)
# Set the plot options
opts = controller.GetPlotOptions()
opts.SetOutputDirectory(output_dir)
opts.SetPlotFrameRef(False)
opts.SetPlotValue(False)
opts.SetPlotReference(True)
opts.SetPlotInvisibleText(False)
opts.SetExcludeEdgeLayer(True)
opts.SetSubtractMaskFromSilk(False)
opts.SetPlotViaOnMaskLayer(False)
opts.SetSkipPlotNPTH_Pads(True)
opts.SetUseAuxOrigin(self.__use_aux_origin)
opts.SetDrillMarksType(PCB_PLOT_PARAMS.NO_DRILL_SHAPE)
opts.SetAutoScale(False)
opts.SetScale(self.__scale)
opts.SetPlotMode(FILLED)
opts.SetLineWidth(FromMils(0.1))
opts.SetMirror(False)
opts.SetNegative(False)
if self.__fmt == PLOT_FORMAT_GERBER:
opts.SetUseGerberProtelExtensions(not override_gerber_ext)
opts.SetCreateGerberJobFile(False)
opts.SetGerberPrecision(6)
opts.SetUseGerberX2format(False)
opts.SetIncludeGerberNetlistInfo(False)
# Plot the layer
controller.SetColorMode(False)
controller.SetLayer(self.__num)
controller.OpenPlotfile(suffix, self.__fmt, self.__descr)
controller.PlotLayer()
controller.ClosePlot()
# Rename Gerber layers with file extension overrides
if override_gerber_ext:
src = '{}-{}.gbr'.format(_BOARD_NAME, suffix)
dest = _BOARD_NAME
if self.__suffix:
dest = '{}-{}'.format(dest, self.__suffix)
dest = '{}.{}'.format(dest, _GERBER_EXT_OVERRIDES[self.__num])
rename(path.join(output_dir, src), path.join(output_dir, dest))
_OUTPUT_DIR = 'plots'
_LAYERS = (
_Layer(F_Mask, 'F.Mask'),
_Layer(F_Cu, 'F.Cu'),
_Layer(B_Cu, 'B.Cu'),
_Layer(B_Mask, 'B.Mask'),
_Layer(Edge_Cuts, 'Edge.Cuts')
)
def main(version=None):
# Canonicalize the board filename and output directory
project_dir = realpath(dirname(__file__))
board_file = '{}.kicad_pcb'.format(_BOARD_NAME)
abs_board_file = path.join(project_dir, board_file)
output_dir = realpath(path.join(project_dir, _OUTPUT_DIR))
# Plot the layers
for layer in _LAYERS:
layer.plot(abs_board_file, output_dir, version)
# Write the drill file
print('Writing Excellon drill file...')
board = LoadBoard(abs_board_file)
writer = EXCELLON_WRITER(board)
writer.SetOptions(False, # aMirror
False, # aMinimalHeader
board.GetDesignSettings().m_AuxOrigin, # aOffset
True) # aMerge_PTH_NPTH
writer.SetRouteModeForOvalHoles(True)
writer.SetFormat(True, # aMetric
EXCELLON_WRITER.DECIMAL_FORMAT) # aZerosFmt
writer.CreateDrillandMapFilesSet(output_dir, # aPlotDirectory
True, # aGenDrill
False) # aGenMap
rename(path.join(output_dir, '{}.drl'.format(_BOARD_NAME)),
path.join(output_dir, '{}.xln'.format(_BOARD_NAME)))
# Indicate status
print('Plotted {}'.format(board_file))
if __name__ == '__main__':
parser = ArgumentParser(description='creates board plots')
parser.add_argument('version', nargs='?', help='the board version')
args = parser.parse_args()
main(args.version)