Skip to content

Commit 13ce325

Browse files
authored
Merge pull request johnbeard#6 from INTI-CMNB/gen_sch_variant
Gen sch variant
2 parents 48be2fa + 6fa903e commit 13ce325

38 files changed

+1197
-131
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99
### Added
1010
- Now variants are separated entities.
11-
- Only the internal BoM currently supports it.
11+
- Only the internal BoM and Schematic print currently supports it.
1212
- In the future IBoM will also support it, contact me if you think this is
1313
high priority.
1414
- New filters entities. They implement all the functionality in KiBoM and IBoM.
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- Marking components as "Do Not Fit"
1919
- Marking components as "Do Not Change"
2020
- The internal BoM format supports KiBoM and IBoM style variants
21+
- Schematic print to PDF supports variants. Not fitted components are crossed.
2122

2223
## [0.6.2] - 2020-08-25
2324
### Changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ gen_ref:
106106
cp -a $(REFILL).refill $(REFILL)
107107
src/kibot -c tests/yaml_samples/pdf_zone-refill.kibot.yaml -b tests/board_samples/zone-refill.kicad_pcb -d $(REFDIR)
108108
src/kibot -c tests/yaml_samples/print_pcb_zone-refill.kibot.yaml -b tests/board_samples/zone-refill.kicad_pcb -d $(REFDIR)
109+
src/kibot -c tests/yaml_samples/print_pdf_no_inductors_1.kibot.yaml -e tests/board_samples/test_v5.sch -d $(REFDIR)
110+
mv "$(REFDIR)no_inductor/test_v5-schematic_(no_L).pdf" $(REFDIR)
111+
rmdir $(REFDIR)no_inductor/
109112
cp -a $(REFILL).ok $(REFILL)
110113

111114
doc:

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ Next time you need this list just use an alias, like this:
405405
- `number`: [number=1] Number of boards to build (components multiplier).
406406
- `output`: [string='%f-%i%v.%x'] filename for the output (%i=bom). Affected by global options.
407407
- `use_alt`: [boolean=false] Print grouped references in the alternate compressed style eg: R1-R7,R18.
408-
- `variant`: [string=''] Board variant(s), used to determine which components
408+
- `variant`: [string=''] Board variant, used to determine which components
409409
are output to the BoM..
410410
- `xlsx`: [dict] Options for the XLSX format.
411411
* Valid keys:
@@ -522,7 +522,7 @@ Next time you need this list just use an alias, like this:
522522
- `exclude_edge_layer`: [boolean=true] do not include the PCB edge layer.
523523
- `exclude_pads_from_silkscreen`: [boolean=false] do not plot the component pads in the silk screen.
524524
- `force_plot_invisible_refs_vals`: [boolean=false] include references and values even when they are marked as invisible.
525-
- `gerber_job_file`: [string='%f-%i.%x'] name for the gerber job file (%i='job', %x='gbrjob').
525+
- `gerber_job_file`: [string='%f-%i%v.%x'] name for the gerber job file (%i='job', %x='gbrjob'). Affected by global options.
526526
- `gerber_precision`: [number=4.6] this the gerber coordinate format, can be 4.5 or 4.6.
527527
- `line_width`: [number=0.1] [0.02,2] line_width for objects without width [mm].
528528
- `output`: [string='%f-%i%v.%x'] output file name, the default KiCad name if empty. Affected by global options.
@@ -812,7 +812,10 @@ Next time you need this list just use an alias, like this:
812812
- `name`: [string=''] Used to identify this particular output definition.
813813
- `options`: [dict] Options for the `pdf_sch_print` output.
814814
* Valid keys:
815+
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
816+
A short-cut to use for simple cases where a variant is an overkill.
815817
- `output`: [string='%f-%i%v.%x'] filename for the output PDF (%i=schematic %x=pdf). Affected by global options.
818+
- `variant`: [string=''] Board variant(s), used to determine which components are crossed..
816819

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

