Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: pytest
- name: Run mypy
run: mypy .
- name: Run flake8
run: flake8
- name: Run isort
run: isort --check --diff .
- name: Run ruff check
run: ruff check .
- name: Run ruff format
run: ruff format --check
6 changes: 4 additions & 2 deletions cadquery_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ class StepAssembly:
"""
A STEP assembly.
"""

def __init__(self, name: str):
self.assembly = cq.Assembly(name=name)

# Less verbose output
for printer in Message.DefaultMessenger_s().Printers():
printer.SetTraceLevel(Message_Gravity.Message_Fail)

def add_body(self, body: cq.Workplane, name: str, color: cq.Color,
location: Optional[cq.Location] = None) -> None:
def add_body(
self, body: cq.Workplane, name: str, color: cq.Color, location: Optional[cq.Location] = None
) -> None:
"""
Add a body to the assembly.

Expand Down
13 changes: 7 additions & 6 deletions common.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Common functionality for generator scripts.
"""

import collections
import csv
import re
Expand All @@ -18,7 +19,7 @@
('\r', '\\r'),
('\t', '\\t'),
('\v', '\\v'),
('"', '\\"'),
('"', '\\"'),
)


Expand Down Expand Up @@ -113,10 +114,7 @@ def get_pad_uuids(base_lib_path: str, pkg_uuid: str) -> Dict[str, str]:
"""
with open(path.join(base_lib_path, 'pkg', pkg_uuid, 'package.lp'), 'r') as f:
lines = f.readlines()
opt_matches = [
re.match(r' \(pad ([^\s]*) \(name "([^"]*)"\)\)$', line)
for line in lines
]
opt_matches = [re.match(r' \(pad ([^\s]*) \(name "([^"]*)"\)\)$', line) for line in lines]
matches = list(filter(None, opt_matches))
mapping = {}
for match in matches:
Expand All @@ -132,13 +130,16 @@ def human_sort_key(key: str) -> List[Any]:
Function that can be used for natural sorting, where "PB2" comes before
"PB10" and after "PA3".
"""

def _convert(text: str) -> Union[int, str]:
return int(text) if text.isdigit() else text

return [_convert(x) for x in re.split(r'(\d+)', key) if x]


def serialize_common(serializable: Any, output_directory: str, uuid: str, long_type: str, short_type: str) -> None:
def serialize_common(
serializable: Any, output_directory: str, uuid: str, long_type: str, short_type: str
) -> None:
"""
Centralized serialize() implementation shared between Component, Symbol, Device, Package
"""
Expand Down
171 changes: 101 additions & 70 deletions dfn_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@

from typing import Any, Callable, Optional, Tuple

from entities.common import Angle, Circle, Diameter, Fill, GrabArea, Layer, Polygon, Position, Vertex, Width
from entities.common import (
Angle,
Circle,
Diameter,
Fill,
GrabArea,
Layer,
Polygon,
Position,
Vertex,
Width,
)
from entities.package import Footprint

# Maximal lead width as a function of pitch, Table 4 in the JEDEC
Expand All @@ -16,58 +27,61 @@
0.8: 0.35,
0.65: 0.35,
0.5: 0.30,
0.4: 0.25
0.4: 0.25,
}

# Toe and heel length as a function of pitch
# According to IPC-7351C, see slide 26 of
# http://ocipcdc.org/archive/What_is_New_in_IPC-7351C_03_11_2015.pdf
LEAD_TOE_HEEL = {
1.00: 0.35,
0.95: 0.35, # not specified in standard
0.95: 0.35, # not specified in standard
0.8: 0.33,
0.65: 0.31,
0.50: 0.29,
0.40: 0.27,
0.35: 0.25
0.35: 0.25,
}

# The real CadQuery types are not known statically, thus allowing any type.
StepModificationFn = Callable[[Any, Any, Any], Tuple[Any, Any]]


class DfnConfig:
def __init__(self,
length: float,
width: float,
pitch: float,
pin_count: int,
height_nominal: float,
height_max: float,
lead_length: float,
exposed_width: float,
exposed_length: float,
keywords: str,
no_exp: bool = True, # By default we create variants w/o exp
print_pad: bool = False, # By default, the pad length is not in the full name
lead_width: Optional[float] = None,
name: Optional[str] = None,
create_date: Optional[str] = None,
library: Optional[str] = None,
pin1_corner_dx_dy: Optional[float] = None, # Some parts have a triangular pin1 marking
extended_doc_fn: Optional[Callable[['DfnConfig', Callable[[str], str], Footprint], None]] = None,
step_modification_fn: Optional[StepModificationFn] = None,
):
def __init__(
self,
length: float,
width: float,
pitch: float,
pin_count: int,
height_nominal: float,
height_max: float,
lead_length: float,
exposed_width: float,
exposed_length: float,
keywords: str,
no_exp: bool = True, # By default we create variants w/o exp
print_pad: bool = False, # By default, the pad length is not in the full name
lead_width: Optional[float] = None,
name: Optional[str] = None,
create_date: Optional[str] = None,
library: Optional[str] = None,
pin1_corner_dx_dy: Optional[float] = None, # Some parts have a triangular pin1 marking
extended_doc_fn: Optional[
Callable[['DfnConfig', Callable[[str], str], Footprint], None]
] = None,
step_modification_fn: Optional[StepModificationFn] = None,
):
self.length = length
self.width = width
self.pitch = pitch
self.pin_count = pin_count
self.height = height_max
self.height_nominal = height_nominal

