Custom reports for plot outputs (i.e. custom gerber job generation)

This commit is contained in:
Salvador E. Tropea 2021-01-14 10:24:04 -03:00
parent aa3025b348
commit 9f4763c36b
4 changed files with 121 additions and 2 deletions

View File

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Now layers can be selected using the default KiCad names.
- More control over the name of the drill and gerber files.
- More options to customize the excellon output.
- Custom reports for plot outputs (i.e. custom gerber job generation)
### Changed
- Now the default output name applies to the DRC and ERC report names.

View File

@ -662,6 +662,11 @@ Next time you need this list just use an alias, like this:
- `name`: [string=''] Used to identify this particular output definition.
- `options`: [dict] Options for the `dxf` output.
* Valid keys:
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `drill_marks`: [string='full'] what to use to indicate the drill places, can be none, small or full (for real scale).
@ -759,6 +764,11 @@ Next time you need this list just use an alias, like this:
* Valid keys:
- `create_gerber_job_file`: [boolean=true] Creates a file with information about all the generated gerbers.
You can use it in gerbview to load all gerbers at once.
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `disable_aperture_macros`: [boolean=false] Disable aperture macros (workaround for buggy CAM software) (KiCad 6).
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
@ -801,6 +811,11 @@ Next time you need this list just use an alias, like this:
- `name`: [string=''] Used to identify this particular output definition.
- `options`: [dict] Options for the `hpgl` output.
* Valid keys:
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `drill_marks`: [string='full'] what to use to indicate the drill places, can be none, small or full (for real scale).
@ -1025,6 +1040,11 @@ Next time you need this list just use an alias, like this:
This output is what you get from the File/Plot menu in pcbnew.
* Valid keys:
- `comment`: [string=''] A comment for documentation purposes.
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `dir`: [string='.'] Output directory for the generated files.
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
@ -1045,6 +1065,11 @@ Next time you need this list just use an alias, like this:
- `name`: [string=''] Used to identify this particular output definition.
- `options`: [dict] Options for the `pdf` output.
* Valid keys:
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `drill_marks`: [string='full'] what to use to indicate the drill places, can be none, small or full (for real scale).
@ -1160,6 +1185,11 @@ Next time you need this list just use an alias, like this:
- `options`: [dict] Options for the `ps` output.
* Valid keys:
- `a4_output`: [boolean=true] force A4 paper size.
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `drill_marks`: [string='full'] what to use to indicate the drill places, can be none, small or full (for real scale).
@ -1243,6 +1273,11 @@ Next time you need this list just use an alias, like this:
- `name`: [string=''] Used to identify this particular output definition.
- `options`: [dict] Options for the `svg` output.
* Valid keys:
- `custom_reports`: [list(dict)] A list of customized reports for the manufacturer.
* Valid keys:
- `content`: [string=''] Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER.
- `output`: [string='Custom_report.txt'] File name for the custom report.
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `drill_marks`: [string='full'] what to use to indicate the drill places, can be none, small or full (for real scale).

View File

@ -168,6 +168,13 @@ outputs:
type: 'dxf'
dir: 'Example/dxf_dir'
options:
# [list(dict)] A list of customized reports for the manufacturer
custom_reports:
# [string=''] Content for the report. Use ${basename} for the project name without extension.
# Use ${filename(LAYER)} for the file corresponding to LAYER
- content: ''
# [string='Custom_report.txt'] File name for the custom report
output: 'Custom_report.txt'
# [string|list(string)=''] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: ''
@ -291,6 +298,13 @@ outputs:
# [boolean=true] Creates a file with information about all the generated gerbers.
# You can use it in gerbview to load all gerbers at once
create_gerber_job_file: true
# [list(dict)] A list of customized reports for the manufacturer
custom_reports:
# [string=''] Content for the report. Use ${basename} for the project name without extension.
# Use ${filename(LAYER)} for the file corresponding to LAYER
- content: ''
# [string='Custom_report.txt'] File name for the custom report
output: 'Custom_report.txt'
# [boolean=false] Disable aperture macros (workaround for buggy CAM software) (KiCad 6)
disable_aperture_macros: false
# [string|list(string)=''] Name of the filter to mark components as not fitted.
@ -347,6 +361,13 @@ outputs:
type: 'hpgl'
dir: 'Example/hpgl_dir'
options:
# [list(dict)] A list of customized reports for the manufacturer
custom_reports:
# [string=''] Content for the report. Use ${basename} for the project name without extension.
# Use ${filename(LAYER)} for the file corresponding to LAYER
- content: ''
# [string='Custom_report.txt'] File name for the custom report
output: 'Custom_report.txt'
# [string|list(string)=''] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: ''
@ -663,6 +684,13 @@ outputs:
type: 'pdf'
dir: 'Example/pdf_dir'
options:
# [list(dict)] A list of customized reports for the manufacturer
custom_reports:
# [string=''] Content for the report. Use ${basename} for the project name without extension.
# Use ${filename(LAYER)} for the file corresponding to LAYER
- content: ''
# [string='Custom_report.txt'] File name for the custom report
output: 'Custom_report.txt'
# [string|list(string)=''] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: ''
@ -789,6 +817,13 @@ outputs:
options:
# [boolean=true] force A4 paper size
a4_output: true
# [list(dict)] A list of customized reports for the manufacturer
custom_reports:
# [string=''] Content for the report. Use ${basename} for the project name without extension.
# Use ${filename(LAYER)} for the file corresponding to LAYER
- content: ''
# [string='Custom_report.txt'] File name for the custom report
output: 'Custom_report.txt'
# [string|list(string)=''] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: ''
@ -891,6 +926,13 @@ outputs:
type: 'svg'
dir: 'Example/svg_dir'
options:
# [list(dict)] A list of customized reports for the manufacturer
custom_reports:
# [string=''] Content for the report. Use ${basename} for the project name without extension.
# Use ${filename(LAYER)} for the file corresponding to LAYER
- content: ''
# [string='Custom_report.txt'] File name for the custom report
output: 'Custom_report.txt'
# [string|list(string)=''] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: ''

