Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ruben-iteng committed Sep 2, 2024
1 parent 039a197 commit 7772723
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 42 deletions.
2 changes: 2 additions & 0 deletions src/faebryk/exporters/parameters/parameters_to_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def export_parameters_to_file(module: Module, path: Path):
]

logger.info(f"Writing parameters to {path}")
if not path.exists() or not path.is_file():
path.touch()
if path.suffix == ".txt":
with open(path, "w") as f:
for module_name, paras in sorted(parameters.items()):
Expand Down
203 changes: 191 additions & 12 deletions src/faebryk/exporters/pcb/kicad/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
import uuid
from abc import abstractmethod
from dataclasses import fields
from enum import Enum, auto
from itertools import pairwise
from typing import Any, Callable, Iterable, List, Sequence, TypeVar
from typing import Any, Callable, Iterable, List, Optional, Sequence, TypeVar

import numpy as np
from shapely import Polygon
Expand All @@ -19,6 +20,7 @@
from faebryk.core.module import Module
from faebryk.core.moduleinterface import ModuleInterface
from faebryk.core.node import Node
from faebryk.core.util import get_all_nodes_with_trait
from faebryk.libs.geometry.basic import Geometry
from faebryk.libs.kicad.fileformats import (
UUID,
Expand All @@ -32,10 +34,12 @@
C_rect,
C_stroke,
C_text,
C_text_layer,
C_wh,
C_xy,
C_xyr,
C_xyz,
E_fill,
)
from faebryk.libs.sexp.dataclass_sexp import dataclass_dfs
from faebryk.libs.util import cast_assert, find, get_key
Expand Down Expand Up @@ -297,9 +301,44 @@ def is_marked(obj) -> bool:

# Getter ---------------------------------------------------------------------------
@staticmethod
def get_fp(cmp) -> Footprint:
def get_fp(cmp: Node) -> Footprint:
return cmp.get_trait(PCB_Transformer.has_linked_kicad_footprint).get_fp()

def get_all_footprints(self) -> List[tuple[Module, Footprint]]:
return [
(cast_assert(Module, cmp), t.get_fp())
for cmp, t in get_all_nodes_with_trait(
self.graph, PCB_Transformer.has_linked_kicad_footprint
)
]

# TODO: make universal fp bbox getter (also take into account pads)
def get_footprint_silkscreen_bbox(
self, cmp: Node
) -> None | tuple[Point2D, Point2D]:
fp = self.get_fp(cmp)
silk_outline = [geo for geo in get_all_geos(fp) if geo.layer == "F.SilkS"]

extremes = list[C_xy]()

for geo in silk_outline:
if isinstance(geo, C_line):
extremes.extend([geo.start, geo.end])
elif isinstance(geo, C_arc):
# TODO: calculate extremes.extend([geo.start, geo.mid, geo.end])
...
elif isinstance(geo, C_rect):
extremes.extend([geo.start, geo.end])
elif isinstance(geo, C_circle):
# TODO: calculate extremes.extend([geo.center, geo.end])
...

if not extremes:
logger.warn(f"{cmp} with fp:{fp.name} has no silk outline")
return None

return Geometry.bbox([Point2D((point.x, point.y)) for point in extremes])

def get_net(self, net: FNet) -> Net:
nets = {pcb_net.name: pcb_net for pcb_net in self.pcb.nets}
return nets[net.get_trait(F.has_overriden_name).get_name()]
Expand Down Expand Up @@ -543,21 +582,31 @@ def insert_via(
)
)

def insert_text(self, text: str, at: C_xyr, font: Font, front: bool = True):
def insert_text(
self, text: str, at: C_xyr, font: Font, layer: str = "F.SilkS", alignment=None
):
self.pcb.gr_texts.append(
GR_Text(
text=text,
at=at,
layer=f"{'F' if front else 'B'}.SilkS",
layer=layer,
effects=C_effects(
font=font,
justify=(
C_effects.E_justify.center,
C_effects.E_justify.center,
C_effects.E_justify.mirror
if not front
else C_effects.E_justify.normal,
),
(
C_effects.E_justify.center,
C_effects.E_justify.center,
C_effects.E_justify.mirror,
)
if not layer.startswith("F.")
else (
C_effects.E_justify.center,
C_effects.E_justify.center,
C_effects.E_justify.normal,
)
)
if alignment is None
else alignment,
),
uuid=self.gen_uuid(mark=True),
)
Expand Down Expand Up @@ -638,7 +687,13 @@ def get_net_obj_bbox(self, net: Net, layer: str, tolerance=0.0):