self.exposed_width = exposed_width # E2
self.exposed_length = exposed_length # D2
self.no_exp = no_exp # Option with noexp
self.exposed_width = exposed_width # E2
self.exposed_length = exposed_length # D2
self.no_exp = no_exp # Option with noexp

self.lead_length = lead_length
self.print_pad = print_pad
Expand All @@ -80,17 +94,18 @@ def __init__(self,
try:
self.toe_heel = LEAD_TOE_HEEL[pitch]
except KeyError:
raise NotImplementedError("No toe/heel length for pitch {:s}".format(pitch))
raise NotImplementedError('No toe/heel length for pitch {:s}'.format(pitch))

self.keywords = keywords
self.name = name
self.create_date = create_date
self.library = library or "LibrePCB_Base.lplib"
self.library = library or 'LibrePCB_Base.lplib'

self.extended_doc_fn = extended_doc_fn
self.step_modification_fn = step_modification_fn


# fmt: off
JEDEC_CONFIGS = [
# Table 6
# Square, 1.5 x 1.5
Expand Down Expand Up @@ -128,8 +143,8 @@ def __init__(self,
DfnConfig(3.0, 3.0, 0.5, 8, 0.75, 0.80, 0.40, 2.70, 1.75, 'W3030D-4,WEED-4', no_exp=False), # no nominal exp_pad
DfnConfig(3.0, 3.0, 0.5, 8, 0.95, 1.00, 0.55, 2.50, 1.50, 'V3030D-6,VEED-6', no_exp=False), # no nominal exp_pad
DfnConfig(3.0, 3.0, 0.5, 8, 0.75, 0.80, 0.55, 2.50, 1.50, 'W3030D-6,WEED-6', no_exp=False), # no nominal exp_pad
DfnConfig(3.0, 3.0, 0.5, 8, 0.95, 1.00, 0.45, 1.60, 1.60, 'V3030D-7,VEED-7', no_exp=False), # no nominal pad length and exp_pad
DfnConfig(3.0, 3.0, 0.5, 8, 0.75, 0.80, 0.45, 1.60, 1.60, 'W3030D-7,WEED-7', no_exp=False), # no nominal pad length and exp_pad
DfnConfig(3.0, 3.0, 0.5, 8, 0.95, 1.00, 0.45, 1.60, 1.60, 'V3030D-7,VEED-7', no_exp=False), # no nominal pad length and exp_pad # noqa: E501
DfnConfig(3.0, 3.0, 0.5, 8, 0.75, 0.80, 0.45, 1.60, 1.60, 'W3030D-7,WEED-7', no_exp=False), # no nominal pad length and exp_pad # noqa: E501
DfnConfig(3.0, 3.0, 0.5, 10, 0.95, 1.00, 0.55, 2.20, 1.60, 'V3030D-2,VEED-2', print_pad=True),
DfnConfig(3.0, 3.0, 0.5, 10, 0.75, 0.80, 0.55, 2.00, 1.20, 'W3030D-2,WEED-2'),
DfnConfig(3.0, 3.0, 0.5, 10, 0.95, 1.00, 0.30, 2.20, 1.60, 'V3030D-3,VEED-3', print_pad=True),
Expand Down Expand Up @@ -171,9 +186,9 @@ def __init__(self,
DfnConfig(2.0, 3.0, 0.5, 6, 0.75, 0.80, 0.40, 1.00, 1.20, 'W2030D-1,WCED-1', no_exp=False), # no nominal exp_pad
DfnConfig(2.0, 3.0, 0.5, 8, 0.95, 1.00, 0.40, 1.75, 1.90, 'V2030D-2,VCED-2', no_exp=False), # no nominal exp_pad
DfnConfig(2.0, 3.0, 0.5, 8, 0.75, 0.80, 0.40, 1.75, 1.90, 'W2030D-2,WCED-2', no_exp=False), # no nominal exp_pad
DfnConfig(2.0, 3.0, 0.5, 8, 0.95, 1.00, 0.45, 1.60, 1.60, 'V2030D-3,VCED-3', no_exp=False), # no nominal pad length and exp_pad
DfnConfig(2.0, 3.0, 0.5, 8, 0.75, 0.80, 0.45, 1.60, 1.60, 'W2030D-3,WCED-3', no_exp=False), # no nominal pad length and exp_pad
DfnConfig(2.0, 3.0, 0.5, 8, 0.55, 0.65, 0.45, 1.60, 1.60, 'U2030D', no_exp=False), # no nominal pad length and exp_pad
DfnConfig(2.0, 3.0, 0.5, 8, 0.95, 1.00, 0.45, 1.60, 1.60, 'V2030D-3,VCED-3', no_exp=False), # no nominal pad length and exp_pad # noqa: E501
DfnConfig(2.0, 3.0, 0.5, 8, 0.75, 0.80, 0.45, 1.60, 1.60, 'W2030D-3,WCED-3', no_exp=False), # no nominal pad length and exp_pad # noqa: E501
DfnConfig(2.0, 3.0, 0.5, 8, 0.55, 0.65, 0.45, 1.60, 1.60, 'U2030D', no_exp=False), # no nominal pad length and exp_pad # noqa: E501
# Rectangular, Type 1, 2.5 x 3.0
DfnConfig(2.5, 3.0, 0.8, 6, 0.95, 1.00, 0.55, 1.50, 1.20, 'V2530B,VDEB'),
DfnConfig(2.5, 3.0, 0.8, 6, 0.75, 0.80, 0.55, 1.50, 1.20, 'W2530B,WDEB'),
Expand Down Expand Up @@ -221,14 +236,14 @@ def __init__(self,
DfnConfig(3.0, 1.5, 0.5, 10, 0.95, 1.00, 0.55, 2.20, 0.10, 'W3015D-2,VEBD-2'),
DfnConfig(3.0, 1.5, 0.5, 10, 0.75, 0.80, 0.55, 2.20, 0.10, 'W3015D-2,WEBD-2'),
# Rectangular, Type 2, 3.0 x 2.0
DfnConfig(3.0, 2.0, 0.95, 6, 0.95, 1.00, 0.30, 2.20, 0.60, 'V3020A,VECA'), # no nominal exp_pad, using manual values
DfnConfig(3.0, 2.0, 0.65, 8, 0.95, 1.00, 0.30, 2.20, 0.60, 'V3020C,VECC'), # no nominal exp_pad, using manual values
DfnConfig(3.0, 2.0, 0.95, 6, 0.95, 1.00, 0.30, 2.20, 0.60, 'V3020A,VECA'), # no nominal exp_pad, using manual values # noqa: E501
DfnConfig(3.0, 2.0, 0.65, 8, 0.95, 1.00, 0.30, 2.20, 0.60, 'V3020C,VECC'), # no nominal exp_pad, using manual values # noqa: E501
DfnConfig(3.0, 2.0, 0.5, 8, 0.95, 1.00, 0.55, 2.20, 0.60, 'V3020D-1,V3020D-4,VECD-1,VECD-4'),
DfnConfig(3.0, 2.0, 0.5, 8, 0.75, 0.80, 0.55, 2.20, 0.60, 'W3020D-1,W3020D-4,WECD-1,WECD-4'),
# Commented out as they coincide with the V3020D-1, only the tolerances are different,
# so we may need to re-add them again later.
# DfnConfig(3.0, 2.0, 0.5, 8, 0.95, 1.00, 0.40, 2.20, 0.60, 'V3020D-4,VECD-4', no_exp=False), # no nominal exp_pad
# DfnConfig(3.0, 2.0, 0.5, 8, 0.75, 0.80, 0.40, 2.20, 0.60, 'W3020D-4,WECD-4', no_exp=False), # no nominal exp_pad
# DfnConfig(3.0, 2.0, 0.5, 8, 0.95, 1.00, 0.40, 2.20, 0.60, 'V3020D-4,VECD-4', no_exp=False), # no nominal exp_pad
# DfnConfig(3.0, 2.0, 0.5, 8, 0.75, 0.80, 0.40, 2.20, 0.60, 'W3020D-4,WECD-4', no_exp=False), # no nominal exp_pad
DfnConfig(3.0, 2.0, 0.5, 10, 0.95, 1.00, 0.55, 2.20, 0.60, 'V3020D-2,VECD-2', print_pad=True),
DfnConfig(3.0, 2.0, 0.5, 10, 0.75, 0.80, 0.55, 2.20, 0.60, 'W3020D-2,WECD-2'),
DfnConfig(3.0, 2.0, 0.5, 10, 0.95, 1.00, 0.30, 2.20, 0.60, 'V3020D-3,VECD-3', print_pad=True),
Expand Down Expand Up @@ -274,65 +289,80 @@ def __init__(self,
DfnConfig(6.0, 5.0, 0.5, 18, 0.95, 1.00, 0.55, 4.70, 3.40, 'V6050D-2,VLJD-2', no_exp=False), # no nominal exp_pad
DfnConfig(6.0, 5.0, 0.5, 18, 0.75, 0.80, 0.55, 4.70, 3.40, 'W6050D-2,WLJD-2', no_exp=False), # no nominal exp_pad
]
# fmt: on


def draw_circle(diameter: float) -> Callable[[DfnConfig, Callable[[str], str], Footprint], None]:
def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -> None:
footprint.add_circle(Circle(
uuid('hole-circle-doc'),
Layer('top_documentation'),
Width(0.1),
Fill(False),
GrabArea(False),
Diameter(diameter),
Position(0, 0),
))
footprint.add_circle(
Circle(
uuid('hole-circle-doc'),
Layer('top_documentation'),
Width(0.1),
Fill(False),
GrabArea(False),
Diameter(diameter),
Position(0, 0),
)
)

return _draw


def draw_rect(x: float, y: float, width: float, height: float) -> Callable[[DfnConfig, Callable[[str], str], Footprint], None]:
def draw_rect(
x: float, y: float, width: float, height: float
) -> Callable[[DfnConfig, Callable[[str], str], Footprint], None]:
def _draw(config: DfnConfig, uuid: Callable[[str], str], footprint: Footprint) -> None:
footprint.add_polygon(Polygon(
uuid=uuid('hole-polygon-doc'),
layer=Layer('top_documentation'),
width=Width(0),
fill=Fill(True),
grab_area=GrabArea(False),
vertices=[
Vertex(Position(x - width / 2, y + height / 2), Angle(0)),
Vertex(Position(x + width / 2, y + height / 2), Angle(0)),
Vertex(Position(x + width / 2, y - height / 2), Angle(0)),
Vertex(Position(x - width / 2, y - height / 2), Angle(0)),
Vertex(Position(x - width / 2, y + height / 2), Angle(0)),
],
))
footprint.add_polygon(
Polygon(
uuid=uuid('hole-polygon-doc'),
layer=Layer('top_documentation'),
width=Width(0),
fill=Fill(True),
grab_area=GrabArea(False),
vertices=[
Vertex(Position(x - width / 2, y + height / 2), Angle(0)),
Vertex(Position(x + width / 2, y + height / 2), Angle(0)),
Vertex(Position(x + width / 2, y - height / 2), Angle(0)),
Vertex(Position(x - width / 2, y - height / 2), Angle(0)),
Vertex(Position(x - width / 2, y + height / 2), Angle(0)),
],
)
)

return _draw


def step_modification_sphere(diameter: float) -> StepModificationFn:
def _fn(body: Any, dot: Any, workplane: Any) -> Tuple[Any, Any]:
return body.cut(workplane.sphere(diameter / 2, centered=True)), dot

return _fn


def step_modification_cylinder(x: float, y: float, diameter: float, length: float) -> StepModificationFn:
def step_modification_cylinder(
x: float, y: float, diameter: float, length: float
) -> StepModificationFn:
def _fn(body: Any, dot: Any, workplane: Any) -> Tuple[Any, Any]:
cutout = workplane.transformed(offset=(x, y, 0), rotate=(0, 90, 0)) \
.cylinder(length, diameter / 2, centered=True)
cutout = workplane.transformed(offset=(x, y, 0), rotate=(0, 90, 0)).cylinder(
length, diameter / 2, centered=True
)
return body.cut(cutout), dot

return _fn


def step_modification_sgp3x(body: Any, dot: Any, workplane: Any) -> Tuple[Any, Any]:
dot = workplane.cylinder(0.2, 0.6, centered=[True, True, False]) \
.transformed(offset=(0.5, 0.5, 0), rotate=(0, 0, 45)) \
dot = (
workplane.cylinder(0.2, 0.6, centered=[True, True, False])
.transformed(offset=(0.5, 0.5, 0), rotate=(0, 0, 45))
.box(0.3, 0.3, 0.3, centered=[True, True, False])
)
return body, dot


# fmt: off
THIRD_CONFIGS = [
# length, width, pitch, pin_count, height_nominal, height_max, lead_length, exposed_width, exposed_length, keywords

# Sensirion
DfnConfig(
length=2.0,
Expand Down Expand Up @@ -411,3 +441,4 @@ def step_modification_sgp3x(body: Any, dot: Any, workplane: Any) -> Tuple[Any, A
no_exp=False,
),
]
# fmt: on
Loading