Skip to content

Commit

Permalink
Merge pull request johnbeard#6 from INTI-CMNB/gen_sch_variant
Browse files Browse the repository at this point in the history
Gen sch variant
  • Loading branch information
set-soft authored Sep 2, 2020
2 parents 48be2fa + 6fa903e commit 13ce325
Show file tree
Hide file tree
Showing 38 changed files with 1,197 additions and 131 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Now variants are separated entities.
- Only the internal BoM currently supports it.
- Only the internal BoM and Schematic print currently supports it.
- In the future IBoM will also support it, contact me if you think this is
high priority.
- New filters entities. They implement all the functionality in KiBoM and IBoM.
Expand All @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Marking components as "Do Not Fit"
- Marking components as "Do Not Change"
- The internal BoM format supports KiBoM and IBoM style variants
- Schematic print to PDF supports variants. Not fitted components are crossed.

## [0.6.2] - 2020-08-25
### Changed
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ gen_ref:
cp -a $(REFILL).refill $(REFILL)
src/kibot -c tests/yaml_samples/pdf_zone-refill.kibot.yaml -b tests/board_samples/zone-refill.kicad_pcb -d $(REFDIR)
src/kibot -c tests/yaml_samples/print_pcb_zone-refill.kibot.yaml -b tests/board_samples/zone-refill.kicad_pcb -d $(REFDIR)
src/kibot -c tests/yaml_samples/print_pdf_no_inductors_1.kibot.yaml -e tests/board_samples/test_v5.sch -d $(REFDIR)
mv "$(REFDIR)no_inductor/test_v5-schematic_(no_L).pdf" $(REFDIR)
rmdir $(REFDIR)no_inductor/
cp -a $(REFILL).ok $(REFILL)

doc:
Expand Down
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ Next time you need this list just use an alias, like this:
- `number`: [number=1] Number of boards to build (components multiplier).
- `output`: [string='%f-%i%v.%x'] filename for the output (%i=bom). Affected by global options.
- `use_alt`: [boolean=false] Print grouped references in the alternate compressed style eg: R1-R7,R18.
- `variant`: [string=''] Board variant(s), used to determine which components
- `variant`: [string=''] Board variant, used to determine which components
are output to the BoM..
- `xlsx`: [dict] Options for the XLSX format.
* Valid keys:
Expand Down Expand Up @@ -522,7 +522,7 @@ Next time you need this list just use an alias, like this:
- `exclude_edge_layer`: [boolean=true] do not include the PCB edge layer.
- `exclude_pads_from_silkscreen`: [boolean=false] do not plot the component pads in the silk screen.
- `force_plot_invisible_refs_vals`: [boolean=false] include references and values even when they are marked as invisible.
- `gerber_job_file`: [string='%f-%i.%x'] name for the gerber job file (%i='job', %x='gbrjob').
- `gerber_job_file`: [string='%f-%i%v.%x'] name for the gerber job file (%i='job', %x='gbrjob'). Affected by global options.
- `gerber_precision`: [number=4.6] this the gerber coordinate format, can be 4.5 or 4.6.
- `line_width`: [number=0.1] [0.02,2] line_width for objects without width [mm].
- `output`: [string='%f-%i%v.%x'] output file name, the default KiCad name if empty. Affected by global options.
Expand Down Expand Up @@ -812,7 +812,10 @@ 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_sch_print` output.
* Valid keys:
- `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.
- `output`: [string='%f-%i%v.%x'] filename for the output PDF (%i=schematic %x=pdf). Affected by global options.
- `variant`: [string=''] Board variant(s), used to determine which components are crossed..

* Pick & place
* Type: `position`
Expand Down Expand Up @@ -866,6 +869,21 @@ Next time you need this list just use an alias, like this:
- `width_adjust`: [number=0] this width factor is intended to compensate PS printers/plotters that do not strictly obey line width settings.
Only used to plot pads and tracks.

