From 3a96269a25e9fdc464b3076afe6e935dac9ed9f4 Mon Sep 17 00:00:00 2001 From: Bugra Onal Date: Tue, 24 Jun 2025 01:05:12 -0700 Subject: [PATCH 1/2] Add multi sided footprint support for KiCAD --- pcbflow/kicad.py | 37 +++++++++++++++++++++++++++++++++---- pcbflow/part.py | 9 +++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/pcbflow/kicad.py b/pcbflow/kicad.py index 251aaee..1ca0dbb 100644 --- a/pcbflow/kicad.py +++ b/pcbflow/kicad.py @@ -19,6 +19,11 @@ "F.Mask": "GTS", "F.Cu": "GTL", "F.Fab": "GTD", + "B.SilkS": "GBO", + "B.Paste": "GBP", + "B.Mask": "GBS", + "B.Cu": "GBL", + "B.Fab": "GBD", } FP_LIB_PATH = None @@ -45,6 +50,7 @@ def __init__(self, dc, val=None, source=None, libraryfile=None, **kwargs): super().__init__(dc, val, source, **kwargs) def _add_obj_to_layer(self, obj, layer): + oposite_side = "bottom" if self.side == "top" else "top" if layer == "GTO": self.board.get_silk_layer(side=self.side).add(obj) elif layer == "GTD": @@ -56,6 +62,17 @@ def _add_obj_to_layer(self, obj, layer): self.board.layers["GBL"].add(obj) else: self.board.layers["GTL"].add(obj) + elif layer == "GBO": + self.board.get_silk_layer(side=oposite_side).add(obj) + elif layer == "GBD": + self.board.get_docu_layer(side=oposite_side).add(obj) + elif layer == "GBP": + self.board.get_paste_layer(side=oposite_side).add(obj) + elif layer == "GBL": + if self.side == "bottom": + self.board.layers["GTL"].add(obj) + else: + self.board.layers["GBL"].add(obj) def place(self, dc): for line in self.lines: @@ -104,6 +121,12 @@ def place(self, dc): self.smd_pad(p, ignore_paste=no_paste) elif "GTP" in pad["layers"]: self.board.get_paste_layer(side=self.side).add(p.poly()) + if "GBL" in pad["layers"]: + no_paste = True if "GBP" not in pad["layers"] else False + self.smd_pad(p, ignore_paste=no_paste, back_side=True) + elif "GBP" in pad["layers"]: + side = "bottom" if self.side == "top" else "top" + self.board.get_paste_layer(side=side).add(p.poly()) for pad in self.pin_pads: diameter = pad["size"][0] @@ -146,14 +169,18 @@ def _map_layers(self, layers): def _parse_fp_text(self, items): xy = [] - layers = [] text = items[0] + layer = None for e in items: if isinstance(e, dict): if "at" in e: xy = float(e["at"][0]), -float(e["at"][1]) elif "layer" in e: - layer = self._map_layers(e["layer"])[0] + layer_ = self._map_layers(e["layer"]) + if len(layer_) > 0: + layer = layer_[0] + if not layer: + return if text == "reference": self.labels.append({"xy": xy, "text": text, "layer": layer}) @@ -182,7 +209,7 @@ def _parse_fp_circle(self, items): center = (0, 0) width = 0 diameter = 0 - layers = [] + layer = None fill=True for e in items: if isinstance(e, dict): @@ -203,7 +230,9 @@ def _parse_fp_circle(self, items): if 'none' in e['fill']: fill=False elif "layer" in e: - layer = self._map_layers(e["layer"])[0] + layers = self._map_layers(e["layer"]) + if len(layers) > 0: + layer = layers[0] self.circles.append( {"center": center, "diameter": diameter, "width": width, "layer": layer, "fill" : fill} ) diff --git a/pcbflow/part.py b/pcbflow/part.py index 74b61bd..7fe9655 100644 --- a/pcbflow/part.py +++ b/pcbflow/part.py @@ -213,8 +213,13 @@ def chamfered(self, dc, w, h, drawid=True, idoffset=(0, 0)): ) dc.pop() - def smd_pad(self, dc, ignore_paste=False): - for layer in dc.board.get_smd_pad_layers(self.side, ignore_paste=ignore_paste): + def smd_pad(self, dc, ignore_paste=False, back_side=False): + side = self.side + if back_side and side == "top": + side = "bottom" + elif back_side and side == "bottom": + side = "top" + for layer in dc.board.get_smd_pad_layers(side, ignore_paste=ignore_paste): if layer.is_mask: g = dc.poly().buffer(dc.board.drc.soldermask_margin) else: From e02d51e3e9bdba375058367afaed4da62f15c66b Mon Sep 17 00:00:00 2001 From: Bugra Onal Date: Tue, 24 Jun 2025 18:51:58 -0700 Subject: [PATCH 2/2] Default layers value is [] --- pcbflow/kicad.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pcbflow/kicad.py b/pcbflow/kicad.py index 1ca0dbb..f7cd70a 100644 --- a/pcbflow/kicad.py +++ b/pcbflow/kicad.py @@ -170,15 +170,15 @@ def _map_layers(self, layers): def _parse_fp_text(self, items): xy = [] text = items[0] - layer = None + layers = [] for e in items: if isinstance(e, dict): if "at" in e: xy = float(e["at"][0]), -float(e["at"][1]) elif "layer" in e: - layer_ = self._map_layers(e["layer"]) - if len(layer_) > 0: - layer = layer_[0] + layers = self._map_layers(e["layer"]) + if len(layers) > 0: + layer = layers[0] if not layer: return if text == "reference": @@ -209,7 +209,7 @@ def _parse_fp_circle(self, items): center = (0, 0) width = 0 diameter = 0 - layer = None + layers = [] fill=True for e in items: if isinstance(e, dict):