Skip to content
Open
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
205 changes: 143 additions & 62 deletions generate_do.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Generate DO packages.

- JEDEC DO-214 https://www.jedec.org/system/files/docs/DO-214D.PDF
- JEDEC DO-219 https://www.jedec.org/sites/default/files/docs/do-219b.pdf

"""

Expand Down Expand Up @@ -63,10 +64,10 @@
StrokeWidth,
)

GENERATOR_NAME = 'librepcb-parts-generator (generate_do.py)'
GENERATOR_NAME = 'librepcb-parts-generator (generate_do214.py)'

line_width = 0.2

silkscreen_clearance = 0.15

# Initialize UUID cache
uuid_cache_file = 'uuid_cache_do.csv'
Expand Down Expand Up @@ -94,7 +95,7 @@ def __init__(
contact_width_min: float,
contact_width_max: float,
variant: str,
common_name: str,
common_name: Optional[str],
):
self.body_length = body_length_nom
self.body_width = body_width_nom
Expand All @@ -116,18 +117,37 @@ def generate_pkg(
library: str,
author: str,
config: DoConfig,
flat_leads: bool,
polarity: bool,
generate_3d_models: bool,
pkgcat: str,
version: str,
create_date: Optional[str],
) -> None:
keywords = f'Diode,SMD,DO-214{config.variant},DO214{config.variant},{config.common_name}'
polarity_text = 'Unidirectional' if polarity else 'Bidirectional'
prefix = 'DIOM' if polarity else 'DIONM'
pkg_name = f'{prefix}{fd(config.total_length, 1)}{fd(config.body_width, 1)}X{fd(config.total_height, 2)}'
assert polarity or not flat_leads, 'Flat leads are only supported for unidirectional diodes'

jedec_id = '219' if flat_leads else '214'
kw_common_name = ',' + config.common_name if config.common_name else ''
keywords = (
f'Diode,SMD,DO-{jedec_id}{config.variant},DO{jedec_id}{config.variant}{kw_common_name}'
)
if flat_leads:
pkg_name = (
f'SODFL{fd(config.total_length, 1)}X{fd(config.body_width, 1)}X{fd(config.total_height, 2)}'
+ f'L{fd(config.contact_length, 1)}X{fd(config.contact_width, 1)}'
)
else:
prefix = 'DIOM' if polarity else 'DIONM'
pkg_name = f'{prefix}{fd(config.total_length, 1)}{fd(config.body_width, 1)}X{fd(config.total_height, 2)}'
if flat_leads:
desc_name = 'Small Outline Diode'
elif polarity:
desc_name = 'Unidirectional Diode Outline'
else:
desc_name = 'Bidirectional Diode Outline'
desc_common_name = ' (' + config.common_name + ')' if config.common_name else ''
pkg_description = f"""\
{polarity_text} Diode Outline DO-214{config.variant} ({config.common_name}), standardized by JEDEC.
{desc_name} DO-{jedec_id}{config.variant}{desc_common_name}, standardized by JEDEC.

Length: {config.total_length:.2f}mm
Width: {config.body_width:.2f}mm
Expand Down Expand Up @@ -295,7 +315,22 @@ def _add_silkscreen(
grab_area=GrabArea(False),
)