872+
* Schematic with variant generator
873+
* Type: `sch_variant`
874+
* Description: Creates a copy of the schematic with all the filters and variants applied.
875+
This copy isn't intended for development.
876+
Is just a tweaked version of the original where you can look at the results.
877+
* Valid keys:
878+
- `comment`: [string=''] A comment for documentation purposes.
879+
- `dir`: [string='.'] Output directory for the generated files.
880+
- `name`: [string=''] Used to identify this particular output definition.
881+
- `options`: [dict] Options for the `sch_variant` output.
882+
* Valid keys:
883+
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
884+
A short-cut to use for simple cases where a variant is an overkill.
885+
- `variant`: [string=''] Board variant(s) to apply.
886+
869887
* STEP (ISO 10303-21 Clear Text Encoding of the Exchange Structure)
870888
* Type: `step`
871889
* Description: Exports the PCB as a 3D model.

docs/samples/generic_plot.kibot.yaml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ outputs:
121121
output: '%f-%i%v.%x'
122122
# [boolean=false] Print grouped references in the alternate compressed style eg: R1-R7,R18
123123
use_alt: false
124-
# [string=''] Board variant(s), used to determine which components
124+
# [string=''] Board variant, used to determine which components
125125
# are output to the BoM.
126126
variant: ''
127127
# [dict] Options for the XLSX format
@@ -258,8 +258,8 @@ outputs:
258258
exclude_pads_from_silkscreen: false
259259
# [boolean=false] include references and values even when they are marked as invisible
260260
force_plot_invisible_refs_vals: false
261-
# [string='%f-%i.%x'] name for the gerber job file (%i='job', %x='gbrjob')
262-
gerber_job_file: '%f-%i.%x'
261+
# [string='%f-%i%v.%x'] name for the gerber job file (%i='job', %x='gbrjob'). Affected by global options
262+
gerber_job_file: '%f-%i%v.%x'
263263
# [number=4.6] this the gerber coordinate format, can be 4.5 or 4.6
264264
gerber_precision: 4.6
265265
# [number=0.1] [0.02,2] line_width for objects without width [mm]
@@ -619,8 +619,13 @@ outputs:
619619
type: 'pdf_sch_print'
620620
dir: 'Example/pdf_sch_print_dir'
621621
options:
622+
# [string|list(string)=''] Name of the filter to mark components as not fitted.
623+
# A short-cut to use for simple cases where a variant is an overkill
624+
dnf_filter: ''
622625
# [string='%f-%i%v.%x'] filename for the output PDF (%i=schematic %x=pdf). Affected by global options
623626
output: '%f-%i%v.%x'
627+
# [string=''] Board variant(s), used to determine which components are crossed.
628+
variant: ''
624629

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

694+
# Schematic with variant generator:
695+
# This copy isn't intended for development.
696+
# Is just a tweaked version of the original where you can look at the results.
697+
- name: 'sch_variant_example'
698+
comment: 'Creates a copy of the schematic with all the filters and variants applied.'
699+
type: 'sch_variant'
700+
dir: 'Example/sch_variant_dir'
701+
options:
702+
# [string|list(string)=''] Name of the filter to mark components as not fitted.
703+
# A short-cut to use for simple cases where a variant is an overkill
704+
dnf_filter: ''
705+
# [string=''] Board variant(s) to apply
706+
variant: ''
707+
689708
# STEP (ISO 10303-21 Clear Text Encoding of the Exchange Structure):
690709
# This is the most common 3D format for exchange purposes.
691710
# This output is what you get from the 'File/Export/STEP' menu in pcbnew.

kibot/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
'out_pdf_sch_print',
9595
'out_position',
9696
'out_ps',
97+
'out_sch_variant',
9798
'out_step',
9899
'out_svg',
99100
'out_svg_sch_print',

kibot/bom/bom.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,15 @@ def group_components(cfg, components):
363363

364364
def do_bom(file_name, ext, comps, cfg):
365365
# Apply all the filters
366-
for c in comps:
367-
c.in_bom = cfg.exclude_filter.filter(c)
368-
c.fitted = cfg.dnf_filter.filter(c)
369-
c.fixed = cfg.dnc_filter.filter(c)
366+
if cfg.exclude_filter:
367+
for c in comps:
368+
c.in_bom = cfg.exclude_filter.filter(c)
369+
if cfg.dnf_filter:
370+
for c in comps:
371+
c.fitted = cfg.dnf_filter.filter(c)
372+
if cfg.dnc_filter:
373+
for c in comps:
374+
c.fixed = cfg.dnc_filter.filter(c)
370375
# Apply the variant
371376
cfg.variant.filter(comps)
372377
# Group components according to group_fields

