seveibar/adm6-breakout
This code defines PCB designs featuring a 60-pin fanout or direct routing layout with multiple signal and power layers, test pads, and component footprints for a high-density electronic breakout board.
- Version
- 1.0.2
- License
- unset
- Stars
- 0
scripts/verify-fanout.mjs
import { readFileSync } from "node:fs"
const debugDir = "dist/autorouter-debug"
const traces = JSON.parse(
readFileSync(`${debugDir}/phase-1.previous-output.traces.json`, "utf8"),
)
const timeout = JSON.parse(
readFileSync(`${debugDir}/phase-1.timeout.json`, "utf8"),
)
const circuit = JSON.parse(
readFileSync(`${debugDir}/board.source-and-pcb.circuit.json`, "utf8"),
)
const j1Source = circuit.find(
(element) => element.type === "source_component" && element.name === "J1",
)
const j1Pcb = circuit.find(
(element) =>
element.type === "pcb_component" &&
element.source_component_id === j1Source?.source_component_id,
)
const connectorPads = circuit.filter(
(element) =>
element.type === "pcb_smtpad" &&
element.pcb_component_id === j1Pcb?.pcb_component_id,
)
const alignmentHoles = circuit.filter(
(element) =>
element.type === "pcb_hole" &&
element.pcb_component_id === j1Pcb?.pcb_component_id,
)
const firstRowX = connectorPads
.filter((pad) => Math.abs(pad.y - connectorPads[0].y) < 0.001)
.map((pad) => pad.x)
.sort((a, b) => a - b)
const measuredPitch = firstRowX[1] - firstRowX[0]
const measuredPadDiameter = connectorPads[0]?.radius * 2
const sourcePortIds = new Set()
const layers = new Set()
let viaCount = 0
for (const trace of traces) {
if (trace.type !== "pcb_trace") {
throw new Error(`Unexpected fanout element type: ${trace.type}`)
}
for (const point of trace.route ?? []) {
if (point.start_pcb_port_id) sourcePortIds.add(point.start_pcb_port_id)
if (point.layer) layers.add(point.layer)
if (point.route_type === "via") viaCount += 1
}
}
const summary = {
exactFootprintPads: connectorPads.length,
alignmentHoles: alignmentHoles.length,
measuredPadDiameterMm: measuredPadDiameter,
measuredPitchMm: measuredPitch,
denseFanoutTraceCount: traces.length,
uniqueSourcePadsEscaped: sourcePortIds.size,
layersUsed: [...layers].sort(),
viaCount,
followUpPhase: timeout.phaseOrdinal,
followUpConnectionCount: timeout.connectionCount,
followUpStatus: "intentionally timeout-bounded",
}
console.log(JSON.stringify(summary, null, 2))
if (traces.length !== 240) {
throw new Error(`Expected 240 dense fanout traces, found ${traces.length}`)
}
if (connectorPads.length !== 240 || alignmentHoles.length !== 2) {
throw new Error(
`Exact ADM6 footprint mismatch: ${connectorPads.length} pads, ${alignmentHoles.length} alignment holes`,
)
}
if (Math.abs(measuredPitch - 0.635) > 0.001) {
throw new Error(`Expected 0.635 mm connector pitch, found ${measuredPitch}`)
}
if (Math.abs(measuredPadDiameter - 0.356) > 0.001) {
throw new Error(
`Expected 0.356 mm connector pads, found ${measuredPadDiameter}`,
)
}
if (sourcePortIds.size !== 240) {
throw new Error(
`Expected 240 unique connector pads to escape, found ${sourcePortIds.size}`,
)
}
if (timeout.previousTraceCount !== 240) {
throw new Error(
`Follow-up phase did not receive all 240 fanout traces (${timeout.previousTraceCount})`,
)
}