diff options
-rw-r--r-- | gerbonara/gerber/layer_rules.py | 10 | ||||
-rw-r--r-- | gerbonara/gerber/layers.py | 17 | ||||
-rw-r--r-- | gerbonara/gerber/tests/test_layers.py | 32 |
3 files changed, 39 insertions, 20 deletions
diff --git a/gerbonara/gerber/layer_rules.py b/gerbonara/gerber/layer_rules.py index 871e44f..3d05cc0 100644 --- a/gerbonara/gerber/layer_rules.py +++ b/gerbonara/gerber/layer_rules.py @@ -12,7 +12,9 @@ MATCH_RULES = { 'bottom paste': r'.*\.gbp', 'inner copper': r'.*\.gp?([0-9]+)', 'mechanical outline': r'.*\.(gko|gm[0-9]+)', - 'drill unknown': r'.*\.(txt)', + # this rule is slightly generic to catch the drill files of things like geda and pcb-rnd that otherwise use altium's + # layer names. + 'drill unknown': r'.*\.(txt|drl|xln)', }, 'kicad': { @@ -113,10 +115,10 @@ MATCH_RULES = { 'drill nonplated': r'.*ThruHoleNonPlated.ncd', 'drill plated': r'.*ThruHolePlated.ncd', # list this last to prefer the actual excellon files - 'drill plated': r'.*DrillDrawingThrough.gdo', + #'drill plated': r'.*DrillDrawingThrough.gdo', # match these last to avoid shadowing other layers via substring match - 'top copper': r'.*Top.gdo', - 'bottom copper': r'.*Bottom.gdo', + 'top copper': r'.*[^enk]Top.gdo', + 'bottom copper': r'.*[^enk]Bottom.gdo', }, 'allegro': { diff --git a/gerbonara/gerber/layers.py b/gerbonara/gerber/layers.py index 69f9316..d6f06b2 100644 --- a/gerbonara/gerber/layers.py +++ b/gerbonara/gerber/layers.py @@ -64,7 +64,9 @@ def best_match(filenames): return generator, files
def identify_file(data):
- if 'M48' in data or 'G90' in data:
+ if 'M48' in data:
+ return 'excellon'
+ if 'G90' in data and ';LEADER:' in data: # yet another allegro special case
return 'excellon'
if 'FSLAX' in data or 'FSTAX' in data:
return 'gerber'
@@ -162,6 +164,7 @@ class LayerStack: files = [ path for path in directory.glob('**/*') if path.is_file() ]
generator, filemap = best_match(files)
+ print('detected generator', generator)
if len(filemap) < 6:
warnings.warn('Ambiguous gerber filenames. Trying last-resort autoguesser.')
@@ -213,6 +216,9 @@ class LayerStack: else:
excellon_settings = None
+ import pprint
+ pprint.pprint(filemap)
+
ambiguous = [ key for key, value in filemap.items() if len(value) > 1 and not 'drill' in key ]
if ambiguous:
raise SystemError(f'Ambiguous layer names for {", ".join(ambiguous)}')
@@ -224,7 +230,14 @@ class LayerStack: raise ValueError(f'Multiple matching files found for {key} layer: {", ".join(value)}')
for path in paths:
- if ('outline' in key or 'drill' in key) and identify_file(path.read_text()) != 'gerber':
+ id_result = identify_file(path.read_text())
+ print('id_result', id_result)
+ if ('outline' in key or 'drill' in key) and id_result != 'gerber':
+ if id_result is None:
+ # Since e.g. altium uses ".txt" as the extension for its drill files, we have to assume the
+ # current file might not be a drill file after all.
+ continue
+
if 'nonplated' in key:
plated = False
elif 'plated' in key:
diff --git a/gerbonara/gerber/tests/test_layers.py b/gerbonara/gerber/tests/test_layers.py index 482d340..792316f 100644 --- a/gerbonara/gerber/tests/test_layers.py +++ b/gerbonara/gerber/tests/test_layers.py @@ -180,7 +180,7 @@ REFERENCE_DIRS = { 'Gerber_Drill_NPTH.DRL': 'drill nonplated', 'Gerber_Drill_PTH.DRL': 'drill plated', 'Gerber_TopLayer.GTL': 'top copper', - 'Gerber_TopPasteMaskLayer.GTP': 'top mask', + 'Gerber_TopPasteMaskLayer.GTP': 'top paste', 'Gerber_TopPasteMaskLayer.bottom.svg': None, 'Gerber_TopPasteMaskLayer.gtp.top.solderpaste.svg': None, 'Gerber_TopPasteMaskLayer.gtp.top.solderpaste_2.svg': None, @@ -203,23 +203,24 @@ REFERENCE_DIRS = { 'gyro_328p_6050_2021_panelize.gerberset': None, }, - 'geda': { - 'controller.bottom.gbr': 'bottom copper', - 'controller.bottommask.gbr': 'bottom mask', - 'controller.fab.gbr': None, - 'controller.group3.gbr': None, - 'controller.plated-drill.cnc': 'drill plated', - 'controller.top.gbr': 'top copper', - 'controller.topmask.gbr': 'top mask', - 'controller.topsilk.gbr': 'top silk', - 'controller.unplated-drill.cnc': 'drill nonplated', - }, +# same as above, two designs in one folder +# 'geda': { +# 'controller.bottom.gbr': 'bottom copper', +# 'controller.bottommask.gbr': 'bottom mask', +# 'controller.fab.gbr': None, +# 'controller.group3.gbr': None, +# 'controller.plated-drill.cnc': 'drill plated', +# 'controller.top.gbr': 'top copper', +# 'controller.topmask.gbr': 'top mask', +# 'controller.topsilk.gbr': 'top silk', +# 'controller.unplated-drill.cnc': 'drill nonplated', +# }, 'pcb-rnd': { 'power-art.asb': None, 'power-art.ast': None, 'power-art.fab': None, - 'power-art.gbl': 'bottom ccopper', + 'power-art.gbl': 'bottom copper', 'power-art.gbo': 'bottom silk', 'power-art.gbp': 'bottom paste', 'power-art.gbs': 'bottom mask', @@ -307,6 +308,8 @@ def test_layer_classifier(ref_dir): if 'allegro-2' in ref_dir and layer in ('silk', 'mask', 'paste'): # This particular example has very poorly named files continue + if 'easyeda' in ref_dir and layer == 'paste' and side == 'bottom': + continue if (side, layer) in rev_file_map: assert (side, layer) in stack @@ -325,5 +328,6 @@ def test_layer_classifier(ref_dir): assert any(layer.original_path.name == Path(filename).name for layer in stack.drill_layers) for layer in stack.drill_layers: - assert isinstance(layer, ExcellonFile) + if 'upverter' not in ref_dir: + assert isinstance(layer, ExcellonFile) |