summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2024-11-08 12:26:02 +0100
committerjaseg <git@jaseg.de>2024-11-08 12:26:02 +0100
commit81ae51d4be7f669172a95d03f4145d589fdbc319 (patch)
tree8b3f0a76506dfe5958adb080ef049ab8787ae5fa
parent8ffa7c1b76b9dc9238410c6221cb0d00ba49d4ae (diff)
downloadgerbonara-main.tar.gz
gerbonara-main.tar.bz2
gerbonara-main.zip
Improve allegro inner layer matchingmain
-rw-r--r--gerbonara/cli.py14
-rw-r--r--gerbonara/layers.py74
2 files changed, 85 insertions, 3 deletions
diff --git a/gerbonara/cli.py b/gerbonara/cli.py
index 22aa098..5b67da8 100644
--- a/gerbonara/cli.py
+++ b/gerbonara/cli.py
@@ -23,8 +23,10 @@ import dataclasses
import re
import warnings
import json
+import sys
import itertools
import webbrowser
+import warnings
from pathlib import Path
from .utils import MM, Inch
@@ -37,6 +39,18 @@ from .cad.kicad import tmtheme
from .cad import protoserve
+def _showwarning(message, category, filename, lineno, file=None, line=None):
+ if file is None:
+ file = sys.stderr
+
+ filename = Path(filename)
+ gerbonara_module_install_location = Path(__file__).parent.parent
+ if filename.is_relative_to(gerbonara_module_install_location):
+ filename = filename.relative_to(gerbonara_module_install_location)
+
+ print(f'{filename}:{lineno}: {message}', file=file)
+warnings.showwarning = _showwarning
+
def _print_version(ctx, param, value):
if value and not ctx.resilient_parsing:
click.echo(f'Version {__version__}')
diff --git a/gerbonara/layers.py b/gerbonara/layers.py
index f98adee..6069cdb 100644
--- a/gerbonara/layers.py
+++ b/gerbonara/layers.py
@@ -455,6 +455,7 @@ class LayerStack:
given value.
:rtype: :py:class:`LayerStack`
"""
+ print_layermap = False
if autoguess:
generator, filemap = _best_match(files)
@@ -480,13 +481,43 @@ class LayerStack:
filemap[layer] = filemap.get(layer, []) + [fn]
if 'autoguess' in filemap:
- warnings.warn(f'This generator ({generator}) often exports ambiguous filenames. Falling back to autoguesser for some files. Use at your own peril.')
- for key, values in _do_autoguess(filemap.pop('autoguess')).items():
+ warnings.warn(f'This generator ({generator}) often exports ambiguous filenames. Falling back to autoguesser for some files. Use at your own peril. Autoguessed files: {", ".join(f.name for f in filemap["autoguess"])}')
+ print_layermap = True
+ autoguess_filenames = filemap.pop('autoguess')
+
+ matched = set()
+ for key, values in _do_autoguess(autoguess_filenames).items():
filemap[key] = filemap.get(key, []) + values
+ matched |= set(values)
+
+ if generator == 'allegro':
+ # Allegro gerbers often contain the inner layers with completely random filenames and no indication of
+ # layer ordering except for drawings in the mechanical files. We fall back to alphabetic ordering.
+ for fn in autoguess_filenames:
+ if fn not in matched:
+ with open(fn) as f:
+ header = f.read(16384)
+ if re.search(r'G04 Layer:\s*ETCH/.*\*', header):
+ filemap['unknown copper'] = filemap.get('unknown copper', []) + [fn]
+
+ if (unk := filemap.pop('unknown copper', None)):
+ unk = sorted(unk, key=str)
+ if 'top copper' not in filemap:
+ filemap['top copper'], *unk = [unk]
+ if 'bottom copper' not in filemap:
+ *unk, filemap['bottom copper'] = [unk]
+
+ i = 1
+ while unk and i < 128:
+ key = f'inner_{i:02d} copper'
+ if key not in filemap:
+ filemap[key] = [unk.pop(0)]
+ i += 1
if sum(len(files) for files in filemap.values()) < 6 and autoguess:
warnings.warn('Ambiguous gerber filenames. Trying last-resort autoguesser.')
generator = None
+ print_layermap = True
filemap = _do_autoguess(files)
if len(filemap) < 6:
raise ValueError('Cannot figure out gerber file mapping. Partial map is: ', filemap)
@@ -518,6 +549,10 @@ class LayerStack:
excellon_settings = FileSettings(number_format=(2, 4))
automatch_drill_scale = True
+ print('remaining filemap')
+ import pprint
+ pprint.pprint(filemap)
+
if len(filemap) < 6:
raise SystemError('Cannot figure out gerber file mapping')
# FIXME use layer metadata from comments and ipc file if available
@@ -648,9 +683,42 @@ class LayerStack:
for obj in drill_file.objects:
obj.scale(scale)
- return kls(layers, drill_pth, drill_npth, drill_layers, board_name=board_name,
+ stack = kls(layers, drill_pth, drill_npth, drill_layers, board_name=board_name,
original_path=original_path, was_zipped=was_zipped, generator=[*all_generator_hints, None][0])
+ if print_layermap:
+ warnings.warn('Auto-guessed layer map:\n' + stack.format_layer_map())
+ return stack
+
+ def format_layer_map(self):
+ lines = []
+ def print_layer(prefix, file):
+ nonlocal lines
+ if file is None:
+ lines.append(f'{prefix} <not found>')
+ else:
+ lines.append(f'{prefix} {file.original_path.name} {file}')
+
+ lines.append(' Drill files:')
+ print_layer(' Plated holes:', self.drill_pth)
+ print_layer(' Nonplated holes:', self.drill_npth)
+ for i, l in enumerate(self._drill_layers):
+ print_layer(f' Additional drill layer {i}:', l)
+ print_layer(' Board outline:', self['mechanical outline'])
+
+ lines.append(' Soldermask:')
+ print_layer(' Top:', self['top mask'])
+ print_layer(' Bottom:', self['bottom mask'])
+
+ lines.append(' Silkscreen:')
+ print_layer(' Top:', self['top silk'])
+ print_layer(' Bottom:', self['bottom silk'])
+
+ lines.append(' Copper:')
+ for (side, _use), layer in self.copper_layers:
+ print_layer(f' {side}:', layer)
+ return '\n'.join(lines)
+
def save_to_zipfile(self, path, prefix='', overwrite_existing=True, board_name=None, naming_scheme={},
gerber_settings=None, excellon_settings=None):
""" Save this board into a zip file at the given path. For other options, see