View File

@ -6,9 +6,11 @@
# Project: KiBot (formerly KiPlot)
# Adapted from: https://github.com/johnbeard/kiplot
import os
import re
from pcbnew import GERBER_JOBFILE_WRITER, PLOT_CONTROLLER, IsCopperLayer, F_Cu, B_Cu, Edge_Cuts
from .out_base import (BaseOutput)
from .error import (PlotError, KiPlotConfigurationError)
from .optionable import Optionable
from .out_base import BaseOutput
from .error import PlotError, KiPlotConfigurationError
from .layer import Layer
from .gs import GS
from .misc import KICAD_VERSION_5_99, W_NOLAYER
@ -19,6 +21,17 @@ from . import log
logger = log.get_logger(__name__)
class CustomReport(Optionable):
def __init__(self):
super().__init__()
with document:
self.output = 'Custom_report.txt'
""" File name for the custom report """
self.content = ''
""" Content for the report. Use ${basename} for the project name without extension.
Use ${filename(LAYER)} for the file corresponding to LAYER """
class AnyLayerOptions(VariantOptions):
""" Base class for: DXF, Gerber, HPGL, PDF, PS and SVG """
def __init__(self):
@ -47,8 +60,15 @@ class AnyLayerOptions(VariantOptions):
Example '.g%n' """
self.edge_cut_extension = ''
""" Used to configure the edge cuts layer extension for Protel mode """
self.custom_reports = CustomReport
""" [list(dict)] A list of customized reports for the manufacturer """
super().__init__()
def config(self):
super().config()
if isinstance(self.custom_reports, type):
self.custom_reports = []
def _configure_plot_ctrl(self, po, output_dir):
logger.debug("Configuring plot controller for output")
po.SetOutputDirectory(output_dir)
@ -93,6 +113,7 @@ class AnyLayerOptions(VariantOptions):
# Apply the variants and filters
exclude = self.filter_components(board)
# Plot every layer in the output
generated = {}
layers = Layer.solve(layers)
for la in layers:
suffix = la.suffix
@ -134,9 +155,29 @@ class AnyLayerOptions(VariantOptions):
os.rename(k_filename, filename)
if create_job:
jobfile_writer.AddGbrFile(id, os.path.basename(filename))
generated[la.layer] = os.path.basename(filename)
# Create the job file
if create_job:
jobfile_writer.CreateJobFile(self.expand_filename(output_dir, po.gerber_job_file, 'job', 'gbrjob'))
# Custom reports
regex_fname = re.compile(r'\$\{filename\(.*\)\}')
for report in self.custom_reports:
filename = report.output
content = report.content
# Replace special white spaces
content = content.replace('\\r', chr(13))
content = content.replace('\\n', chr(10))
content = content.replace('\\t', chr(9))
# Replace file names, compatible with gerber_zipper_action
content = content.replace('${basename}', GS.pcb_basename)
for name, file in generated.items():
content = content.replace('${filename('+name+')}', file)
# Replace unused layers
content = regex_fname.sub('', content)
# Create the report
logger.debug('Creating custom report `'+filename+'`')
with open(os.path.join(output_dir, filename), 'wt') as f:
f.write(content)
# Restore the eliminated layers
if exclude:
self.unfilter_components(board)