astra/f1c100s

This code defines and renders a four-layer, top-mounted F1C100S module with detailed pin assignments, schematic annotations, and layout profiles, facilitating design, validation, and routing of the hardware including support for decoupling capacitors, crystal oscillators, and external connectors.

Version
0.11.0
License
unset
Stars
0

scripts/check-capacitor-orientation.ts

import type { CircuitJson } from "circuit-json";

/** Measure actual pad positions and connectivity after rendering/rotation. */
export function checkCapacitorOrientation(json: CircuitJson): string[] {
	const data = json as any[],
		errors: string[] = [];
	const components = data.filter((e) => e.type === "source_component");
	const sourcePorts = data.filter((e) => e.type === "source_port");
	const pcbPorts = data.filter((e) => e.type === "pcb_port");
	const traces = data.filter((e) => e.type === "source_trace");
	for (const cap of components.filter(
		(e) => e.ftype === "simple_capacitor" && !e.name.startsWith("C_OSC"),
	)) {
		const chip = components.find(
			(e) => e.name === "U1" && e.source_group_id === cap.source_group_id,
		);
		if (!chip) {
			errors.push(`${cap.name}: missing processor`);
			continue;
		}
		const pins = [1, 2].map((n) =>
			sourcePorts.find(
				(p) =>
					p.source_component_id === cap.source_component_id &&
					p.pin_number === n,
			),
		);
		const pads = pins.map((p) =>
			pcbPorts.find((q) => q.source_port_id === p?.source_port_id),
		);
		if (pads.some((p) => !p)) {
			errors.push(`${cap.name}: missing pads`);
			continue;
		}
		const net = traces.find((t) =>
			t.connected_source_port_ids.includes(pins[0].source_port_id),
		);
		const dedicated = cap.name.match(/^C_D(\d+)$/);
		const chipPins = sourcePorts.filter(
			(p) =>
				p.source_component_id === chip.source_component_id &&
				net?.connected_source_port_ids.includes(p.source_port_id) &&
				(!dedicated || p.pin_number === Number(dedicated[1])),
		);
		const center = {
			x: (pads[0].x + pads[1].x) / 2,
			y: (pads[0].y + pads[1].y) / 2,
		};
		const targets = chipPins
			.map((p) => pcbPorts.find((q) => q.source_port_id === p.source_port_id))
			.filter(Boolean)
			.sort(
				(a, b) =>
					Math.hypot(a.x - center.x, a.y - center.y) -
					Math.hypot(b.x - center.x, b.y - center.y),
			);
		const target = targets[0];
		if (!target) {
			errors.push(
				`${cap.name}: positive pad is not connected to its processor target`,
			);
			continue;
		}
		const positiveDistance = Math.hypot(
			pads[0].x - target.x,
			pads[0].y - target.y,
		);
		const otherDistance = Math.hypot(
			pads[1].x - target.x,
			pads[1].y - target.y,
		);
		if (positiveDistance + 1e-6 >= otherDistance)
			errors.push(
				`${cap.name}: supply/reference pad faces away from U1 pin ${chipPins.find((p) => p.source_port_id === target.source_port_id)?.pin_number}`,
			);
	}
	return errors;
}