Add validation

This commit is contained in:
John Beard 2018-06-02 16:33:11 +01:00
parent f7805cbe09
commit d3b331e3ad
5 changed files with 234 additions and 17 deletions

View File

@ -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

View File

@ -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)

View 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:

View File

@ -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)

View File

@ -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