Add validation
This commit is contained in:
parent
f7805cbe09
commit
d3b331e3ad
|
|
@ -26,6 +26,9 @@ outputs:
|
|||
use_protel_extensions: false
|
||||
gerber_precision: 4.5
|
||||
create_gerber_job_file: true
|
||||
use_gerber_x2_attributes: true
|
||||
use_gerber_net_attributes: false
|
||||
|
||||
layers:
|
||||
- layer: F.Cu
|
||||
suffix: F_Cu
|
||||
|
|
@ -74,10 +77,37 @@ outputs:
|
|||
width_adjust: 0
|
||||
mirror_plot: false
|
||||
negative_plot: false
|
||||
a4_output: true
|
||||
layers:
|
||||
- layer: F.Cu
|
||||
suffix: F_Cu
|
||||
- layer: F.Fab
|
||||
suffix: F_Fab
|
||||
# - layer: Inner.1
|
||||
# suffix: Inner_1
|
||||
# suffix: Inner_1
|
||||
#
|
||||
- name: DXF
|
||||
comment: "DXF files"
|
||||
type: dxf
|
||||
dir: gerberdir
|
||||
options:
|
||||
exclude_edge_layer: false
|
||||
exclude_pads_from_silkscreen: false
|
||||
use_aux_axis_as_origin: false
|
||||
plot_sheet_reference: false
|
||||
plot_footprint_refs: true
|
||||
plot_footprint_values: true
|
||||
force_plot_invisible_refs_vals: false
|
||||
tent_vias: true
|
||||
check_zone_fills: true
|
||||
|
||||
# PS options
|
||||
drill_marks: full
|
||||
sketch_plot: true
|
||||
use_aux_axis_as_origin: false
|
||||
polygon_mode: true
|
||||
layers:
|
||||
- layer: F.Cu
|
||||
suffix: F_Cu
|
||||
- layer: F.Fab
|
||||
suffix: F_Fab
|
||||
|
|
@ -11,6 +11,9 @@ from . import config_reader
|
|||
|
||||
def main():
|
||||
|
||||
EXIT_BAD_ARGS = 1
|
||||
EXIT_BAD_CONFIG = 2
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Command-line Plotting for KiCad')
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
|
|
@ -33,6 +36,7 @@ def main():
|
|||
if not os.path.isfile(args.plot_config):
|
||||
logging.error("Plot config file not found: {}"
|
||||
.format(args.plot_config))
|
||||
sys.exit(EXIT_BAD_ARGS)
|
||||
|
||||
cr = config_reader.CfgYamlReader()
|
||||
|
||||
|
|
@ -43,8 +47,15 @@ def main():
|
|||
outdir = os.path.join(os.getcwd(), args.out_dir)
|
||||
cfg.outdir = outdir
|
||||
|
||||
plotter = kiplot.Plotter(cfg)
|
||||
# Finally, once all value are in, check they make sense
|
||||
errs = cfg.validate()
|
||||
|
||||
if errs:
|
||||
logging.error('Invalid config:\n\n' + "\n".join(errs))
|
||||
sys.exit(EXIT_BAD_CONFIG)
|
||||
|
||||
# Set up the plotter and do it
|
||||
plotter = kiplot.Plotter(cfg)
|
||||
plotter.plot(args.board_file)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,18 @@ class CfgYamlReader(CfgReader):
|
|||
'to': 'create_gerber_job_file',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'use_gerber_x2_attributes',
|
||||
'types': ['gerber'],
|
||||
'to': 'use_gerber_x2_attributes',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'use_gerber_net_attributes',
|
||||
'types': ['gerber'],
|
||||
'to': 'use_gerber_net_attributes',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'scale_adjust_x',
|
||||
'types': ['ps'],
|
||||
|
|
@ -252,12 +264,24 @@ class CfgYamlReader(CfgReader):
|
|||
'to': 'width_adjust',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'a4_output',
|
||||
'types': ['ps'],
|
||||
'to': 'a4_output',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'pen_width',
|
||||
'types': ['hpgl'],
|
||||
'to': 'pen_width',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'polygon_mode',
|
||||
'types': ['dxf'],
|
||||
'to': 'polygon_mode',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
{
|
||||
'key': 'use_aux_axis_as_origin',
|
||||
'types': ANY_DRILL,
|
||||
|
|
@ -387,7 +411,8 @@ class CfgYamlReader(CfgReader):
|
|||
except KeyError:
|
||||
raise YamlError("Output needs a type")
|
||||
|
||||
if otype not in ['gerber', 'ps', 'excellon']:
|
||||
if otype not in ['gerber', 'ps', 'hpgl', 'dxf', 'pdf',
|
||||
'gerb_drill', 'excellon']:
|
||||
raise YamlError("Unknown output type: {}".format(otype))
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ class Plotter(object):
|
|||
|
||||
return output.options.type in [
|
||||
PCfg.OutputOptions.GERBER,
|
||||
PCfg.OutputOptions.POSTSCRIPT
|
||||
PCfg.OutputOptions.POSTSCRIPT,
|
||||
PCfg.OutputOptions.DXF,
|
||||
]
|
||||
|
||||
def _output_is_drill(self, output):
|
||||
|
|
@ -74,7 +75,11 @@ class Plotter(object):
|
|||
|
||||
mapping = {
|
||||
PCfg.OutputOptions.GERBER: pcbnew.PLOT_FORMAT_GERBER,
|
||||
PCfg.OutputOptions.POSTSCRIPT: pcbnew.PLOT_FORMAT_POST
|
||||
PCfg.OutputOptions.POSTSCRIPT: pcbnew.PLOT_FORMAT_POST,
|
||||
PCfg.OutputOptions.HPGL: pcbnew.PLOT_FORMAT_HPGL,
|
||||
PCfg.OutputOptions.PDF: pcbnew.PLOT_FORMAT_PDF,
|
||||
PCfg.OutputOptions.DXF: pcbnew.PLOT_FORMAT_DXF,
|
||||
PCfg.OutputOptions.SVG: pcbnew.PLOT_FORMAT_SVG,
|
||||
}
|
||||
|
||||
try:
|
||||
|
|
@ -186,6 +191,9 @@ class Plotter(object):
|
|||
po.SetGerberPrecision(gerb_opts.gerber_precision)
|
||||
po.SetCreateGerberJobFile(gerb_opts.create_gerber_job_file)
|
||||
|
||||
po.SetUseGerberAttributes(gerb_opts.use_gerber_x2_attributes)
|
||||
po.SetIncludeGerberNetlistInfo(gerb_opts.use_gerber_net_attributes)
|
||||
|
||||
def _configure_hpgl_opts(self, po, output):
|
||||
|
||||
assert(output.options.type == PCfg.OutputOptions.HPGL)
|
||||
|
|
@ -201,6 +209,24 @@ class Plotter(object):
|
|||
po.SetWidthAdjust(ps_opts.width_adjust)
|
||||
po.SetFineScaleAdjustX(ps_opts.scale_adjust_x)
|
||||
po.SetFineScaleAdjustX(ps_opts.scale_adjust_y)
|
||||
po.SetA4Output(ps_opts.a4_output)
|
||||
|
||||
def _configure_dxf_opts(self, po, output):
|
||||
|
||||
assert(output.options.type == PCfg.OutputOptions.DXF)
|
||||
dxf_opts = output.options.type_options
|
||||
|
||||
po.SetDXFPlotPolygonMode(dxf_opts.polygon_mode)
|
||||
|
||||
def _configure_pdf_opts(self, po, output):
|
||||
|
||||
assert(output.options.type == PCfg.OutputOptions.PDF)
|
||||
# pdf_opts = output.options.type_options
|
||||
|
||||
def _configure_svg_opts(self, po, output):
|
||||
|
||||
assert(output.options.type == PCfg.OutputOptions.SVG)
|
||||
# pdf_opts = output.options.type_options
|
||||
|
||||
def _configure_output_dir(self, plot_ctrl, output):
|
||||
|
||||
|
|
@ -247,6 +273,14 @@ class Plotter(object):
|
|||
self._configure_gerber_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.POSTSCRIPT:
|
||||
self._configure_ps_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.DXF:
|
||||
self._configure_dxf_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.SVG:
|
||||
self._configure_svg_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.PDF:
|
||||
self._configure_pdf_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.HPGL:
|
||||
self._configure_hpgl_opts(po, output)
|
||||
|
||||
po.SetDrillMarksType(opts.drill_marks)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,17 @@ class KiPlotConfigurationError(error.KiPlotError):
|
|||
pass
|
||||
|
||||
|
||||
class LayerOptions(object):
|
||||
class TypeOptions(object):
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
Return list of invalid settings
|
||||
"""
|
||||
|
||||
return []
|
||||
|
||||
|
||||
class LayerOptions(TypeOptions):
|
||||
"""
|
||||
Common options that all layer outputs have
|
||||
"""
|
||||
|
|
@ -17,12 +27,14 @@ class LayerOptions(object):
|
|||
|
||||
def __init__(self):
|
||||
|
||||
super(LayerOptions, self).__init__()
|
||||
|
||||
self.exclude_edge_layer = False
|
||||
self.exclude_pads_from_silkscreen = False
|
||||
self.plot_sheet_reference = False
|
||||
|
||||
self._supports_line_width = False
|
||||
self._line_width = None
|
||||
self._line_width = 0
|
||||
|
||||
self._supports_aux_axis_origin = False
|
||||
self._use_aux_axis_as_origin = False
|
||||
|
|
@ -42,6 +54,9 @@ class LayerOptions(object):
|
|||
self._supports_drill_marks = False
|
||||
self._drill_marks = pcbnew.PCB_PLOT_PARAMS.NO_DRILL_SHAPE
|
||||
|
||||
self._support_sketch_mode = False
|
||||
self._sketch_mode = False
|
||||
|
||||
@property
|
||||
def line_width(self):
|
||||
return self._line_width
|
||||
|
|
@ -56,7 +71,7 @@ class LayerOptions(object):
|
|||
print("Set LW %d" % self._line_width)
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This output doesn't support setting line width")
|
||||
"This output doesn't support setting line width")
|
||||
|
||||
@property
|
||||
def auto_scale(self):
|
||||
|
|
@ -82,7 +97,7 @@ class LayerOptions(object):
|
|||
self._auto_scale = False
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This Layer output does not support scaling")
|
||||
"This Layer output does not support scaling")
|
||||
|
||||
@property
|
||||
def mirror_plot(self):
|
||||
|
|
@ -95,7 +110,7 @@ class LayerOptions(object):
|
|||
self._mirror_plot = val
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This Layer output does not support mirror plotting")
|
||||
"This Layer output does not support mirror plotting")
|
||||
|
||||
@property
|
||||
def negative_plot(self):
|
||||
|
|
@ -108,7 +123,7 @@ class LayerOptions(object):
|
|||
self._mirror_plot = val
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This Layer output does not support negative plotting")
|
||||
"This Layer output does not support negative plotting")
|
||||
|
||||
@property
|
||||
def drill_marks(self):
|
||||
|
|
@ -127,12 +142,12 @@ class LayerOptions(object):
|
|||
}[val]
|
||||
except KeyError:
|
||||
raise KiPlotConfigurationError(
|
||||
"Unknown drill mark type: {}".format(val))
|
||||
"Unknown drill mark type: {}".format(val))
|
||||
|
||||
self._drill_marks = drill_mark
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This Layer output does not support drill marks")
|
||||
"This Layer output does not support drill marks")
|
||||
|
||||
@property
|
||||
def use_aux_axis_as_origin(self):
|
||||
|
|
@ -145,8 +160,21 @@ class LayerOptions(object):
|
|||
self._use_aux_axis_as_origin = val
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This Layer output does not support using the auxiliary"
|
||||
" axis as the origin")
|
||||
"This Layer output does not support using the auxiliary"
|
||||
" axis as the origin")
|
||||
|
||||
@property
|
||||
def sketch_mode(self):
|
||||
return self._sketch_mode
|
||||
|
||||
@sketch_mode.setter
|
||||
def sketch_mode(self, val):
|
||||
|
||||
if self._supports_sketch_mode:
|
||||
self._sketch_mode = val
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"This Layer output does not support sketch mode")
|
||||
|
||||
|
||||
class GerberOptions(LayerOptions):
|
||||
|
|
@ -161,10 +189,22 @@ class GerberOptions(LayerOptions):
|
|||
self.subtract_mask_from_silk = False
|
||||
self.use_protel_extensions = False
|
||||
self.create_gerber_job_file = False
|
||||
self.use_gerber_x2_attributes = False
|
||||
self.use_gerber_net_attributes = False
|
||||
|
||||
# either 5 or 6
|
||||
self._gerber_precision = None
|
||||
|
||||
def validate(self):
|
||||
|
||||
errs = super(GerberOptions, self).validate()
|
||||
|
||||
if (not self.use_gerber_x2_attributes and
|
||||
self.use_gerber_net_attributes):
|
||||
errs.append("Must set Gerber X2 attributes to use net attributes")
|
||||
|
||||
return errs
|
||||
|
||||
@property
|
||||
def gerber_precision(self):
|
||||
return self._gerber_precision
|
||||
|
|
@ -180,7 +220,7 @@ class GerberOptions(LayerOptions):
|
|||
self._gerber_precision = 6
|
||||
else:
|
||||
raise KiPlotConfigurationError(
|
||||
"Bad Gerber precision : {}".format(val))
|
||||
"Bad Gerber precision : {}".format(val))
|
||||
|
||||
|
||||
class HpglOptions(LayerOptions):
|
||||
|
|
@ -189,6 +229,8 @@ class HpglOptions(LayerOptions):
|
|||
|
||||
super(HpglOptions, self).__init__()
|
||||
|
||||
self._supports_sketch_mode = True
|
||||
|
||||
self._pen_width = None
|
||||
|
||||
@property
|
||||
|
|
@ -211,12 +253,15 @@ class PsOptions(LayerOptions):
|
|||
self._supports_scaling = True
|
||||
self._supports_drill_marks = True
|
||||
self._supports_line_width = True
|
||||
self._supports_sketch_mode = True
|
||||
|
||||
self.scale_adjust_x = 1.0
|
||||
self.scale_adjust_y = 1.0
|
||||
|
||||
self._width_adjust = 0
|
||||
|
||||
self.a4_output = False
|
||||
|
||||
@property
|
||||
def width_adjust(self):
|
||||
return self._width_adjust
|
||||
|
|
@ -226,9 +271,48 @@ class PsOptions(LayerOptions):
|
|||
self._width_adjust = pcbnew.FromMM(width_adjust_mm)
|
||||
|
||||
|
||||
class DrillOptions(object):
|
||||
class SvgOptions(LayerOptions):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(SvgOptions, self).__init__()
|
||||
|
||||
self._supports_line_width = True
|
||||
self._supports_mirror = True
|
||||
self._supports_negative = True
|
||||
self._supports_drill_marks = True
|
||||
|
||||
|
||||
class PdfOptions(LayerOptions):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(PdfOptions, self).__init__()
|
||||
|
||||
self._supports_line_width = True
|
||||
self._supports_mirror = True
|
||||
self._supports_negative = True
|
||||
self._supports_drill_marks = True
|
||||
|
||||
|
||||
class DxfOptions(LayerOptions):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(DxfOptions, self).__init__()
|
||||
|
||||
self._supports_aux_axis_origin = True
|
||||
self._supports_drill_marks = True
|
||||
|
||||
self.polygon_mode = False
|
||||
|
||||
|
||||
class DrillOptions(TypeOptions):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(DrillOptions, self).__init__()
|
||||
|
||||
self.map_options = None
|
||||
self.report_options = None
|
||||
|
||||
|
|
@ -268,7 +352,13 @@ class OutputOptions(object):
|
|||
|
||||
GERBER = 'gerber'
|
||||
POSTSCRIPT = 'ps'
|
||||
HPGL = 'hpgl'
|
||||
SVG = 'svg'
|
||||
PDF = 'pdf'
|
||||
DXF = 'dxf'
|
||||
|
||||
EXCELLON = 'excellon'
|
||||
GERB_DRILL = 'gerb_drill'
|
||||
|
||||
def __init__(self, otype):
|
||||
self.type = otype
|
||||
|
|
@ -277,11 +367,26 @@ class OutputOptions(object):
|
|||
self.type_options = GerberOptions()
|
||||
elif otype == self.POSTSCRIPT:
|
||||
self.type_options = PsOptions()
|
||||
elif otype == self.HPGL:
|
||||
self.type_options = HpglOptions()
|
||||
elif otype == self.SVG:
|
||||
self.type_options = SvgOptions()
|
||||
elif otype == self.DXF:
|
||||
self.type_options = DxfOptions()
|
||||
elif otype == self.PDF:
|
||||
self.type_options = PdfOptions()
|
||||
elif otype == self.EXCELLON:
|
||||
self.type_options = ExcellonOptions()
|
||||
else:
|
||||
self.type_options = None
|
||||
|
||||
def validate(self):
|
||||
|
||||
if self.type_options is None:
|
||||
return ["No type specific options found"]
|
||||
|
||||
return self.type_options.validate()
|
||||
|
||||
|
||||
class LayerInfo(object):
|
||||
|
||||
|
|
@ -311,6 +416,9 @@ class PlotOutput(object):
|
|||
|
||||
self.layers = []
|
||||
|
||||
def validate(self):
|
||||
return self.options.validate()
|
||||
|
||||
|
||||
class PlotConfig(object):
|
||||
|
||||
|
|
@ -322,6 +430,15 @@ class PlotConfig(object):
|
|||
def add_output(self, new_op):
|
||||
self._outputs.append(new_op)
|
||||
|
||||
def validate(self):
|
||||
|
||||
errs = []
|
||||
|
||||
for o in self._outputs:
|
||||
errs += o.validate()
|
||||
|
||||
return errs
|
||||
|
||||
@property
|
||||
def outputs(self):
|
||||
return self._outputs
|
||||
|
|
|
|||
Loading…
Reference in New Issue