return Geometry.rect_to_polygon(bbox)

def insert_zone(self, net: Net, layers: str | list[str], polygon: list[Point2D]):
def insert_zone(
self,
net: Net,
layers: str | list[str],
polygon: list[Point2D],
keepout: bool = False,
):
# check if exists
zones = self.pcb.zones
# TODO check bbox
Expand Down Expand Up @@ -678,18 +733,81 @@ def insert_zone(self, net: Net, layers: str | list[str], polygon: list[Point2D])
thermal_bridge_width=0.2,
smoothing=None,
radius=1,
island_removal_mode=Zone.C_fill.E_island_removal_mode.do_not_remove,
# island_removal_mode=Zone.C_fill.E_island_removal_mode.do_not_remove, # noqa E501
island_area_min=10.0,
),
locked=False,
hatch=Zone.C_hatch(mode=Zone.C_hatch.E_mode.edge, pitch=0.5),
priority=0,
keepout=Zone.C_keepout(
tracks=Zone.C_keepout.E_keepout_bool.allowed,
vias=Zone.C_keepout.E_keepout_bool.allowed,
pads=Zone.C_keepout.E_keepout_bool.allowed,
copperpour=Zone.C_keepout.E_keepout_bool.not_allowed,
footprints=Zone.C_keepout.E_keepout_bool.allowed,
)
if keepout
else None,
connect_pads=Zone.C_connect_pads(
mode=Zone.C_connect_pads.E_mode.thermal_reliefs, clearance=0.2
),
)
)

# JLCPCB ---------------------------------------------------------------------------
class JLCPBC_QR_Size(Enum):
SMALL_5x5mm = C_xy(5, 5)
MEDIUM_8x8mm = C_xy(5, 5)
LARGE_10x10mm = C_xy(5, 5)

def insert_jlcpcb_qr(
self,
size: JLCPBC_QR_Size,
center_at: C_xy,
layer="F.SilkS",
number: bool = True,
):
assert layer.endswith("SilkS"), "JLCPCB QR code must be on silk screen layer"
if number:
self.insert_text(
"######",
at=C_xyr(center_at.x, center_at.y + size.value.y / 2 + 1, 0),
font=Font(size=C_wh(0.75, 0.75), thickness=0.15),
layer="F.Fab" if layer.startswith("F.") else "B.Fab",
)
self.insert_geo(
C_rect(
start=C_xy(
center_at.x - size.value.x / 2, center_at.y - size.value.y / 2
),
end=C_xy(
center_at.x + size.value.x / 2, center_at.y + size.value.y / 2
),
stroke=C_stroke(width=0.15, type=C_stroke.E_type.solid),
fill=E_fill.solid,
layer=layer,
uuid=self.gen_uuid(mark=True),
)
)

def insert_jlcpcb_serial(
self,
center_at: C_xyr,
layer="F.SilkS",
):
assert layer.endswith(
"SilkS"
), "JLCPCB serial number must be on silk screen layer"
self.insert_text(
"JLCJLCJLCJLC",
at=center_at,
font=Font(
size=C_wh(1, 1),
thickness=0.15,
),
layer=layer,
)

