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
38 changes: 37 additions & 1 deletion src/fn/sod123.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { AnyCircuitElement, PcbCourtyardRect } from "circuit-json"
import type {
AnyCircuitElement,
PcbCourtyardRect,
PcbSilkscreenPath,
} from "circuit-json"
import { z } from "zod"
import { rectpad } from "../helpers/rectpad"
import { silkscreenRef, type SilkscreenRef } from "src/helpers/silkscreenRef"
Expand Down Expand Up @@ -39,9 +43,41 @@ export const sod123 = (
layer: "top",
}

// Body outline. Every other member of the sod family draws one; sod123 was
// the only one shipping bare pads. Derived from the pads rather than from
// `h`, because `h` here is the body height (1.22mm) and the pads are taller
// than that (1.2mm tall, so ±0.6) — placing the runs at ±h/2 would leave
// 0.01mm and the stroke alone would put silk on copper.
const padHalfLength = length.parse(parameters.pl) / 2
const padHalfWidth = length.parse(parameters.pw) / 2
const pitch = length.parse(parameters.p)
const strokeWidth = 0.1
const silkPadClearance = 0.2 + strokeWidth / 2

const outlineHalfHeight = padHalfWidth + silkPadClearance
// Left edge sits outboard of pad 1, marking the cathode end like KiCad's
// D_SOD-123 does; the right side stays open so it never crosses pad 2.
const outlineLeftX = -pitch / 2 - padHalfLength - silkPadClearance
const outlineRightX = pitch / 2 - padHalfLength - silkPadClearance

const silkscreenOutline: PcbSilkscreenPath = {
type: "pcb_silkscreen_path",
layer: "top",
pcb_component_id: "",
pcb_silkscreen_path_id: "",
route: [
{ x: outlineRightX, y: outlineHalfHeight },
{ x: outlineLeftX, y: outlineHalfHeight },
{ x: outlineLeftX, y: -outlineHalfHeight },
{ x: outlineRightX, y: -outlineHalfHeight },
],
stroke_width: strokeWidth,
}

return {
circuitJson: sodWithoutParsing(parameters).concat(
...createFabricationNoteDiodeFromCopperPads(parameters),
silkscreenOutline as AnyCircuitElement,
silkscreenRefText as AnyCircuitElement,
courtyard as AnyCircuitElement,
),
Expand Down
63 changes: 62 additions & 1 deletion src/fn/sot723.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
length,
type AnyCircuitElement,
type PcbCourtyardOutline,
type PcbSilkscreenPath,
} from "circuit-json"
import { z } from "zod"
import { rectpad } from "../helpers/rectpad"
Expand Down Expand Up @@ -44,8 +45,68 @@ export const sot723 = (
layer: "top",
}

// Body outline. Every sibling SOT draws one; sot723 shipped bare pads.
// The pads reach past the body on both sides, so this emits the two runs
// that clear copper (above pin 1 / below pin 2) rather than a closed box,
// which is what KiCad's SOT-723 does.
const padHalfWidth = length.parse(parameters.pw) / 2
const padHalfLength = length.parse(parameters.pl) / 2
const pitch = length.parse(parameters.p)
const strokeWidth = 0.1
const silkPadClearance = 0.2 + strokeWidth / 2

// Take the pad extents from the coordinate function rather than assuming
// them, so the outline follows if the geometry is ever parameterised.
const padCoords = [1, 2, 3].map((pn) =>
getCcwSot723Coords({
num_pins: parameters.num_pins,
pn,
w: length.parse(parameters.w),
h: length.parse(parameters.h),
pl: length.parse(parameters.pl),
p: pitch,
}),
)
const padOuterY =
Math.max(...padCoords.map((c) => Math.abs(c.y))) + padHalfWidth
const runY = padOuterY + silkPadClearance
// The runs sit clear of every pad vertically, so they span the body width.
// Clamp anyway against any pad that does reach into the run's y band, so the
// outline stays correct if the geometry is ever parameterised differently.
const bodyHalfWidth = length.parse(parameters.w) / 2
let runHalfX = bodyHalfWidth
for (const coord of padCoords) {
const padTop = coord.y + padHalfWidth + silkPadClearance
const padBottom = coord.y - padHalfWidth - silkPadClearance
// `>=` so a run that only grazes the clearance boundary — which is exactly
// where `runY` lands for the outermost pad — isn't treated as a collision.
if (runY >= padTop || runY <= padBottom) continue
runHalfX = Math.min(
runHalfX,
Math.max(0, Math.abs(coord.x) - padHalfLength - silkPadClearance),
)
}

const silkPath = (id: string, y: number): PcbSilkscreenPath => ({
type: "pcb_silkscreen_path",
layer: "top",
pcb_component_id: "",
pcb_silkscreen_path_id: id,
route: [
{ x: -runHalfX, y },
{ x: runHalfX, y },
],
stroke_width: strokeWidth,
})

return {
circuitJson: [...pad, silkscreenRefText as AnyCircuitElement, courtyard],
circuitJson: [
...pad,
silkPath("silkscreen_path_top", runY) as AnyCircuitElement,
silkPath("silkscreen_path_bottom", -runY) as AnyCircuitElement,
silkscreenRefText as AnyCircuitElement,
courtyard,
],
parameters,
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/__snapshots__/sod123.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/__snapshots__/sot723.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading