diff --git a/kibot/fil_generic.py b/kibot/fil_generic.py index b6feb68a..60014f8a 100644 --- a/kibot/fil_generic.py +++ b/kibot/fil_generic.py @@ -66,10 +66,12 @@ class Generic(BaseFilter): # noqa: F821 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': - # return True + self.exclude_virtual = False + """ KiCad 5: exclude components marked as virtual in the PCB """ + self.exclude_smd = False + """ KiCad 5: exclude components marked as smd in the PCB """ + self.exclude_tht = False + """ KiCad 5: exclude components marked as through-hole in the PCB """ self.add_to_doc('keys', 'Use `dnf_list` for '+str(DNF)) self.add_to_doc('keys', 'Use `dnc_list` for '+str(DNC)) @@ -151,6 +153,13 @@ class Generic(BaseFilter): # noqa: F821 # Exclude all ref == #* if self.exclude_all_hash_ref and comp.ref[0] == '#': return exclude + # KiCad 5 PCB classification + if self.exclude_virtual and comp.virtual: + return exclude + if self.exclude_smd and comp.smd: + return exclude + if self.exclude_tht and comp.tht: + 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 diff --git a/kibot/gs.py b/kibot/gs.py index 6141bc2e..1dac6c3f 100644 --- a/kibot/gs.py +++ b/kibot/gs.py @@ -19,13 +19,13 @@ class GS(object): Is a static class, just a placeholder for some global variables. """ # PCB name and useful parts - pcb_file = None # /.../dir/file.sch - pcb_no_ext = None # /.../dir/file + pcb_file = None # /.../dir/pcb.kicad_pcb + pcb_no_ext = None # /.../dir/pcb pcb_dir = None # /.../dir pcb_basename = None # file # SCH name and useful parts - sch_file = None # /.../dir/pcb.kicad_pcb - sch_basename = None # /.../dir/pcb + sch_file = None # /.../dir/file.sch + sch_basename = None # /.../dir/file sch_no_ext = None # /.../dir sch_dir = None # pcb # Main output dir @@ -39,6 +39,7 @@ class GS(object): today = n.strftime('%Y-%m-%d') time = n.strftime('%H-%M-%S') kicad_version = '' + board_comps_joined = False # Flag to indicate we already merged data from the board # Data from the SCH because it doesn't have a Python API sch_title = None sch_date = None diff --git a/kibot/kicad/v5_sch.py b/kibot/kicad/v5_sch.py index e877145c..f179d089 100644 --- a/kibot/kicad/v5_sch.py +++ b/kibot/kicad/v5_sch.py @@ -803,6 +803,10 @@ class SchematicComponent(object): self.fitted = True self.in_bom = True self.fixed = False + # KiCad 5 PCB flags (mutually exclusive) + self.smd = False + self.virtual = False + self.tht = False def get_field_value(self, field): field = field.lower() diff --git a/kibot/kiplot.py b/kibot/kiplot.py index 693f9f07..68cb8ff4 100644 --- a/kibot/kiplot.py +++ b/kibot/kiplot.py @@ -169,6 +169,28 @@ def load_sch(): exit(EXIT_BAD_CONFIG) +def get_board_comps_data(comps): + if GS.board_comps_joined or not GS.pcb_file: + return + if not GS.board: + load_board() + comps_hash = {c.ref: c for c in comps} + for m in GS.board.GetModules(): + ref = m.GetReference() + if ref not in comps_hash: + logger.warning('{} component in board, but not in schematic'.format(ref)) + continue + c = comps_hash[ref] + attrs = m.GetAttributes() + # KiCad 5 (6 will change it) + if attrs == 1: + c.smd = True + elif attrs == 2: + c.virtual = True + else: + c.tht = True + + def preflight_checks(skip_pre): logger.debug("Preflight checks") diff --git a/kibot/out_bom.py b/kibot/out_bom.py index 23e1d7ac..7dd60285 100644 --- a/kibot/out_bom.py +++ b/kibot/out_bom.py @@ -13,6 +13,7 @@ from .optionable import Optionable, BaseOptions from .registrable import RegOutput from .error import KiPlotConfigurationError from .misc import IFILL_MECHANICAL +from .kiplot import get_board_comps_data from .macros import macros, document, output_class # noqa: F401 from .bom.columnlist import ColumnList, BoMError from .bom.bom import do_bom @@ -364,6 +365,7 @@ class BoMOptions(BaseOptions): self.kicad_version = GS.kicad_version # Get the components list from the schematic comps = GS.sch.get_components() + get_board_comps_data(comps) try: do_bom(output, format, comps, self) except BoMError as e: diff --git a/tests/board_samples/kibom-variant_3.kicad_pcb b/tests/board_samples/kibom-variant_3.kicad_pcb index 7cb862b7..5092b44a 100644 --- a/tests/board_samples/kibom-variant_3.kicad_pcb +++ b/tests/board_samples/kibom-variant_3.kicad_pcb @@ -121,26 +121,25 @@ (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator") (tags resistor) (path /5F43D4BB) - (attr smd) (fp_text reference R2 (at 0 -1.65) (layer F.SilkS) (effects (font (size 1 1) (thickness 0.15))) ) (fp_text value 1000 (at 0 1.65) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))) ) + (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) (fp_text user %R (at 0 0) (layer F.Fab) (effects (font (size 0.5 0.5) (thickness 0.08))) ) - (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) (pad 2 smd roundrect (at 0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) (net 7 "Net-(R2-Pad2)")) (pad 1 smd roundrect (at -0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) @@ -164,19 +163,19 @@ (fp_text value 1k (at 0 1.65) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))) ) + (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) (fp_text user %R (at 0 0) (layer F.Fab) (effects (font (size 0.5 0.5) (thickness 0.08))) ) - (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) (pad 2 smd roundrect (at 0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) (net 5 "Net-(R1-Pad2)")) (pad 1 smd roundrect (at -0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) @@ -193,26 +192,25 @@ (descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator") (tags capacitor) (path /5F43CE1C) - (attr smd) (fp_text reference C2 (at 0 -1.65) (layer F.SilkS) (effects (font (size 1 1) (thickness 0.15))) ) (fp_text value "1000 pF" (at 0 1.65) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))) ) + (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) (fp_text user %R (at 0 0) (layer F.Fab) (effects (font (size 0.5 0.5) (thickness 0.08))) ) - (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) (pad 2 smd roundrect (at 0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) (net 3 "Net-(C2-Pad2)")) (pad 1 smd roundrect (at -0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) @@ -229,26 +227,26 @@ (descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator") (tags capacitor) (path /5F43BEC2) - (attr smd) + (attr virtual) (fp_text reference C1 (at 0 -1.65) (layer F.SilkS) (effects (font (size 1 1) (thickness 0.15))) ) (fp_text value 1nF (at 0 1.65) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))) ) + (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) + (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) + (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) (fp_text user %R (at 0 0) (layer F.Fab) (effects (font (size 0.5 0.5) (thickness 0.08))) ) - (fp_line (start -1 0.6) (end -1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -1 -0.6) (end 1 -0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 -0.6) (end 1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start 1 0.6) (end -1 0.6) (layer F.Fab) (width 0.1)) - (fp_line (start -0.258578 -0.71) (end 0.258578 -0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -0.258578 0.71) (end 0.258578 0.71) (layer F.SilkS) (width 0.12)) - (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) - (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) (pad 2 smd roundrect (at 0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) (net 1 "Net-(C1-Pad2)")) (pad 1 smd roundrect (at -0.9375 0) (size 0.975 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) diff --git a/tests/test_plot/test_int_bom.py b/tests/test_plot/test_int_bom.py index d1ca4c5d..b83b1525 100644 --- a/tests/test_plot/test_int_bom.py +++ b/tests/test_plot/test_int_bom.py @@ -1285,6 +1285,20 @@ def test_int_bom_fil_1(): ctx.clean_up() +def test_int_bom_fil_2(): + prj = 'kibom-variant_3' + ctx = context.TestContextSCH('test_int_bom_fil_2', prj, 'int_bom_fil_2', BOM_DIR) + ctx.run() + rows, header, info = ctx.load_csv('smd.csv') + ref_column = header.index(REF_COLUMN_NAME) + check_kibom_test_netlist(rows, ref_column, 2, None, ['R2', 'C1-C2']) + rows, header, info = ctx.load_csv('tht.csv') + check_kibom_test_netlist(rows, ref_column, 2, None, ['R1', 'C1']) + rows, header, info = ctx.load_csv('virtual.csv') + check_kibom_test_netlist(rows, ref_column, 2, None, ['R1-R2', 'C2']) + ctx.clean_up() + + def test_int_bom_variant_t3(): """ Test if we can move the filters to the variant. Also test the '!' filter (always false) """ diff --git a/tests/yaml_samples/int_bom_fil_2.kibot.yaml b/tests/yaml_samples/int_bom_fil_2.kibot.yaml new file mode 100644 index 00000000..d299197d --- /dev/null +++ b/tests/yaml_samples/int_bom_fil_2.kibot.yaml @@ -0,0 +1,48 @@ +# Example KiBot config file +kibot: + version: 1 + +filters: + - name: 'no smd' + type: 'generic' + comment: 'Remove components with smd attribute' + exclude_smd: true + + - name: 'no tht' + type: 'generic' + comment: 'Remove components with through-hole attribute' + exclude_tht: true + + - name: 'no virtual' + type: 'generic' + comment: 'Remove components with virtual attribute' + exclude_virtual: true + +outputs: + - name: 'no smd' + comment: "BoM no smd" + type: bom + dir: BoM + options: + output: 'smd.csv' + use_alt: true + exclude_filter: 'no smd' + + - name: 'no tht' + comment: "BoM no THT" + type: bom + dir: BoM + options: + output: 'tht.csv' + use_alt: true + exclude_filter: 'no tht' + + - name: 'no smd' + comment: "BoM no virtual" + type: bom + dir: BoM + options: + output: 'virtual.csv' + use_alt: true + exclude_filter: 'no virtual' +