summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gerbonara/gerber/layer_rules.py10
-rw-r--r--gerbonara/gerber/layers.py17
-rw-r--r--gerbonara/gerber/tests/test_layers.py32
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)