* Schematic with variant generator
* Type: `sch_variant`
* Description: Creates a copy of the schematic with all the filters and variants applied.
This copy isn't intended for development.
Is just a tweaked version of the original where you can look at the results.
* Valid keys:
- `comment`: [string=''] A comment for documentation purposes.
- `dir`: [string='.'] Output directory for the generated files.
- `name`: [string=''] Used to identify this particular output definition.
- `options`: [dict] Options for the `sch_variant` output.
* Valid keys:
- `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.
- `variant`: [string=''] Board variant(s) to apply.

* STEP (ISO 10303-21 Clear Text Encoding of the Exchange Structure)
* Type: `step`
* Description: Exports the PCB as a 3D model.
Expand Down
25 changes: 22 additions & 3 deletions docs/samples/generic_plot.kibot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ outputs:
output: '%f-%i%v.%x'
# [boolean=false] Print grouped references in the alternate compressed style eg: R1-R7,R18
use_alt: false
# [string=''] Board variant(s), used to determine which components
# [string=''] Board variant, used to determine which components
# are output to the BoM.
variant: ''
# [dict] Options for the XLSX format
Expand Down Expand Up @@ -258,8 +258,8 @@ outputs:
exclude_pads_from_silkscreen: false
# [boolean=false] include references and values even when they are marked as invisible
force_plot_invisible_refs_vals: false
# [string='%f-%i.%x'] name for the gerber job file (%i='job', %x='gbrjob')
gerber_job_file: '%f-%i.%x'
# [string='%f-%i%v.%x'] name for the gerber job file (%i='job', %x='gbrjob'). Affected by global options
gerber_job_file: '%f-%i%v.%x'
# [number=4.6] this the gerber coordinate format, can be 4.5 or 4.6
gerber_precision: 4.6
# [number=0.1] [0.02,2] line_width for objects without width [mm]
Expand Down Expand Up @@ -619,8 +619,13 @@ outputs:
type: 'pdf_sch_print'
dir: 'Example/pdf_sch_print_dir'
options:
# [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: ''
# [string='%f-%i%v.%x'] filename for the output PDF (%i=schematic %x=pdf). Affected by global options
output: '%f-%i%v.%x'
# [string=''] Board variant(s), used to determine which components are crossed.
variant: ''

# Pick & place:
# This output is what you get from the 'File/Fabrication output/Footprint poistion (.pos) file' menu in pcbnew.
Expand Down Expand Up @@ -686,6 +691,20 @@ outputs:
width_adjust: 0
layers: all

# Schematic with variant generator:
# This copy isn't intended for development.
# Is just a tweaked version of the original where you can look at the results.
- name: 'sch_variant_example'
comment: 'Creates a copy of the schematic with all the filters and variants applied.'
type: 'sch_variant'
dir: 'Example/sch_variant_dir'
options:
# [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: ''
# [string=''] Board variant(s) to apply
variant: ''

# STEP (ISO 10303-21 Clear Text Encoding of the Exchange Structure):
# This is the most common 3D format for exchange purposes.
# This output is what you get from the 'File/Export/STEP' menu in pcbnew.
Expand Down
1 change: 1 addition & 0 deletions kibot/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
'out_pdf_sch_print',
'out_position',
'out_ps',
'out_sch_variant',
'out_step',
'out_svg',
'out_svg_sch_print',
Expand Down
13 changes: 9 additions & 4 deletions kibot/bom/bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,15 @@ def group_components(cfg, components):

def do_bom(file_name, ext, comps, cfg):
# Apply all the filters
for c in comps:
c.in_bom = cfg.exclude_filter.filter(c)
c.fitted = cfg.dnf_filter.filter(c)
c.fixed = cfg.dnc_filter.filter(c)
if cfg.exclude_filter:
for c in comps:
c.in_bom = cfg.exclude_filter.filter(c)
if cfg.dnf_filter:
for c in comps:
c.fitted = cfg.dnf_filter.filter(c)
if cfg.dnc_filter:
for c in comps:
c.fixed = cfg.dnc_filter.filter(c)
# Apply the variant
cfg.variant.filter(comps)
# Group components according to group_fields
Expand Down
10 changes: 4 additions & 6 deletions kibot/config_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,10 @@ def _parse_variant(self, o_tree, kind, reg_class):
logger.debug("Parsing "+kind+" "+name_type)
o_var = reg_class.get_class_for(otype)()
o_var.set_tree(o_tree)
# No errors yet
# try:
# o_var.config()
# except KiPlotConfigurationError as e:
# config_error("In section `"+name_type+"`: "+str(e))
o_var.config()
try:
o_var.config()
except KiPlotConfigurationError as e:
config_error("In section `"+name_type+"`: "+str(e))
return o_var

def _parse_variants(self, v):
Expand Down
114 changes: 88 additions & 26 deletions kibot/fil_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,23 @@
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from .registrable import RegFilter, Registrable, RegOutput
from .misc import IFILL_MECHANICAL
from .error import KiPlotConfigurationError
from .bom.columnlist import ColumnList
from .macros import macros, document # noqa: F401
from . import log

logger = log.get_logger(__name__)
DEFAULT_EXCLUDE = [{'column': ColumnList.COL_REFERENCE, 'regex': '^TP[0-9]*'},
{'column': ColumnList.COL_REFERENCE, 'regex': '^FID'},
{'column': ColumnList.COL_PART, 'regex': 'mount.*hole'},
{'column': ColumnList.COL_PART, 'regex': 'solder.*bridge'},
{'column': ColumnList.COL_PART, 'regex': 'solder.*jump'},
{'column': ColumnList.COL_PART, 'regex': 'test.*point'},
{'column': ColumnList.COL_FP, 'regex': 'test.*point'},
{'column': ColumnList.COL_FP, 'regex': 'mount.*hole'},
{'column': ColumnList.COL_FP, 'regex': 'fiducial'},
]


class DummyFilter(Registrable):
Expand Down Expand Up @@ -54,6 +69,7 @@ class BaseFilter(RegFilter):
def __init__(self):
super().__init__()
self._unkown_is_error = True
self._internal = False
with document:
self.name = ''
""" Used to identify this particular filter definition """
Expand All @@ -62,8 +78,57 @@ def __init__(self):
self.comment = ''
""" A comment for documentation purposes """

def config(self):
super().config()
if self.name[0] == '_' and not self._internal:
raise KiPlotConfigurationError('Filter names starting with `_` are reserved ({})'.format(self.name))

@staticmethod
def _create_mechanical(name):
o_tree = {'name': name}
o_tree['type'] = 'generic'
o_tree['comment'] = 'Internal default mechanical filter'
o_tree['exclude_all_hash_ref'] = True
o_tree['exclude_any'] = DEFAULT_EXCLUDE
logger.debug('Creating internal filter: '+str(o_tree))
return o_tree

@staticmethod
def _create_kibom_dnx(name):
type = name[7:10]
if len(name) > 11:
subtype = name[11:]
else:
subtype = 'config'
o_tree = {'name': name}
o_tree['type'] = 'generic'
o_tree['comment'] = 'Internal KiBoM '+type.upper()+' filter ('+subtype+')'
o_tree['config_field'] = subtype
o_tree['exclude_value'] = True
o_tree['exclude_config'] = True
o_tree['keys'] = type+'_list'
if type[-1] == 'c':
o_tree['invert'] = True
logger.debug('Creating internal filter: '+str(o_tree))
return o_tree

@staticmethod
def solve_filter(names, def_key, def_real, creator, target_name):
def _create_internal_filter(name):
if name == IFILL_MECHANICAL:
tree = BaseFilter._create_mechanical(name)
elif name.startswith('_kibom_dn') and len(name) >= 10:
tree = BaseFilter._create_kibom_dnx(name)
else:
return None
filter = RegFilter.get_class_for(tree['type'])()
filter._internal = True
filter.set_tree(tree)
filter.config()
RegOutput.add_filter(filter)
return filter

@staticmethod
def solve_filter(names, target_name, default=None):
""" Name can be:
- A class, meaning we have to use a default.
- A string, the name of a filter.
Expand All @@ -72,42 +137,39 @@ def solve_filter(names, def_key, def_real, creator, target_name):
If def_real is not None we pass this name to creator. """
if isinstance(names, type):
# Nothing specified, use the default
names = [def_key]
if default is None:
return None
names = [default]
elif isinstance(names, str):
# User provided, but only one, make a list
if names == '_none':
return None
names = [names]
# Here we should have a list of strings
filters = []
for name in names:
if name and name[0] == '!':
if not name:
continue
if name[0] == '!':
invert = True
name = name[1:]
# '!' => always False
if not name:
filters.append(NotFilter(DummyFilter()))
continue
else:
invert = False
filter = None
if name == def_key:
# Matched the default name, translate it to the real name
if def_real:
name = def_real
# Is already defined?
if RegOutput.is_filter(name):
filter = RegOutput.get_filter(name)
else: # Nope, create it
tree = creator(name)
filter = RegFilter.get_class_for(tree['type'])()
filter.set_tree(tree)
filter.config()
RegOutput.add_filter(filter)
elif name:
# A filter that is supposed to exist
if not RegOutput.is_filter(name):
raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name))
# Is already defined?
if RegOutput.is_filter(name):
filter = RegOutput.get_filter(name)
if filter:
if invert:
filters.append(NotFilter(filter))
else:
filters.append(filter)
else: # Nope, can be created?
filter = BaseFilter._create_internal_filter(name)
if filter is None:
raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name))
if invert:
filters.append(NotFilter(filter))
else:
filters.append(filter)
# Finished collecting filters
if not filters:
return DummyFilter()
Expand Down
5 changes: 5 additions & 0 deletions kibot/fil_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ def __init__(self):
self.exclude_refs = Optionable
""" [list(string)] List of references to be excluded.
Use R* for all references with R prefix """
self.exclude_all_hash_ref = False
""" Exclude all components with a reference starting with # """
# Skip virtual components if needed
# TODO: We currently lack this information
# if config.blacklist_virtual and m.attr == 'Virtual':
Expand Down Expand Up @@ -146,6 +148,9 @@ def filter(self, comp):
# Exclude components with empty 'Value'
if self.exclude_empty_val and (value == '' or value == '~'):
return exclude
# Exclude all ref == #*
if self.exclude_all_hash_ref and comp.ref[0] == '#':
return exclude
# List of references to be excluded
if self.exclude_refs and (comp.ref in self.exclude_refs or comp.ref_prefix+'*' in self.exclude_refs):
return exclude
Expand Down
Loading

0 comments on commit 13ce325

Please sign in to comment.