153 lines
6.5 KiB
Python
153 lines
6.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright (c) 2020-2023 Salvador E. Tropea
|
|
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
|
|
# Copyright (c) 2018 John Beard
|
|
# License: AGPL-3.0
|
|
# Project: KiBot (formerly KiPlot)
|
|
# Adapted from: https://github.com/johnbeard/kiplot
|
|
import os
|
|
from pcbnew import PLOT_FORMAT_GERBER, FromMM, ToMM
|
|
from .gs import GS
|
|
from .kiplot import register_xmp_import
|
|
from .misc import FONT_HELP_TEXT
|
|
from .optionable import Optionable
|
|
from .out_any_layer import AnyLayer, AnyLayerOptions
|
|
from .error import KiPlotConfigurationError
|
|
from .macros import macros, document, output_class # noqa: F401
|
|
from . import log
|
|
|
|
logger = log.get_logger()
|
|
USEFUL_LAYERS = ['F.SilkS', 'B.SilkS', 'F.Mask', 'B.Mask', 'F.Paste', 'B.Paste', 'Edge.Cuts']
|
|
|
|
|
|
class GerberOptions(AnyLayerOptions):
|
|
def __init__(self):
|
|
with document:
|
|
self.use_aux_axis_as_origin = False
|
|
""" Use the auxiliary axis as origin for coordinates """
|
|
self.line_width = 0.1
|
|
""" [0.02,2] Line_width for objects without width [mm] (KiCad 5) """
|
|
self.subtract_mask_from_silk = False
|
|
""" *Subtract the solder mask from the silk screen """
|
|
self.use_protel_extensions = False
|
|
""" *Use legacy Protel file extensions """
|
|
self._gerber_precision = 4.6
|
|
""" This the gerber coordinate format, can be 4.5 or 4.6 """
|
|
self.create_gerber_job_file = True
|
|
""" *Creates a file with information about all the generated gerbers.
|
|
You can use it in gerbview to load all gerbers at once """
|
|
self.gerber_job_file = GS.def_global_output
|
|
""" Name for the gerber job file (%i='job', %x='gbrjob') """
|
|
self.use_gerber_x2_attributes = True
|
|
""" *Use the extended X2 format (otherwise use X1 formerly RS-274X) """
|
|
self.use_gerber_net_attributes = True
|
|
""" *Include netlist metadata """
|
|
self.disable_aperture_macros = False
|
|
""" Disable aperture macros (workaround for buggy CAM software) (KiCad 6) """
|
|
super().__init__()
|
|
# Gerbers are always 1:1
|
|
del self.scaling
|
|
del self.individual_page_scaling
|
|
self._plot_format = PLOT_FORMAT_GERBER
|
|
if GS.global_output is not None:
|
|
self.gerber_job_file = GS.global_output
|
|
|
|
@property
|
|
def gerber_precision(self):
|
|
return self._gerber_precision
|
|
|
|
@gerber_precision.setter
|
|
def gerber_precision(self, val):
|
|
if val != 4.5 and val != 4.6:
|
|
raise KiPlotConfigurationError("`gerber_precision` must be 4.5 or 4.6")
|
|
self._gerber_precision = val
|
|
|
|
def _configure_plot_ctrl(self, po, output_dir):
|
|
super()._configure_plot_ctrl(po, output_dir)
|
|
po.SetSubtractMaskFromSilk(self.subtract_mask_from_silk)
|
|
po.SetUseGerberProtelExtensions(self.use_protel_extensions)
|
|
po.SetGerberPrecision(5 if self.gerber_precision == 4.5 else 6)
|
|
po.SetCreateGerberJobFile(self.create_gerber_job_file)
|
|
po.SetUseGerberX2format(self.use_gerber_x2_attributes)
|
|
po.SetIncludeGerberNetlistInfo(self.use_gerber_net_attributes)
|
|
po.SetUseAuxOrigin(self.use_aux_axis_as_origin)
|
|
po.SetDrillMarksType(0)
|
|
if GS.ki5:
|
|
po.SetLineWidth(FromMM(self.line_width))
|
|
else:
|
|
po.SetDisableGerberMacros(self.disable_aperture_macros)
|
|
po.gerber_job_file = self.gerber_job_file
|
|
|
|
def read_vals_from_po(self, po):
|
|
super().read_vals_from_po(po)
|
|
# usegerberattributes
|
|
self.use_gerber_x2_attributes = po.GetUseGerberX2format()
|
|
# usegerberextensions
|
|
self.use_protel_extensions = po.GetUseGerberProtelExtensions()
|
|
# usegerberadvancedattributes
|
|
self.use_gerber_net_attributes = po.GetIncludeGerberNetlistInfo()
|
|
# creategerberjobfile
|
|
self.create_gerber_job_file = po.GetCreateGerberJobFile()
|
|
# gerberprecision
|
|
self.gerber_precision = 4.0 + po.GetGerberPrecision()/10.0
|
|
# subtractmaskfromsilk
|
|
self.subtract_mask_from_silk = po.GetSubtractMaskFromSilk()
|
|
# useauxorigin
|
|
self.use_aux_axis_as_origin = po.GetUseAuxOrigin()
|
|
if GS.ki5:
|
|
# linewidth
|
|
self.line_width = ToMM(po.GetLineWidth())
|
|
else:
|
|
# disableapertmacros
|
|
self.disable_aperture_macros = po.GetDisableGerberMacros()
|
|
|
|
|
|
@output_class
|
|
class Gerber(AnyLayer):
|
|
""" Gerber format
|
|
This is the main fabrication format for the PCB.
|
|
This output is what you get from the File/Plot menu in pcbnew. """
|
|
__doc__ += FONT_HELP_TEXT
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
with document:
|
|
self.options = GerberOptions
|
|
""" *[dict] Options for the `gerber` output """
|
|
self._category = 'PCB/fabrication/gerber'
|
|
|
|
@staticmethod
|
|
def get_conf_examples(name, layers):
|
|
gb = {}
|
|
outs = [gb]
|
|
# Create a generic version
|
|
gb['name'] = 'gerber_modern'
|
|
gb['comment'] = 'Gerbers in modern format, recommended by the standard'
|
|
gb['type'] = 'gerber'
|
|
gb['dir'] = 'Gerbers_and_Drill'
|
|
gb['layers'] = [AnyLayer.layer2dict(la) for la in layers]
|
|
# Process the templates
|
|
# Filter the list of layers using the ones we are interested on
|
|
useful = GS.get_useful_layers(USEFUL_LAYERS, layers, include_copper=True)
|
|
tpl_layers = []
|
|
for la in useful:
|
|
tpl_layers.append("- layer: '{}'".format(la.layer))
|
|
tpl_layers.append(" suffix: '{}'".format(la.suffix))
|
|
tpl_layers.append(" description: '{}'".format(la.description))
|
|
tpl_layers = '\n '.join(tpl_layers)
|
|
register_xmp_import('global', {'_KIBOT_MANF_DIR_COMP': 'Manufacturers',
|
|
'_KIBOT_GERBER_LAYERS': tpl_layers})
|
|
# Add the list of layers to the templates
|
|
for tpl in ['Elecrow', 'FusionPCB', 'JLCPCB', 'PCBWay']:
|
|
defs = {'_KIBOT_MANF_DIR': os.path.join('Manufacturers', tpl)}
|
|
if tpl == 'JLCPCB':
|
|
if not GS.sch:
|
|
# We need the schematic for the variant
|
|
defs['_KIBOT_POS_ENABLED'] = 'false'
|
|
else:
|
|
defs['_KIBOT_POS_PRE_TRANSFORM'] = "['_kicost_rename', '_rot_footprint']"
|
|
if not GS.sch_file or not Optionable.solve_field_name('_field_lcsc_part', empty_when_none=True):
|
|
defs['_KIBOT_BOM_ENABLED'] = 'false'
|
|
register_xmp_import(tpl, defs)
|
|
return outs
|