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
19 changes: 11 additions & 8 deletions lib/components/normal-components/Board/Board.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getReadablePcbFoldIssueMessage } from "lib/utils/cad/get-readable-pcb-fold-issue-message"
import { tryCreatePcbFold, type PcbFold } from "@tscircuit/flex-utils"
import { type PcbFold, tryCreatePcbFold } from "@tscircuit/flex-utils"
import { jlcMinTolerances } from "@tscircuit/jlcpcb-manufacturing-specs"
import { getBoundsFromPoints } from "@tscircuit/math-utils"
import { boardProps } from "@tscircuit/props"
Expand All @@ -9,30 +8,34 @@ import type {
PcbBoard,
PcbVia,
} from "circuit-json"
import { getReadablePcbFoldIssueMessage } from "lib/utils/cad/get-readable-pcb-fold-issue-message"
import { getBoardAvailableLayers } from "lib/utils/getViaSpanLayers"
import { getViaTenting } from "lib/utils/getViaTenting"
import { type Matrix, compose, translate } from "transformation-matrix"
import type { z } from "zod"
import { z } from "zod"
import { getDescendantSubcircuitIds } from "../../../utils/autorouting/getAncestorSubcircuitIds"
import { getBoardCenterFromAnchor } from "../../../utils/boards/get-board-center-from-anchor"
import { inflateCircuitJson } from "../../../utils/circuit-json/inflate-circuit-json"
import { getViaDiameterDefaults } from "../../../utils/pcbStyle/getViaDiameterDefaults"
import { NormalComponent } from "../../base-components/NormalComponent/NormalComponent"
import type { RenderPhase } from "../../base-components/Renderable"
import { Group } from "../../primitive-components/Group/Group"
import { resolveBoardMotorMount } from "../../primitive-components/resolve-board-motor-mount"
import type { SubcircuitI } from "../../primitive-components/Group/Subcircuit/SubcircuitI"
import { Subcircuit_doInitialRenderIsolatedSubcircuits } from "../../primitive-components/Group/Subcircuit/Subcircuit_doInitialRenderIsolatedSubcircuits"
import { Subcircuit_getSubcircuitPropHash } from "../../primitive-components/Group/Subcircuit_getSubcircuitPropHash"
import { Board_updatePcbDesignRuleChecks } from "./Board_updatePcbDesignRuleChecks"
import { resolveBoardMotorMount } from "../../primitive-components/resolve-board-motor-mount"
import type { BoardI } from "./BoardI"
import { Board_doInitialPcbCopperPourCleanup } from "./Board_doInitialPcbCopperPourCleanup"
import { Board_doInitialPcbPlacementDesignRuleChecks } from "./Board_doInitialPcbPlacementDesignRuleChecks"
import { Board_doInitialPcbStackupRender } from "./Board_doInitialPcbStackupRender"
import { Board_updatePcbDesignRuleChecks } from "./Board_updatePcbDesignRuleChecks"
import { BoardCastellatedHole } from "./board-castellated-hole"

const MIN_EFFECTIVE_BORDER_RADIUS_MM = 0.01
const DEFAULT_VIA_PAD_DIAMETER_OVER_HOLE_DIAMETER_MM = 0.15
const boardPropsWithStackup = boardProps.extend({
jlcpcbStackup: z.string().optional(),
})

