[Global options][Add] Option to remove solder mask apertures

`remove_solder_mask_for_dnp` similar to `remove_solder_paste_for_dnp`
but applied to the solder mask apertures.

Closes #476
This commit is contained in:
Salvador E. Tropea 2023-08-04 12:31:17 -03:00
parent 9c6ca87214
commit abeea7ec03
7 changed files with 50 additions and 11 deletions

View File

@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.6.4] - UNRELEASED ## [1.6.4] - UNRELEASED
### Added ### Added
- Global options:
- `remove_solder_mask_for_dnp` similar to `remove_solder_paste_for_dnp` but
applied to the solder mask apertures. (#476)
- BoM: - BoM:
- Support for ${field} expansion. (#471) - Support for ${field} expansion. (#471)
- iBoM: - iBoM:

View File

@ -876,6 +876,7 @@ global:
- `pcb_material`: [string='FR4'] PCB core material. Currently used for documentation and to choose default colors. - `pcb_material`: [string='FR4'] PCB core material. Currently used for documentation and to choose default colors.
Currently known are FR1 to FR5. 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_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. - `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. - `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 They must be stored in sub-dirs. I.e. kibot_resources/fonts/MyFont.ttf

View File

@ -233,6 +233,8 @@ class Globals(FiltersOptions):
""" When applying filters and variants remove the solder paste for components that won't be included """ """ When applying filters and variants remove the solder paste for components that won't be included """
self.remove_adhesive_for_dnp = True self.remove_adhesive_for_dnp = True
""" When applying filters and variants remove the adhesive (glue) for components that won't be included """ """ 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 self.restore_project = False
""" Restore the KiCad project after execution. """ Restore the KiCad project after execution.
Note that this option will undo operations like `set_text_variables` """ Note that this option will undo operations like `set_text_variables` """

View File

@ -165,6 +165,7 @@ class GS(object):
global_pcb_finish = None global_pcb_finish = None
global_pcb_material = None global_pcb_material = None
global_remove_solder_paste_for_dnp = None global_remove_solder_paste_for_dnp = None
global_remove_solder_mask_for_dnp = None
global_remove_adhesive_for_dnp = None global_remove_adhesive_for_dnp = None
global_resources_dir = None global_resources_dir = None
global_restore_project = None global_restore_project = None

View File

@ -377,9 +377,10 @@ class VariantOptions(BaseOptions):
def remove_paste_and_glue(self, board, comps_hash): def remove_paste_and_glue(self, board, comps_hash):
""" Remove from solder paste layers the filtered components. """ """ 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 return
logger.debug('Removing paste and glue') logger.debug('Removing paste, mask and/or glue')
exclude = LSET() exclude = LSET()
fpaste = board.GetLayerID('F.Paste') fpaste = board.GetLayerID('F.Paste')
bpaste = board.GetLayerID('B.Paste') bpaste = board.GetLayerID('B.Paste')
@ -390,19 +391,24 @@ class VariantOptions(BaseOptions):
badhes = board.GetLayerID('B.Adhes') badhes = board.GetLayerID('B.Adhes')
old_fadhes = [] old_fadhes = []
old_badhes = [] old_badhes = []
old_fmask = []
old_bmask = []
rescue = board.GetLayerID(GS.work_layer) rescue = board.GetLayerID(GS.work_layer)
fmask = board.GetLayerID('F.Mask') fmask = board.GetLayerID('F.Mask')
bmask = board.GetLayerID('B.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): for m in GS.get_modules_board(board):
ref = m.GetReference() ref = m.GetReference()
c = comps_hash.get(ref, None) c = comps_hash.get(ref, None)
if c and c.included and not c.fitted: if c and c.included and not c.fitted:
# Remove all pads from *.Paste # 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 = [] old_c_layers = []
for p in m.Pads(): for p in m.Pads():
pad_layers = p.GetLayerSet() 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()) old_c_layers.append(pad_layers.FmtHex())
pad_layers.removeLayerSet(exclude) pad_layers.removeLayerSet(exclude)
if len(pad_layers.Seq()) == 0: 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) logger.warning(W_WRONGPASTE+'Pad with solder paste, but no copper or solder mask aperture in '+ref)
p.SetLayerSet(pad_layers) p.SetLayerSet(pad_layers)
old_layers.append(old_c_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 # Remove any graphical item in the *.Adhes layers
if GS.global_remove_adhesive_for_dnp: if GS.global_remove_adhesive_for_dnp:
found = False found = False
@ -428,24 +434,42 @@ class VariantOptions(BaseOptions):
found = True found = True
if found: if found:
logger.debugl(3, '- Removed adhesive from '+ref) 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 # Store the data to undo the above actions
self.old_layers = old_layers self.old_layers = old_layers
self.old_fadhes = old_fadhes self.old_fadhes = old_fadhes
self.old_badhes = old_badhes self.old_badhes = old_badhes
self.old_fmask = old_fmask
self.old_bmask = old_bmask
self._fadhes = fadhes self._fadhes = fadhes
self._badhes = badhes self._badhes = badhes
self._fmask = fmask
self._bmask = bmask
return exclude return exclude
def restore_paste_and_glue(self, board, comps_hash): def restore_paste_and_glue(self, board, comps_hash):
if comps_hash is None: if comps_hash is None:
return return
logger.debug('Restoring paste and glue') logger.debug('Restoring paste, mask and/or glue')
if GS.global_remove_solder_paste_for_dnp: if GS.global_remove_solder_paste_for_dnp or GS.global_remove_solder_mask_for_dnp:
for m in GS.get_modules_board(board): for m in GS.get_modules_board(board):
ref = m.GetReference() ref = m.GetReference()
c = comps_hash.get(ref, None) c = comps_hash.get(ref, None)
if c and c.included and not c.fitted: 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) restore = self.old_layers.pop(0)
for p in m.Pads(): for p in m.Pads():
pad_layers = p.GetLayerSet() pad_layers = p.GetLayerSet()
@ -457,6 +481,10 @@ class VariantOptions(BaseOptions):
gi.SetLayer(self._fadhes) gi.SetLayer(self._fadhes)
for gi in self.old_badhes: for gi in self.old_badhes:
gi.SetLayer(self._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): def remove_fab(self, board, comps_hash):
""" Remove from Fab the excluded components. """ """ Remove from Fab the excluded components. """

View File

@ -150,13 +150,14 @@ def test_gerber_variant_1(test_dir):
# R3 is a component added to the PCB, included in all cases # R3 is a component added to the PCB, included in all cases
# variant: default directory: gerber components: R1, R2 and R3 # variant: default directory: gerber components: R1, R2 and R3
check_layers_exist(ctx, 'gerber', prj, ALL_LAYERS, '') 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 # variant: production directory: production components: R1, R2, R3 and C2
check_layers_exist(ctx, 'production', prj, ALL_LAYERS, '_(production)') 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 # variant: test directory: test components: R1, R3 and C2
check_layers_exist(ctx, 'test', prj, ALL_LAYERS, '_(test)') 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) ctx.clean_up(keep_project=True)

View File

@ -2,6 +2,9 @@
kibot: kibot:
version: 1 version: 1
global:
remove_solder_mask_for_dnp: true
variants: variants:
- name: 'production' - name: 'production'
comment: 'Production variant' comment: 'Production variant'