kibot/config_reader.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,10 @@ def _parse_variant(self, o_tree, kind, reg_class):
109109
logger.debug("Parsing "+kind+" "+name_type)
110110
o_var = reg_class.get_class_for(otype)()
111111
o_var.set_tree(o_tree)
112-
# No errors yet
113-
# try:
114-
# o_var.config()
115-
# except KiPlotConfigurationError as e:
116-
# config_error("In section `"+name_type+"`: "+str(e))
117-
o_var.config()
112+
try:
113+
o_var.config()
114+
except KiPlotConfigurationError as e:
115+
config_error("In section `"+name_type+"`: "+str(e))
118116
return o_var
119117

120118
def _parse_variants(self, v):

kibot/fil_base.py

Lines changed: 88 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,23 @@
44
# License: GPL-3.0
55
# Project: KiBot (formerly KiPlot)
66
from .registrable import RegFilter, Registrable, RegOutput
7+
from .misc import IFILL_MECHANICAL
78
from .error import KiPlotConfigurationError
9+
from .bom.columnlist import ColumnList
810
from .macros import macros, document # noqa: F401
11+
from . import log
12+
13+
logger = log.get_logger(__name__)
14+
DEFAULT_EXCLUDE = [{'column': ColumnList.COL_REFERENCE, 'regex': '^TP[0-9]*'},
15+
{'column': ColumnList.COL_REFERENCE, 'regex': '^FID'},
16+
{'column': ColumnList.COL_PART, 'regex': 'mount.*hole'},
17+
{'column': ColumnList.COL_PART, 'regex': 'solder.*bridge'},
18+
{'column': ColumnList.COL_PART, 'regex': 'solder.*jump'},
19+
{'column': ColumnList.COL_PART, 'regex': 'test.*point'},
20+
{'column': ColumnList.COL_FP, 'regex': 'test.*point'},
21+
{'column': ColumnList.COL_FP, 'regex': 'mount.*hole'},
22+
{'column': ColumnList.COL_FP, 'regex': 'fiducial'},
23+
]
924

1025

1126
class DummyFilter(Registrable):
@@ -54,6 +69,7 @@ class BaseFilter(RegFilter):
5469
def __init__(self):
5570
super().__init__()
5671
self._unkown_is_error = True
72+
self._internal = False
5773
with document:
5874
self.name = ''
5975
""" Used to identify this particular filter definition """
@@ -62,8 +78,57 @@ def __init__(self):
6278
self.comment = ''
6379
""" A comment for documentation purposes """
6480

