diff --git a/kibot/layer.py b/kibot/layer.py index 65c4baea..7871fa33 100644 --- a/kibot/layer.py +++ b/kibot/layer.py @@ -75,6 +75,20 @@ class Layer(Optionable): 'F.CrtYd': 'F.Courtyard', 'B.CrtYd': 'B.Courtyard', } + # Protel extensions + PROTEL_EXTENSIONS = { + pcbnew.F_Cu: 'gtl', + pcbnew.B_Cu: 'gbl', + pcbnew.F_Adhes: 'gta', + pcbnew.B_Adhes: 'gba', + pcbnew.F_Paste: 'gtp', + pcbnew.B_Paste: 'gbp', + pcbnew.F_SilkS: 'gto', + pcbnew.B_SilkS: 'gbo', + pcbnew.F_Mask: 'gts', + pcbnew.B_Mask: 'gbs', + pcbnew.Edge_Cuts: 'gm1', + } # Names from the board file _pcb_layers = None _plot_layers = None @@ -87,8 +101,9 @@ class Layer(Optionable): self.suffix = '' """ Suffix used in file names related to this layer. Derived from the name if not specified """ self.description = '' - """ A description for the layer, for documentation purposes """ # pragma: no cover + """ A description for the layer, for documentation purposes """ self._unkown_is_error = True + self._protel_extension = None def config(self): super().config() @@ -106,6 +121,20 @@ class Layer(Optionable): def id(self): return self._id + def fix_protel_ext(self): + """ Makes sure we have a defined Protel extension """ + if self._protel_extension is not None: + # Already set, keep it + return + if self._is_inner: + self._protel_extension = 'g'+str(self.id-pcbnew.F_Cu+1) + return + if self.id in Layer.PROTEL_EXTENSIONS: + self._protel_extension = Layer.PROTEL_EXTENSIONS[self.id] + return + self._protel_extension = 'gbr' + return + @staticmethod def solve(values): board = GS.board @@ -135,6 +164,7 @@ class Layer(Optionable): # Check if the layer is in use if layer._is_inner and (layer._id < 1 or layer._id >= layer_cnt - 1): raise PlotError("Inner layer `{}` is not valid for this board".format(layer)) + layer.fix_protel_ext() new_vals.append(layer) else: # A string ext = None @@ -184,6 +214,7 @@ class Layer(Optionable): layer.suffix = name.replace('.', '_') layer.description = Layer.DEFAULT_LAYER_DESC.get(name) layer._get_layer_id_from_name() + layer.fix_protel_ext() return layer @staticmethod @@ -213,7 +244,7 @@ class Layer(Optionable): if id is not None: # 2) List from the PCB self._id = id - self._is_inner = id < pcbnew.B_Cu + self._is_inner = id > pcbnew.F_Cu and id < pcbnew.B_Cu elif self.layer.startswith("Inner"): # 3) Inner.N names m = match(r"^Inner\.([0-9]+)$", self.layer) diff --git a/kibot/out_any_layer.py b/kibot/out_any_layer.py index 8e55025d..f72d5f7a 100644 --- a/kibot/out_any_layer.py +++ b/kibot/out_any_layer.py @@ -7,9 +7,8 @@ # Adapted from: https://github.com/johnbeard/kiplot import os import re -from shutil import rmtree -from tempfile import mkdtemp -from pcbnew import GERBER_JOBFILE_WRITER, PLOT_CONTROLLER, IsCopperLayer, F_Cu, B_Cu, Edge_Cuts +from pcbnew import (GERBER_JOBFILE_WRITER, PLOT_CONTROLLER, IsCopperLayer, F_Cu, B_Cu, Edge_Cuts, PLOT_FORMAT_HPGL, + PLOT_FORMAT_GERBER, PLOT_FORMAT_POST, PLOT_FORMAT_DXF, PLOT_FORMAT_PDF, PLOT_FORMAT_SVG) from .optionable import Optionable from .out_base import BaseOutput, VariantOptions from .error import PlotError, KiPlotConfigurationError @@ -22,6 +21,14 @@ from . import log logger = log.get_logger(__name__) +FORMAT_EXTENSIONS = {PLOT_FORMAT_HPGL: 'plt', + PLOT_FORMAT_GERBER: 'gbr', + PLOT_FORMAT_POST: 'ps', + PLOT_FORMAT_DXF: 'dxf', + PLOT_FORMAT_PDF: 'pdf', + PLOT_FORMAT_SVG: 'svg'} + + class CustomReport(Optionable): def __init__(self): super().__init__() @@ -187,34 +194,25 @@ class AnyLayerOptions(VariantOptions): if exclude: self.unfilter_components(GS.board) + def solve_extension(self, layer): + if self._plot_format == PLOT_FORMAT_GERBER and self.use_protel_extensions: + return layer._protel_extension + return FORMAT_EXTENSIONS[self._plot_format] + def get_targets(self, output_dir, layers): - # This is tricky because we can use names generated by KiCad targets = [] - # Configure KiCad's plotter - plot_ctrl = PLOT_CONTROLLER(GS.board) - po = plot_ctrl.GetPlotOptions() - self._configure_plot_ctrl(po, output_dir) - # KiCad doesn't assign an extension until we actually call OpenPlotFile - # So we create temporal files just to get their name :-( - tmp_dir = mkdtemp() - po.SetOutputDirectory(tmp_dir) layers = Layer.solve(layers) for la in layers: id = la.id if not GS.board.IsLayerEnabled(id): continue - plot_ctrl.SetLayer(id) - plot_ctrl.OpenPlotfile(la.suffix, self._plot_format, '') - # Here we convert the temporal name to the actual name using replace - k_filename = plot_ctrl.GetPlotFileName().replace(tmp_dir, output_dir) + k_filename = self.expand_filename(output_dir, '%f-%i.%x', la.suffix, self.solve_extension(la)) filename = self.compute_name(k_filename, output_dir, self.output, id, la.suffix) - plot_ctrl.ClosePlot() if GS.debug_level > 2: logger.debug('Layer id {} file name {} ({})'.format(id, filename, k_filename)) targets.append(filename) - rmtree(tmp_dir) - if po.GetCreateGerberJobFile(): - targets.append(self.expand_filename(output_dir, po.gerber_job_file, 'job', 'gbrjob')) + if self._plot_format == PLOT_FORMAT_GERBER and self.create_gerber_job_file: + targets.append(self.expand_filename(output_dir, self.gerber_job_file, 'job', 'gbrjob')) for report in self.custom_reports: targets.append(os.path.join(output_dir, report.output)) return targets