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
3 changes: 3 additions & 0 deletions src/fn/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { dip } from "./dip"
export { spdip28 } from "./spdip28"
export { pdip } from "./pdip"
export { diode } from "./diode"
export { cap } from "./cap"
export { led } from "./led"
Expand Down Expand Up @@ -81,3 +83,4 @@ export { sot343 } from "./sot343"
export { m2host } from "./m2host"
export { mountedpcbmodule } from "./mountedpcbmodule"
export { to92l } from "./to92l"
export { utdfn4ep1x1 } from "./utdfn4ep1x1"
24 changes: 24 additions & 0 deletions src/fn/pdip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { AnyCircuitElement } from "circuit-json"
import { dip } from "./dip"

/**
* PDIP-8 (Plastic DIP, 8-pin) footprint
*
* Specs:
* - 8 pins (4 per side)
* - Row spacing: 7.62mm (0.3")
* - Pin pitch: 2.54mm (0.1")
* - Body width: typically 6.35-7.5mm
*/
export const pdip = (): {
circuitJson: AnyCircuitElement[]
parameters: any
} => {
return dip({
fn: "pdip",
dip: true,
num_pins: 8,
w: 7.62,
p: 2.54,
})
}
15 changes: 15 additions & 0 deletions src/fn/spdip28.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { AnyCircuitElement } from "circuit-json"
import { dip } from "./dip"

export const spdip28 = (): {
circuitJson: AnyCircuitElement[]
parameters: any
} => {
return dip({
fn: "spdip28",
dip: true,
num_pins: 28,
w: 7.62,
p: 2.54,
})
}
171 changes: 171 additions & 0 deletions src/fn/utdfn4ep1x1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import type {
AnyCircuitElement,
PcbCourtyardRect,
PcbSilkscreenPath,
} from "circuit-json"
import { z } from "zod"
import { length } from "circuit-json"
import type { NowDefined } from "../helpers/zod/now-defined"
import { rectpad } from "../helpers/rectpad"
import { base_def } from "../helpers/zod/base_def"
import { type SilkscreenRef, silkscreenRef } from "src/helpers/silkscreenRef"

const utdfn4ep1x1_def = base_def.extend({
fn: z.string(),
num_pins: z.union([z.literal(4)]).default(4),
w: z.string().default("1mm"),
h: z.string().default("1mm"),
p: z.string().default("0.5mm"),
pl: z.string().default("0.28mm"),
pw: z.string().default("0.22mm"),
ep: z
.union([z.literal(true), z.object({ x: z.string(), y: z.string() })])
.default(true),
})

type Utdfn4ep1x1Input = z.infer<typeof utdfn4ep1x1_def>

/**
* Ultra-Thin Dual Flat No-Lead with Exposed Pad, 4-pin, 1x1mm
*
* Pins on left and right sides, with a thermal/ep exposed pad at the bottom center.
*/
export const utdfn4ep1x1 = (
raw_params: Utdfn4ep1x1Input,
): { circuitJson: AnyCircuitElement[]; parameters: any } => {
const def = utdfn4ep1x1_def
const parameters = def
.transform((v) => {
const w = length.parse(v.w)
const h = length.parse(v.h)
const p = length.parse(v.p)
const pl = length.parse(v.pl)
const pw = length.parse(v.pw)
if (!v.ep) return v
return {
...v,
w,
h,
p,
pl,
pw,
} as NowDefined<typeof v, "w" | "h" | "p" | "pl" | "pw">
})
.parse(raw_params)

const w = parameters.w
const h = parameters.h
const p = parameters.p
const pl = parameters.pl
const pw = parameters.pw

const pads: AnyCircuitElement[] = []

// Left side pins (1, 2) - going top to bottom
// Right side pins (3, 4) - going bottom to top
// Based on getCcwSoicCoords: pin 1 is top-left, pins increase CCW
for (let i = 0; i < parameters.num_pins; i++) {
const pn = i + 1
const ph = parameters.num_pins / 2
const isLeft = pn <= ph
const leftPinGaps = ph - 1
const gs = p
const sh = gs * leftPinGaps

let x: number
let y: number

if (isLeft) {
x = -w / 2 - pl / 2
y = sh / 2 - (pn - 1) * gs
} else {
x = w / 2 + pl / 2
y = -sh / 2 + (pn - ph - 1) * gs
}

pads.push(rectpad(pn, x, y, pl, pw))
}

// Exposed pad (thermal pad)
if (parameters.ep) {
const epw = 0.55 // exposed pad width
const eph = 0.35 // exposed pad height
pads.push(rectpad(["thermalpad"], 0, 0, epw, eph))
}

// Silkscreen body outline
const silkscreenPaths: PcbSilkscreenPath[] = []
const m = Math.min(1, p / 2)
const sw = w
const sh = (parameters.num_pins / 2 - 1) * p + pw + m

// Pin 1 marker (top-left corner arrow)
const as = p / 4
const atx = -sw / 2 - as / 2
const aty = sh / 2 - p / 2

silkscreenPaths.push({
layer: "top",
pcb_component_id: "",
pcb_silkscreen_path_id: "",
route: [
{ x: atx, y: aty },
{ x: atx - as, y: aty + as },
{ x: atx - as, y: aty - as },
{ x: atx, y: aty },
],
type: "pcb_silkscreen_path",
stroke_width: 0.1,
})

// Silkscreen corners (DFN-style)
for (const corner of [
{ dx: -1, dy: 1 },
{ dx: -1, dy: -1 },
{ dx: 1, dy: -1 },
{ dx: 1, dy: 1 },
] as const) {
const { dx, dy } = corner
silkscreenPaths.push({
layer: "top",
pcb_component_id: "",
pcb_silkscreen_path_id: "",
route: [
{ x: (dx * sw) / 2 - dx * p, y: (dy * sh) / 2 },
{ x: (dx * sw) / 2, y: (dy * sh) / 2 },
{ x: (dx * sw) / 2, y: (dy * sh) / 2 - dy * p },
],
type: "pcb_silkscreen_path",
stroke_width: 0.1,
})
}

const silkscreenRefText: SilkscreenRef = silkscreenRef(0, sh / 2 + 0.4, sh / 12)

const courtyardPadding = 0.25
const padExtentX = w / 2 + pl / 2
const padExtentY = sh / 2
const crtMinX = -padExtentX - courtyardPadding
const crtMaxX = padExtentX + courtyardPadding
const crtMinY = -padExtentY - courtyardPadding
const crtMaxY = padExtentY + courtyardPadding
const courtyard: PcbCourtyardRect = {
type: "pcb_courtyard_rect",
pcb_courtyard_rect_id: "",
pcb_component_id: "",
center: { x: (crtMinX + crtMaxX) / 2, y: (crtMinY + crtMaxY) / 2 },
width: crtMaxX - crtMinX,
height: crtMaxY - crtMinY,
layer: "top",
}

return {
circuitJson: [
...pads,
...silkscreenPaths,
silkscreenRefText,
courtyard,
] as AnyCircuitElement[],
parameters,
}
}
1 change: 1 addition & 0 deletions src/footprinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export type Footprinter = {
dip: (
num_pins?: number,
) => FootprinterParamsBuilder<"w" | "p" | "id" | "od" | "wide" | "narrow">
spdip28: () => FootprinterParamsBuilder<never>
cap: () => FootprinterParamsBuilder<CommonPassiveOptionKey>
res: () => FootprinterParamsBuilder<CommonPassiveOptionKey>
diode: () => FootprinterParamsBuilder<CommonPassiveOptionKey>
Expand Down
Loading