81+
def config(self):
82+
super().config()
83+
if self.name[0] == '_' and not self._internal:
84+
raise KiPlotConfigurationError('Filter names starting with `_` are reserved ({})'.format(self.name))
85+
86+
@staticmethod
87+
def _create_mechanical(name):
88+
o_tree = {'name': name}
89+
o_tree['type'] = 'generic'
90+
o_tree['comment'] = 'Internal default mechanical filter'
91+
o_tree['exclude_all_hash_ref'] = True
92+
o_tree['exclude_any'] = DEFAULT_EXCLUDE
93+
logger.debug('Creating internal filter: '+str(o_tree))
94+
return o_tree
95+
96+
@staticmethod
97+
def _create_kibom_dnx(name):
98+
type = name[7:10]
99+
if len(name) > 11:
100+
subtype = name[11:]
101+
else:
102+
subtype = 'config'
103+
o_tree = {'name': name}
104+
o_tree['type'] = 'generic'
105+
o_tree['comment'] = 'Internal KiBoM '+type.upper()+' filter ('+subtype+')'
106+
o_tree['config_field'] = subtype
107+
o_tree['exclude_value'] = True
108+
o_tree['exclude_config'] = True
109+
o_tree['keys'] = type+'_list'
110+
if type[-1] == 'c':
111+
o_tree['invert'] = True
112+
logger.debug('Creating internal filter: '+str(o_tree))
113+
return o_tree
114+
65115
@staticmethod
66-
def solve_filter(names, def_key, def_real, creator, target_name):
116+
def _create_internal_filter(name):
117+
if name == IFILL_MECHANICAL:
118+
tree = BaseFilter._create_mechanical(name)
119+
elif name.startswith('_kibom_dn') and len(name) >= 10:
120+
tree = BaseFilter._create_kibom_dnx(name)
121+
else:
122+
return None
123+
filter = RegFilter.get_class_for(tree['type'])()
124+
filter._internal = True
125+
filter.set_tree(tree)
126+
filter.config()
127+
RegOutput.add_filter(filter)
128+
return filter
129+
130+
@staticmethod
131+
def solve_filter(names, target_name, default=None):
67132
""" Name can be:
68133
- A class, meaning we have to use a default.
69134
- A string, the name of a filter.
@@ -72,42 +137,39 @@ def solve_filter(names, def_key, def_real, creator, target_name):
72137
If def_real is not None we pass this name to creator. """
73138
if isinstance(names, type):
74139
# Nothing specified, use the default
75-
names = [def_key]
140+
if default is None:
141+
return None
142+
names = [default]
76143
elif isinstance(names, str):
77144
# User provided, but only one, make a list
145+
if names == '_none':
146+
return None
78147
names = [names]
79148
# Here we should have a list of strings
80149
filters = []
81150
for name in names:
82-
if name and name[0] == '!':
151+
if not name:
152+
continue
153+
if name[0] == '!':
83154
invert = True
84155
name = name[1:]
156+
# '!' => always False
157+
if not name:
158+
filters.append(NotFilter(DummyFilter()))
159+
continue
85160
else:
86161
invert = False
87-
filter = None
88-
if name == def_key:
89-
# Matched the default name, translate it to the real name
90-
if def_real:
91-
name = def_real
92-
# Is already defined?
93-
if RegOutput.is_filter(name):
94-
filter = RegOutput.get_filter(name)
95-
else: # Nope, create it
96-
tree = creator(name)
97-
filter = RegFilter.get_class_for(tree['type'])()
98-
filter.set_tree(tree)
99-
filter.config()
100-
RegOutput.add_filter(filter)
101-
elif name:
102-
# A filter that is supposed to exist
103-
if not RegOutput.is_filter(name):
104-
raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name))
162+
# Is already defined?
163+
if RegOutput.is_filter(name):
105164
filter = RegOutput.get_filter(name)
106-
if filter:
107-
if invert:
108-
filters.append(NotFilter(filter))
109-
else:
110-
filters.append(filter)
165+
else: # Nope, can be created?
166+
filter = BaseFilter._create_internal_filter(name)
167+
if filter is None:
168+
raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name))
169+
if invert:
170+
filters.append(NotFilter(filter))
171+
else:
172+
filters.append(filter)
111173
# Finished collecting filters
112174
if not filters:
113175
return DummyFilter()

kibot/fil_generic.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ def __init__(self):
6464
self.exclude_refs = Optionable
6565
""" [list(string)] List of references to be excluded.
6666
Use R* for all references with R prefix """
67+
self.exclude_all_hash_ref = False
68+
""" Exclude all components with a reference starting with # """
6769
# Skip virtual components if needed
6870
# TODO: We currently lack this information
6971
# if config.blacklist_virtual and m.attr == 'Virtual':
@@ -146,6 +148,9 @@ def filter(self, comp):
146148
# Exclude components with empty 'Value'
147149
if self.exclude_empty_val and (value == '' or value == '~'):
148150
return exclude
151+
# Exclude all ref == #*
152+
if self.exclude_all_hash_ref and comp.ref[0] == '#':
153+
return exclude
149154
# List of references to be excluded
150155
if self.exclude_refs and (comp.ref in self.exclude_refs or comp.ref_prefix+'*' in self.exclude_refs):
151156
return exclude

0 commit comments

Comments
 (0)