if polarity:
if flat_leads:
ss_y = max(
config.body_width / 2 + line_offset, # Based on body width
_pad_width() / 2 + line_width / 2 + silkscreen_clearance, # Based on pad width
)
ss = _add_silkscreen('main', uuid_ns)
x0 = _pad_center(-1) - (_pad_length() / 2 + 0.4)
x1 = right_edge - line_offset
y0 = -ss_y
y1 = ss_y
ss.add_vertex(Vertex(Position(x1, y1), Angle(0)))
ss.add_vertex(Vertex(Position(x0, y1), Angle(0)))
ss.add_vertex(Vertex(Position(x0, y0), Angle(0)))
ss.add_vertex(Vertex(Position(x1, y0), Angle(0)))
footprint.add_polygon(ss)
elif polarity:
ss = _add_silkscreen('main', uuid_ns)
x0 = _pad_center(-1) - (_pad_length() / 2 + 0.4)
x1 = right_edge - line_offset
Expand Down Expand Up @@ -409,7 +444,7 @@ def _add_silkscreen(
# Generate 3D models
uuid_3d = _uuid('3d')
if generate_3d_models:
generate_3d(library, pkg_name, uuid_pkg, uuid_3d, config, polarity)
generate_3d(library, pkg_name, uuid_pkg, uuid_3d, config, flat_leads, polarity)
package.add_3d_model(Package3DModel(uuid_3d, Name(pkg_name)))
for footprint in package.footprints:
footprint.add_3d_model(Footprint3DModel(uuid_3d))
Expand All @@ -423,6 +458,7 @@ def generate_3d(
uuid_pkg: str,
uuid_3d: str,
config: DoConfig,
flat_leads: bool,
polarity: bool,
) -> None:
import cadquery as cq
Expand All @@ -431,52 +467,73 @@ def generate_3d(

print(f'Generating pkg 3D model "{pkg_name}": {uuid_3d}')

body_standoff = 0.15 + (0.05 + 0.3) / 2 # A2 + A3
leg_height = (0.15 + 0.41) / 2 # c
leg_z_top = body_standoff + (config.body_height / 2) + (leg_height / 2)
bend_radius = 0.1 + (leg_height / 2)
body_chamfer_xy = 0.15 # rough estimation
body_chamfer_z = (config.body_height - leg_height) / 2
if flat_leads:
body_standoff = 0.02
lead_thickness = 0.3
body_chamfer_xy = 0.15 # rough estimation
body_chamfer_z = config.body_height - lead_thickness
else:
body_standoff = 0.15 + (0.05 + 0.3) / 2 # A2 + A3
leg_height = (0.15 + 0.41) / 2 # c
leg_z_top = body_standoff + (config.body_height / 2) + (leg_height / 2)
bend_radius = 0.1 + (leg_height / 2)
body_chamfer_xy = 0.15 # rough estimation
body_chamfer_z = (config.body_height - leg_height) / 2
bar_length = 0.2 * config.body_length
bar_width = config.body_width - (3 * body_chamfer_xy)
bar_height = 0.02
bar_x = -(config.body_length - bar_length) / 2 + (2 * body_chamfer_xy)

body = (
cq.Workplane('XY', origin=(0, 0, body_standoff + (config.body_height / 2)))
.box(config.body_length, config.body_width, config.body_height)
.edges('|Y')
.chamfer(body_chamfer_z, body_chamfer_xy)
.edges('|X')
.chamfer(body_chamfer_z, body_chamfer_xy)
body = cq.Workplane('XY', origin=(0, 0, body_standoff + (config.body_height / 2))).box(
config.body_length, config.body_width, config.body_height
)
if flat_leads:
body = body.edges('>Z').chamfer(body_chamfer_z, body_chamfer_xy)
else:
body = (
body.edges('|Y')
.chamfer(body_chamfer_z, body_chamfer_xy)
.edges('|X')
.chamfer(body_chamfer_z, body_chamfer_xy)
)
bar = cq.Workplane('XY', origin=(bar_x, 0, body_standoff + config.body_height)).box(
bar_length, bar_width, bar_height
)
leg_path = (
cq.Workplane('XZ')
.hLine(-config.contact_length + (leg_height / 2) + bend_radius)
.ellipseArc(x_radius=bend_radius, y_radius=bend_radius, angle1=180, angle2=270, sense=-1)
.vLine(leg_z_top - leg_height - (2 * bend_radius))
.ellipseArc(x_radius=bend_radius, y_radius=bend_radius, angle1=90, angle2=180, sense=-1)
.hLine(config.contact_length)
)
leg = cq.Workplane('ZY').rect(leg_height, config.contact_width).sweep(leg_path)

assembly = StepAssembly(pkg_name)
assembly.add_body(body, 'body', StepColor.IC_BODY)
if polarity:
assembly.add_body(bar, 'bar', StepColor.IC_PIN1_DOT)
lead_x = (config.total_length / 2) - config.contact_length
assembly.add_body(
leg, 'leg-1', StepColor.LEAD_SMT, location=cq.Location((-lead_x, 0, leg_height / 2))
)
assembly.add_body(
leg,
'leg-2',
StepColor.LEAD_SMT,
location=cq.Location((lead_x, 0, leg_height / 2), (0, 0, 1), 180),
)

if flat_leads:
leg = cq.Workplane('XY', origin=(0, 0, lead_thickness / 2)).box(
config.contact_length, config.contact_width, lead_thickness
)
lead_x = (config.total_length - config.contact_length) / 2
assembly.add_body(leg, 'leg-1', StepColor.LEAD_SMT, location=cq.Location((-lead_x, 0, 0)))
assembly.add_body(leg, 'leg-2', StepColor.LEAD_SMT, location=cq.Location((lead_x, 0, 0)))
else:
leg_path = (
cq.Workplane('XZ')
.hLine(-config.contact_length + (leg_height / 2) + bend_radius)
.ellipseArc(
x_radius=bend_radius, y_radius=bend_radius, angle1=180, angle2=270, sense=-1
)
.vLine(leg_z_top - leg_height - (2 * bend_radius))
.ellipseArc(x_radius=bend_radius, y_radius=bend_radius, angle1=90, angle2=180, sense=-1)
.hLine(config.contact_length)
)
leg = cq.Workplane('ZY').rect(leg_height, config.contact_width).sweep(leg_path)
lead_x = (config.total_length - config.contact_length) / 2
assembly.add_body(
leg, 'leg-1', StepColor.LEAD_SMT, location=cq.Location((-lead_x, 0, leg_height / 2))
)
assembly.add_body(
leg,
'leg-2',
StepColor.LEAD_SMT,
location=cq.Location((lead_x, 0, leg_height / 2), (0, 0, 1), 180),
)

# Save without fusing for slightly better minification.
out_path = path.join('out', library, 'pkg', uuid_pkg, f'{uuid_3d}.step')
Expand All @@ -496,51 +553,75 @@ def generate_3d(
warning = 'Note: Not generating 3D models unless the "--3d" argument is passed in!'
print(f'\033[1;33m{warning}\033[0m')

configs = []
configs_do214 = []
configs_do219 = []

# body_length_nom (E1); body_width_nom (D); body_height_nom (A1)
# total_length_nom (E); total_height_nom (A)
# contact_length_min, contact_length_nom, contact_length_max (L); contact_width_min, contact_width_max (b)
# variant; common_name
# fmt: off
configs.append(DoConfig(4.30, 3.60, 2.15,
5.40, 2.30,
0.75, 1.15, 1.60, 1.95, 2.20,
'AA', 'SMB'))
configs.append(DoConfig(6.85, 5.90, 2.15,
7.95, 2.30,
0.75, 1.15, 1.60, 2.90, 3.20,
'AB', 'SMC'))
configs.append(DoConfig(4.30, 2.60, 2.30,
5.20, 2.40,
0.75, 1.15, 1.60, 1.25, 1.65,
'AC', 'SMA'))
configs.append(DoConfig(4.45, 2.60, 2.80,
5.25, 2.95,
0.75, 1.15, 1.60, 1.00, 1.70,
'BA', 'GF1'))
configs_do214.append(DoConfig(4.30, 3.60, 2.15,
5.40, 2.30,
0.75, 1.15, 1.60, 1.95, 2.20,
'AA', 'SMB'))
configs_do214.append(DoConfig(6.85, 5.90, 2.15,
7.95, 2.30,
0.75, 1.15, 1.60, 2.90, 3.20,
'AB', 'SMC'))
configs_do214.append(DoConfig(4.30, 2.60, 2.30,
5.20, 2.40,
0.75, 1.15, 1.60, 1.25, 1.65,
'AC', 'SMA'))
configs_do214.append(DoConfig(4.45, 2.60, 2.80,
5.25, 2.95,
0.75, 1.15, 1.60, 1.00, 1.70,
'BA', 'GF1'))
configs_do219.append(DoConfig(2.80, 1.80, 1.30,
3.70, 1.30,
0.66, 0.81, 0.96, 0.80, 1.35,
'AA', None))
configs_do219.append(DoConfig(2.80, 1.80, 0.98,
3.70, 0.98,
0.35, 0.60, 0.85, 0.80, 1.35,
'AB', 'SMF'))
# fmt: on

for config in configs:
for config in configs_do214:
generate_pkg(
library='LibrePCB_Base.lplib',
author='murray',
config=config,
flat_leads=False,
polarity=True,
generate_3d_models=generate_3d_models,
pkgcat='dcaa6b6c-0c55-43fd-a320-5dd74a2cdc85',
version='0.2',
version='0.2.1',
create_date='2023-08-15T22:33:08Z',
)
generate_pkg(
library='LibrePCB_Base.lplib',
author='murray',
config=config,
flat_leads=False,
polarity=False,
generate_3d_models=generate_3d_models,
pkgcat='dcaa6b6c-0c55-43fd-a320-5dd74a2cdc85',
version='0.2',
version='0.2.1',
create_date='2023-08-15T22:33:08Z',
)

for config in configs_do219:
generate_pkg(
library='LibrePCB_Base.lplib',
author='eduardosm',
config=config,
flat_leads=True,
polarity=True,
generate_3d_models=generate_3d_models,
pkgcat='9b31c9b4-04b6-4f97-ad12-f095d196bd38',
version='0.1',
create_date='2026-06-06T11:58:35Z',
)

save_cache(uuid_cache_file, uuid_cache)
26 changes: 26 additions & 0 deletions uuid_cache_do.csv
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,29 @@ pkg-dionm7959x230-default-text-value,7ca9ef7b-684e-421b-9acb-d0f938956804
pkg-dionm7959x230-pad-1,c3ba2d5a-579a-4872-a000-4c4257c38b04
pkg-dionm7959x230-pad-2,8bdd5bd5-b9db-4e9e-8ef6-09bbd8636636
pkg-dionm7959x230-pkg,23044d61-28c6-42a4-aff7-c3d06ed91819
pkg-sodfl37x18x130l8x11-3d,99459aa9-1962-4821-97d2-eae2d8e501d5
pkg-sodfl37x18x130l8x11-default-body,1fb7d2ed-b0c7-42ef-858d-4dcf215386ec
pkg-sodfl37x18x130l8x11-default-cathodeband,f6553238-b583-4d0d-8066-d6390898d27d
pkg-sodfl37x18x130l8x11-default-courtyard,08726808-0766-407b-a676-c8746320e34d
pkg-sodfl37x18x130l8x11-default-footprint,55262945-b05e-4a1e-ac9e-99861e148198
pkg-sodfl37x18x130l8x11-default-outline,2d527d5c-f9a4-47f5-b453-88c8cceddc6d
pkg-sodfl37x18x130l8x11-default-pad-lead,65f11457-8b2f-45dc-9cde-2224b74ecdd2
pkg-sodfl37x18x130l8x11-default-silkscreen-main,0bf50b6a-fd79-461f-bd12-60817ca71135
pkg-sodfl37x18x130l8x11-default-text-name,84034b4a-e0b4-4bea-a3e2-4040a65638f8
pkg-sodfl37x18x130l8x11-default-text-value,0cc5aad8-b51a-4ecb-adfa-256d1fce70a0
pkg-sodfl37x18x130l8x11-pad-a,4f11dc61-1f1c-4608-87ea-69a61136a8b4
pkg-sodfl37x18x130l8x11-pad-c,a316f30f-a484-4eab-8a6e-56e6961b481d
pkg-sodfl37x18x130l8x11-pkg,3acfbe0a-9c1a-49dc-9904-12bda61df4cd
pkg-sodfl37x18x98l6x11-3d,3b477e1c-b935-49bf-9500-465ee6d70981
pkg-sodfl37x18x98l6x11-default-body,93170fa3-0f61-476d-87a7-09e3053d1873
pkg-sodfl37x18x98l6x11-default-cathodeband,3ed6674d-1e3a-433a-85b4-5cda4f3954c1
pkg-sodfl37x18x98l6x11-default-courtyard,e2dbbd49-956e-414e-9d6d-36b0580170e4
pkg-sodfl37x18x98l6x11-default-footprint,24a4f12f-003c-4d6c-8f12-ded0898808b8
pkg-sodfl37x18x98l6x11-default-outline,e696d218-6cf9-46b7-9df8-a98d5eb322fb
pkg-sodfl37x18x98l6x11-default-pad-lead,08a5368f-0d28-49d4-8892-c4eb1a5d1923
pkg-sodfl37x18x98l6x11-default-silkscreen-main,9b0b4770-0ad4-4ec6-ac8c-a46193fbd639
pkg-sodfl37x18x98l6x11-default-text-name,f939aa7b-46c4-4a48-b22f-8661651d0b2c
pkg-sodfl37x18x98l6x11-default-text-value,3c659bb0-8f4e-4dce-9b0b-a73698427275
pkg-sodfl37x18x98l6x11-pad-a,4f73a2de-7684-4b17-9bf5-34569fcc8a01
pkg-sodfl37x18x98l6x11-pad-c,f6a7ddb4-6975-4526-8035-03a8e435577b
pkg-sodfl37x18x98l6x11-pkg,43267682-013c-429a-ae15-2ba5b6f0569e
Loading