/**
* Return board-local outline points in mm, centered at the origin in the
Expand Down Expand Up @@ -106,7 +109,7 @@ const getRoundedRectOutline = (
}

export class Board
extends Group<typeof boardProps>
extends Group<typeof boardPropsWithStackup>
implements BoardI, SubcircuitI
{
pcbFold: PcbFold | undefined
Expand All @@ -124,7 +127,7 @@ export class Board
super.doInitialCadModelRender()
}

constructor(props: z.input<typeof boardProps>) {
constructor(props: z.input<typeof boardPropsWithStackup>) {
super(props)
this._castellatedHoles = BoardCastellatedHole.fromBoardOutline(
this._parsedProps.outline,
Expand Down Expand Up @@ -176,7 +179,7 @@ export class Board
get config() {
return {
componentName: "Board",
zodProps: boardProps,
zodProps: boardPropsWithStackup,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { getJlcStackup } from "@tscircuit/jlcpcb-manufacturing-specs"
import {
getJlcStackup,
jlcStackups,
} from "@tscircuit/jlcpcb-manufacturing-specs"
import type { PcbBoard } from "circuit-json"
import type { Board } from "./Board"

Expand All @@ -17,14 +20,29 @@ export function Board_doInitialPcbStackupRender(
element.pcb_board_id === importedPcbBoard?.pcb_board_id,
)
let layers = importedStackup?.layers
if (!layers && board._parsedProps.fabricatorPreset) {
const { num_layers, thickness, material } =
importedPcbBoard ?? db.pcb_board.get(pcb_board_id)!
layers = getJlcStackup({
const { fabricatorPreset, jlcpcbStackup } = board._parsedProps
if (!layers && (fabricatorPreset || jlcpcbStackup)) {
const {
num_layers,
thickness: thickness ?? board.boardThickness,
material,
})?.layers
thickness,
material = "fr4",
} = importedPcbBoard ?? db.pcb_board.get(pcb_board_id)!
const resolvedThickness = thickness ?? board.boardThickness
layers = (
jlcpcbStackup
? jlcStackups.find(
(stackup) =>
stackup.name === jlcpcbStackup &&
stackup.num_layers === num_layers &&
stackup.thickness === resolvedThickness &&
stackup.material === material,
)
: getJlcStackup({
num_layers,
thickness: resolvedThickness,
material,
})
)?.layers
}
if (!layers) return

Expand Down
2 changes: 1 addition & 1 deletion lib/fiber/intrinsic-jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface TscircuitElements {
diode: Props.DiodeProps
fuse: Props.FuseProps
led: Props.LedProps
board: Props.BoardProps
board: Props.BoardProps & { jlcpcbStackup?: string }
drccheck: Props.DrcCheckProps
mountedboard: Props.MountedBoardProps
panel: Props.PanelProps
Expand Down
27 changes: 27 additions & 0 deletions tests/components/normal-components/board-stackup-preset5.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { expect, test } from "bun:test"
import { jlc04101h1080Stackup } from "@tscircuit/jlcpcb-manufacturing-specs"
import { pcb_stackup } from "circuit-json"
import { getBoardStackupFixture } from "tests/fixtures/get-board-stackup-fixture"

test("jlcpcbStackup selects JLC04101H-1080 for 4-layer 1.0mm FR-4 board", async () => {
const circuit = await getBoardStackupFixture({
width: "100mm",
height: "100mm",
layers: 4,
thickness: 1,
material: "fr4",
fabricatorPreset: "jlcpcb_standard",
jlcpcbStackup: "JLC04101H-1080",
})
const stackups = circuit.db.pcb_stackup.list()
expect(stackups).toHaveLength(1)
const stackup = stackups[0]!
expect(pcb_stackup.parse(stackup)).toEqual(stackup)
expect(stackup.layers).toEqual(jlc04101h1080Stackup.layers)
expect(stackup.layers[1]).toMatchObject({
material_name: "1080 RC67%",
thickness: 0.0764,
relative_permittivity: 3.91,
})
expect(circuit.db.pcb_placement_error.list()).toHaveLength(0)
})
28 changes: 28 additions & 0 deletions tests/components/normal-components/board-stackup-preset6.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { expect, test } from "bun:test"
import { jlc04101h2116Stackup } from "@tscircuit/jlcpcb-manufacturing-specs"
import { pcb_stackup } from "circuit-json"
import { getBoardStackupFixture } from "tests/fixtures/get-board-stackup-fixture"

test("jlcpcbStackup selects JLC04101H-2116 for 4-layer 1.0mm FR-4 board", async () => {
const circuit = await getBoardStackupFixture({
width: "100mm",
height: "100mm",
layers: 4,
thickness: 1,
material: "fr4",
fabricatorPreset: "jlcpcb_standard",
jlcpcbStackup: "JLC04101H-2116",
})
const stackups = circuit.db.pcb_stackup.list()
expect(stackups).toHaveLength(1)
const stackup = stackups[0]!
expect(pcb_stackup.parse(stackup)).toEqual(stackup)
expect(stackup.layers).toEqual(jlc04101h2116Stackup.layers)
expect(stackup.layers).toHaveLength(9)
expect(stackup.layers[1]).toMatchObject({
material_name: "2116 RC54%",
thickness: 0.124,
relative_permittivity: 4.16,
})
expect(circuit.db.pcb_placement_error.list()).toHaveLength(0)
})
27 changes: 27 additions & 0 deletions tests/components/normal-components/board-stackup-preset7.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { expect, test } from "bun:test"
import { jlc04101h3313Stackup } from "@tscircuit/jlcpcb-manufacturing-specs"
import { pcb_stackup } from "circuit-json"
import { getBoardStackupFixture } from "tests/fixtures/get-board-stackup-fixture"

test("jlcpcbStackup selects JLC04101H-3313 for 4-layer 1.0mm FR-4 board", async () => {
const circuit = await getBoardStackupFixture({
width: "100mm",
height: "100mm",
layers: 4,
thickness: 1,
material: "fr4",
fabricatorPreset: "jlcpcb_standard",
jlcpcbStackup: "JLC04101H-3313",
})
const stackups = circuit.db.pcb_stackup.list()
expect(stackups).toHaveLength(1)
const stackup = stackups[0]!
expect(pcb_stackup.parse(stackup)).toEqual(stackup)
expect(stackup.layers).toEqual(jlc04101h3313Stackup.layers)
expect(stackup.layers[1]).toMatchObject({
material_name: "3313 RC57%",
thickness: 0.0994,
relative_permittivity: 4.1,
})
expect(circuit.db.pcb_placement_error.list()).toHaveLength(0)
})
27 changes: 27 additions & 0 deletions tests/components/normal-components/board-stackup-preset8.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { expect, test } from "bun:test"
import { jlc04101h7628Stackup } from "@tscircuit/jlcpcb-manufacturing-specs"
import { pcb_stackup } from "circuit-json"
import { getBoardStackupFixture } from "tests/fixtures/get-board-stackup-fixture"

test("jlcpcbStackup selects JLC04101H-7628 for 4-layer 1.0mm FR-4 board", async () => {
const circuit = await getBoardStackupFixture({
width: "100mm",
height: "100mm",
layers: 4,
thickness: 1,
material: "fr4",
fabricatorPreset: "jlcpcb_standard",
jlcpcbStackup: "JLC04101H-7628",
})
const stackups = circuit.db.pcb_stackup.list()
expect(stackups).toHaveLength(1)
const stackup = stackups[0]!
expect(pcb_stackup.parse(stackup)).toEqual(stackup)
expect(stackup.layers).toEqual(jlc04101h7628Stackup.layers)
expect(stackup.layers[1]).toMatchObject({
material_name: "7628 RC49%",
thickness: 0.2104,
relative_permittivity: 4.4,
})
expect(circuit.db.pcb_placement_error.list()).toHaveLength(0)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { expect, test } from "bun:test"
import { getBoardStackupFixture } from "tests/fixtures/get-board-stackup-fixture"

test("mismatched jlcpcbStackup construction for board thickness emits no stackup", async () => {
const circuit = await getBoardStackupFixture({
width: 20,
height: 20,
fabricatorPreset: "jlcpcb_standard",
jlcpcbStackup: "JLC04161H-3313",
layers: 4,
thickness: 1,
material: "fr4",
})
expect(circuit.db.pcb_stackup.list()).toHaveLength(0)
expect(circuit.db.pcb_placement_error.list()).toHaveLength(0)
})
4 changes: 3 additions & 1 deletion tests/fixtures/get-board-stackup-fixture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { AnyCircuitElement, PcbBoard } from "circuit-json"
import simpleCircuitJson from "tests/components/normal-components/assets/simple-circuit.json"
import { getTestFixture } from "./get-test-fixture"

export const getBoardStackupFixture = async (boardProps: BoardProps) => {
export const getBoardStackupFixture = async (
boardProps: BoardProps & { jlcpcbStackup?: string },
) => {
const { circuit } = getTestFixture()
circuit.add(<board {...boardProps} />)
await circuit.renderUntilSettled()
Expand Down
Loading