diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b59c63..59ae525e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.6.4] - UNRELEASED ### Added +- Global options: + - `remove_solder_mask_for_dnp` similar to `remove_solder_paste_for_dnp` but + applied to the solder mask apertures. (#476) - BoM: - Support for ${field} expansion. (#471) - iBoM: diff --git a/README.md b/README.md index 48c53bdd..cc0a5f99 100644 --- a/README.md +++ b/README.md @@ -876,6 +876,7 @@ global: - `pcb_material`: [string='FR4'] PCB core material. Currently used for documentation and to choose default colors. Currently known are FR1 to FR5. - `remove_adhesive_for_dnp`: [boolean=true] When applying filters and variants remove the adhesive (glue) for components that won't be included. + - `remove_solder_mask_for_dnp`: [boolean=false] When applying filters and variants remove the solder mask apertures for components that won't be included. - `remove_solder_paste_for_dnp`: [boolean=true] When applying filters and variants remove the solder paste for components that won't be included. - `resources_dir`: [string='kibot_resources'] Directory where various resources are stored. Currently we support colors and fonts. They must be stored in sub-dirs. I.e. kibot_resources/fonts/MyFont.ttf diff --git a/kibot/globals.py b/kibot/globals.py index 7483d584..6e3b23a1 100644 --- a/kibot/globals.py +++ b/kibot/globals.py @@ -233,6 +233,8 @@ class Globals(FiltersOptions): """ When applying filters and variants remove the solder paste for components that won't be included """ self.remove_adhesive_for_dnp = True """ When applying filters and variants remove the adhesive (glue) for components that won't be included """ + self.remove_solder_mask_for_dnp = False + """ When applying filters and variants remove the solder mask apertures for components that won't be included """ self.restore_project = False """ Restore the KiCad project after execution. Note that this option will undo operations like `set_text_variables` """ diff --git a/kibot/gs.py b/kibot/gs.py index e380382a..125ef092 100644 --- a/kibot/gs.py +++ b/kibot/gs.py @@ -165,6 +165,7 @@ class GS(object): global_pcb_finish = None global_pcb_material = None global_remove_solder_paste_for_dnp = None + global_remove_solder_mask_for_dnp = None global_remove_adhesive_for_dnp = None global_resources_dir = None global_restore_project = None diff --git a/kibot/out_base.py b/kibot/out_base.py index 62495ba7..9901ed41 100644 --- a/kibot/out_base.py +++ b/kibot/out_base.py @@ -377,9 +377,10 @@ class VariantOptions(BaseOptions): def remove_paste_and_glue(self, board, comps_hash): """ Remove from solder paste layers the filtered components. """ - if comps_hash is None or not (GS.global_remove_solder_paste_for_dnp or GS.global_remove_adhesive_for_dnp): + if comps_hash is None or not (GS.global_remove_solder_paste_for_dnp or GS.global_remove_adhesive_for_dnp or + GS.remove_solder_mask_for_dnp): return - logger.debug('Removing paste and glue') + logger.debug('Removing paste, mask and/or glue') exclude = LSET() fpaste = board.GetLayerID('F.Paste') bpaste = board.GetLayerID('B.Paste') @@ -390,19 +391,24 @@ class VariantOptions(BaseOptions): badhes = board.GetLayerID('B.Adhes') old_fadhes = [] old_badhes = [] + old_fmask = [] + old_bmask = [] rescue = board.GetLayerID(GS.work_layer) fmask = board.GetLayerID('F.Mask') bmask = board.GetLayerID('B.Mask') + if GS.global_remove_solder_mask_for_dnp: + exclude.addLayer(fmask) + exclude.addLayer(bmask) for m in GS.get_modules_board(board): ref = m.GetReference() c = comps_hash.get(ref, None) if c and c.included and not c.fitted: # Remove all pads from *.Paste - if GS.global_remove_solder_paste_for_dnp: + if GS.global_remove_solder_paste_for_dnp or GS.global_remove_solder_mask_for_dnp: old_c_layers = [] for p in m.Pads(): pad_layers = p.GetLayerSet() - is_front = fpaste in pad_layers.Seq() + is_front = (fpaste in pad_layers.Seq()) or (fmask in pad_layers.Seq()) old_c_layers.append(pad_layers.FmtHex()) pad_layers.removeLayerSet(exclude) if len(pad_layers.Seq()) == 0: @@ -412,7 +418,7 @@ class VariantOptions(BaseOptions): logger.warning(W_WRONGPASTE+'Pad with solder paste, but no copper or solder mask aperture in '+ref) p.SetLayerSet(pad_layers) old_layers.append(old_c_layers) - logger.debugl(3, '- Removed paste from '+ref) + logger.debugl(3, '- Removed paste/mask from '+ref) # Remove any graphical item in the *.Adhes layers if GS.global_remove_adhesive_for_dnp: found = False @@ -428,24 +434,42 @@ class VariantOptions(BaseOptions): found = True if found: logger.debugl(3, '- Removed adhesive from '+ref) + if GS.global_remove_solder_mask_for_dnp: + found = False + for gi in m.GraphicalItems(): + l_gi = gi.GetLayer() + if l_gi == fmask: + gi.SetLayer(rescue) + old_fmask.append(gi) + found = True + if l_gi == bmask: + gi.SetLayer(rescue) + old_bmask.append(gi) + found = True + if found: + logger.debugl(3, '- Removed mask from '+ref) # Store the data to undo the above actions self.old_layers = old_layers self.old_fadhes = old_fadhes self.old_badhes = old_badhes + self.old_fmask = old_fmask + self.old_bmask = old_bmask self._fadhes = fadhes self._badhes = badhes + self._fmask = fmask + self._bmask = bmask return exclude def restore_paste_and_glue(self, board, comps_hash): if comps_hash is None: return - logger.debug('Restoring paste and glue') - if GS.global_remove_solder_paste_for_dnp: + logger.debug('Restoring paste, mask and/or glue') + if GS.global_remove_solder_paste_for_dnp or GS.global_remove_solder_mask_for_dnp: for m in GS.get_modules_board(board): ref = m.GetReference() c = comps_hash.get(ref, None) if c and c.included and not c.fitted: - logger.debugl(3, '- Restoring paste for '+ref) + logger.debugl(3, '- Restoring paste/mask for '+ref) restore = self.old_layers.pop(0) for p in m.Pads(): pad_layers = p.GetLayerSet() @@ -457,6 +481,10 @@ class VariantOptions(BaseOptions): gi.SetLayer(self._fadhes) for gi in self.old_badhes: gi.SetLayer(self._badhes) + for gi in self.old_fmask: + gi.SetLayer(self._fmask) + for gi in self.old_bmask: + gi.SetLayer(self._bmask) def remove_fab(self, board, comps_hash): """ Remove from Fab the excluded components. """ diff --git a/tests/test_plot/test_gerber.py b/tests/test_plot/test_gerber.py index 16443e6e..1f2c563f 100644 --- a/tests/test_plot/test_gerber.py +++ b/tests/test_plot/test_gerber.py @@ -150,13 +150,14 @@ def test_gerber_variant_1(test_dir): # R3 is a component added to the PCB, included in all cases # variant: default directory: gerber components: R1, R2 and R3 check_layers_exist(ctx, 'gerber', prj, ALL_LAYERS, '') - check_components(ctx, 'gerber', prj, ['F_Paste', 'F_Adhes'], '', ['C1', 'C2'], ['R1', 'R2', 'R3']) + check_components(ctx, 'gerber', prj, ['F_Paste', 'F_Adhes', 'F_Mask'], '', ['C1', 'C2'], ['R1', 'R2', 'R3']) # variant: production directory: production components: R1, R2, R3 and C2 check_layers_exist(ctx, 'production', prj, ALL_LAYERS, '_(production)') - check_components(ctx, 'production', prj, ['F_Paste', 'F_Adhes'], '_(production)', ['C1'], ['R1', 'R2', 'R3', 'C2']) + check_components(ctx, 'production', prj, ['F_Paste', 'F_Adhes', 'F_Mask'], '_(production)', ['C1'], + ['R1', 'R2', 'R3', 'C2']) # variant: test directory: test components: R1, R3 and C2 check_layers_exist(ctx, 'test', prj, ALL_LAYERS, '_(test)') - check_components(ctx, 'test', prj, ['F_Paste', 'F_Adhes'], '_(test)', ['R2'], ['C1', 'R1', 'R3', 'C2']) + check_components(ctx, 'test', prj, ['F_Paste', 'F_Adhes', 'F_Mask'], '_(test)', ['R2'], ['C1', 'R1', 'R3', 'C2']) ctx.clean_up(keep_project=True) diff --git a/tests/yaml_samples/gerber_variant_1.kibot.yaml b/tests/yaml_samples/gerber_variant_1.kibot.yaml index 70c38f23..b879d37b 100644 --- a/tests/yaml_samples/gerber_variant_1.kibot.yaml +++ b/tests/yaml_samples/gerber_variant_1.kibot.yaml @@ -2,6 +2,9 @@ kibot: version: 1 +global: + remove_solder_mask_for_dnp: true + variants: - name: 'production' comment: 'Production variant'