astra/f1c100s

The code defines the physical pin layout, labels, and footprint for the F1C100S system-on-chip (SoC) component used in electronic devices.

Version
0.9.2
License
unset
Stars
0

scripts/save-trace-paths.ts

import { EXTERNAL_NETS } from "../src/pin-map";
import { readFile, writeFile } from "node:fs/promises";
import { fanoutTracePath } from "@tscircuit/props";
import { LAYOUT_PROFILES } from "../src/profiles";
const reverse = (route: any[]) =>
	route
		.toReversed()
		.map((p) =>
			p.route_type === "via"
				? { ...p, from_layer: p.to_layer, to_layer: p.from_layer }
				: { ...p },
		);
for (const profile of LAYOUT_PROFILES) {
	const json = JSON.parse(
		await readFile(`src/generated/${profile}.circuit.json`, "utf8"),
	);
	const ports = json.filter((e: any) => e.type === "pcb_port");
	const sourcePorts = new Map<string, any>(
		json
			.filter((e: any) => e.type === "source_port")
			.map((e: any) => [e.source_port_id, e]),
	);
	const components = new Map<string, any>(
		json
			.filter((e: any) => e.type === "source_component")
			.map((e: any) => [e.source_component_id, e]),
	);
	const paths: any[] = [];
	for (const net of json.filter((e: any) => e.type === "source_trace")) {
		const members = ports.filter((p: any) =>
			net.connected_source_port_ids.includes(p.source_port_id),
		);
		const name = (p: any) =>
			components.get(sourcePorts.get(p.source_port_id).source_component_id)
				.name;
		const root =
			members.find((p: any) =>
				(EXTERNAL_NETS as readonly string[]).includes(name(p)),
			) ??
			members.find((p: any) => name(p) === "Y1") ??
			members[0];
		const graph = new Map<string, { to: string; route: any[] }[]>();
		for (const trace of json.filter(
			(e: any) =>
				e.type === "pcb_trace" && e.source_trace_id === net.source_trace_id,
		)) {
			const route = trace.route.map((p: any) =>
				p.route_type === "wire"
					? {
							route_type: "wire",
							x: p.x,
							y: p.y,
							layer: p.layer,
							width: p.width,
						}
					: {
							route_type: "via",
							x: p.x,
							y: p.y,
							from_layer: p.from_layer,
							to_layer: p.to_layer,
							via_diameter: 0.45,
							via_hole_diameter: 0.2,
						},
			);
			const find = (q: any) =>
				members.find(
					(p: any) =>
						Math.hypot(p.x - q.x, p.y - q.y) < 1e-4 &&
						p.layers.includes(q.layer),
				);
			const a = find(route[0]),
				b = find(route.at(-1));
			if (!a || !b)
				throw Error(`Missing endpoint ${profile} ${trace.pcb_trace_id}`);
			for (const [from, to, r] of [
				[a, b, route],
				[b, a, reverse(route)],
			] as any) {
				if (!graph.has(from.pcb_port_id)) graph.set(from.pcb_port_id, []);
				graph.get(from.pcb_port_id)!.push({ to: to.pcb_port_id, route: r });
			}
		}
		const routes = new Map<string, any[]>([[root.pcb_port_id, []]]),
			queue = [root.pcb_port_id];
		while (queue.length) {
			const id = queue.shift()!;
			for (const edge of graph.get(id) ?? []) {
				if (routes.has(edge.to)) continue;
				routes.set(edge.to, [
					...reverse(edge.route),
					...routes.get(id)!.slice(1),
				]);
				queue.push(edge.to);
			}
		}
		for (const port of members) {
			if (port === root) continue;
			const route = routes.get(port.pcb_port_id);
			if (!route) throw Error(`Disconnected stored net ${net.name}`);
			const source = sourcePorts.get(port.source_port_id);
			paths.push(
				fanoutTracePath.parse({
					connection: `${name(port)}.pin${source.pin_number}`,
					route,
				}),
			);
		}
	}
	await writeFile(
		`src/generated/${profile}.trace-paths.json`,
		JSON.stringify(paths, null, 2) + "\n",
	);
	console.log(profile, paths.length, "saved paths");
}