# Positioning ----------------------------------------------------------------------
def move_footprints(self):
from faebryk.core.util import get_all_nodes_with_traits
Expand Down Expand Up @@ -977,3 +1095,64 @@ def set_pcb_outline_complex(
self.insert_geo(geo)

# find bounding box

class Side(Enum):
TOP = auto()
BOTTOM = auto()
LEFT = auto()
RIGHT = auto()

def set_designator_position(
self,
offset: float,
displacement: C_xy = C_xy(0, 0),
rotation: Optional[float] = None,
offset_side: Side = Side.BOTTOM,
layer: Optional[C_text_layer] = None,
font: Optional[Font] = None,
knockout: Optional[C_text_layer.E_knockout] = None,
justify: Optional[
tuple[C_effects.E_justify, C_effects.E_justify, C_effects.E_justify]
] = None,
):
for mod, fp in self.get_all_footprints():
reference = fp.propertys["Reference"]
reference.layer = (
layer
if layer
else C_text_layer(
layer="F.SilkS" if fp.layer.startswith("F") else "B.SilkS"
)
)
reference.layer.knockout = (
knockout if knockout else reference.layer.knockout
)
reference.effects.font = font if font else reference.effects.font

reference.effects.justify = (
justify if justify else reference.effects.justify
)
rot = rotation if rotation else reference.at.r

footprint_bbox = self.get_footprint_silkscreen_bbox(mod)
if not footprint_bbox:
continue
max_coord = C_xy(*footprint_bbox[1])
min_coord = C_xy(*footprint_bbox[0])

if offset_side == self.Side.BOTTOM:
reference.at = C_xyr(
displacement.x, max_coord.y + offset - displacement.y, rot
)
elif offset_side == self.Side.TOP:
reference.at = C_xyr(
displacement.x, min_coord.y - offset - displacement.y, rot
)
elif offset_side == self.Side.LEFT:
reference.at = C_xyr(
min_coord.x - offset - displacement.x, displacement.y, rot
)
elif offset_side == self.Side.RIGHT:
reference.at = C_xyr(
max_coord.x + offset + displacement.x, displacement.y, rot
)
11 changes: 10 additions & 1 deletion src/faebryk/exporters/pcb/layout/extrude.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LayoutExtrude(Layout):
(0, 0, 0, F.has_pcb_position.layer_type.NONE)
)
dynamic_rotation: bool = False
reverse_order: bool = False

def apply(self, *node: Node):
"""
Expand All @@ -40,7 +41,15 @@ def apply(self, *node: Node):

vector = self.vector if len(self.vector) == 3 else (*self.vector, 0)

for i, n in enumerate(node):
for i, n in enumerate(
sorted(
node,
key=lambda n: n.get_trait(F.has_designator).get_designator()
if n.has_trait(F.has_designator)
else n.get_full_name(),
reverse=self.reverse_order,
)
):
vec_i = (
vector[0] * i,
vector[1] * i,
Expand Down
6 changes: 3 additions & 3 deletions src/faebryk/library/ESP32_C3_MINI_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def attach_to_footprint(self):
"27": self.gpio[19].signal,
# 28 is not connected
# 29 is not connected
"30": self.uart.rx.signal,
"31": self.uart.tx.signal,
"30": self.gpio[20].signal, # self.uart.rx.signal,
"31": self.gpio[21].signal, # self.uart.tx.signal,
# 32 is not connected
# 33 is not connected
# 34 is not connected
Expand Down Expand Up @@ -114,5 +114,5 @@ def attach_to_footprint(self):

designator_prefix = L.f_field(F.has_designator_prefix_defined)("U")
datasheet = L.f_field(F.has_datasheet_defined)(
"https://www.espressif.com/sites/default/files/russianDocumentation/esp32-c3-mini-1_datasheet_en.pdf"
"https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_en.pdf"
)
29 changes: 28 additions & 1 deletion src/faebryk/library/ESP32_C3_MINI_1_Reference_Design.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,34 @@ def __preinit__(self):

# TODO: set the following in the pinmux
# jtag gpio 4,5,6,7
# USB gpio 18,19
self.esp32_c3_mini_1.esp32_c3.usb.usb_if.d.n.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[18].signal
)
self.esp32_c3_mini_1.esp32_c3.usb.usb_if.d.p.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[19].signal
)
# UART0 gpio 30/31 (default)
self.esp32_c3_mini_1.esp32_c3.uart[0].rx.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[20]
)
self.esp32_c3_mini_1.esp32_c3.uart[0].tx.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[21]
)

# UART1 gpio 8/9
self.esp32_c3_mini_1.esp32_c3.uart[1].rx.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[8]
)
self.esp32_c3_mini_1.esp32_c3.uart[1].tx.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[7]
)
# i2c
self.esp32_c3_mini_1.esp32_c3.i2c.sda.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[3] # default 21
)
self.esp32_c3_mini_1.esp32_c3.i2c.scl.connect(
self.esp32_c3_mini_1.esp32_c3.gpio[2] # default 22
)

# connect USB
self.usb.connect(self.esp32_c3_mini_1.esp32_c3.usb)
Expand Down
Loading

0 comments on commit 7772723

Please sign in to comment.