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

src/index.tsx

import type { CircuitJson } from "circuit-json";
import { joinSavedPathExits } from "./saved-paths";
import { attachSchematicLayout } from "./schematic";
import {
	LAYOUT_PROFILES,
	assertLayoutProfile,
	type LayoutProfile,
} from "./profiles";
import { EXTERNAL_NETS } from "./pin-map";
import native from "./generated/native.circuit.json";
import lcdTopStorageRight from "./generated/lcd_top_storage_right.circuit.json";
import lcdRightStorageBottom from "./generated/lcd_right_storage_bottom.circuit.json";
import lcdTopStorageBottom from "./generated/lcd_top_storage_bottom.circuit.json";
import lcdRightStorageLeft from "./generated/lcd_right_storage_left.circuit.json";

export { LAYOUT_PROFILES, type LayoutProfile };
export {
	F1C100SLcdSchematicBox,
	F1C100SStorageSchematicBox,
	F1C100SGpioSchematicBox,
	F1C100SAudioSchematicBox,
	F1C100SVideoTouchSchematicBox,
	F1C100SSystemSchematicBox,
	F1C100SPowerSchematicBox,
	type F1C100SSchematicBoxProps,
} from "./schematic-boxes";
const profiles: Record<LayoutProfile, unknown> = {
	native,
	lcd_top_storage_right: lcdTopStorageRight,
	lcd_right_storage_bottom: lcdRightStorageBottom,
	lcd_top_storage_bottom: lcdTopStorageBottom,
	lcd_right_storage_left: lcdRightStorageLeft,
};
export interface F1C100SModuleProps {
	name: string;
	layoutProfile?: LayoutProfile;
	pcbX?: number;
	pcbY?: number;
	/** Rotation of the complete stored module, including its exit pads. */
	pcbRotation?: number;
	schX?: number;
	schY?: number;
	schSheetName?: string;
	/** Custom mode lets callers place the exported schematic-box components. */
	schematicLayout?: "default" | "custom";
	/** Connect named module pads to parent selectors or nets. */
	connections?: Partial<Record<string, string>>;
}

/** A fresh copy prevents one placed instance from mutating another's routes. */
export function getF1C100SCircuitJson(
	layoutProfile: LayoutProfile = "native",
): CircuitJson {
	assertLayoutProfile(layoutProfile);
	return structuredClone(profiles[layoutProfile]) as CircuitJson;
}

/** Inflate the imported components and connectivity only. Copper is loaded
 * separately by the native fanout pcbTracePaths API. */
function prepareForInflation(layoutProfile: LayoutProfile): CircuitJson {
	const json = getF1C100SCircuitJson(layoutProfile);
	// Explicit local nets give the schematic conventional named connections.
	// The existing source traces and stored copper retain the same endpoints.
	for (const e of [...json] as any[]) {
		if (e.type !== "source_trace" || !e.name?.startsWith("N_")) continue;
		const netName = e.name.slice(2);
		const id = `source_net_${netName}`;
		(json as any[]).push({
			type: "source_net",
			source_net_id: id,
			name: netName,
			member_source_group_ids: [],
		});
		e.connected_source_net_ids = [id];
	}

	return json
		.filter((e) => e.type !== "pcb_trace" && e.type !== "pcb_via")
		.map((e) =>
			// The pinned inflator lacks crystal and testpoint cases. Temporary
			// chips retain selectors until native components replace them.
			e.type === "source_component" &&
			["simple_crystal", "simple_test_point"].includes(e.ftype)
				? { ...e, ftype: "simple_chip" as const }
				: e,
		) as CircuitJson;
}

/** Four-layer, top-mounted, pre-routed F1C100S + decoupling module.
 * The package uses stored copper. No fanout solver runs during instantiation.
 */
export function F1C100SModule(props: F1C100SModuleProps) {
	if ("busProfile" in props || "variant" in props || "busExits" in props)
		throw new Error("Use layoutProfile to select a stored F1C100S layout");
	const {
		name,
		layoutProfile = "native",
		connections = {},
		schematicLayout = "default",
		...placement
	} = props;
	assertLayoutProfile(layoutProfile);
	if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
		throw new Error("Module name must be a selector-safe identifier");
	for (const port of Object.keys(connections))
		if (!EXTERNAL_NETS.includes(port))
			throw new Error(`Unknown F1C100S terminal '${port}'`);
	return (
		<>
			<subcircuit
				name={name}
				{...{
					ref: (instance: Parameters<typeof attachSchematicLayout>[0]) =>
						attachSchematicLayout(instance, schematicLayout, layoutProfile),
				}}
				minTraceWidth={0.12}
				minViaPadDiameter={0.45}
				minViaHoleDiameter={0.2}
				autorouter={{ local: true, algorithmFn: joinSavedPathExits }}
				schTraceAutoLabelEnabled
				schMaxTraceDistance={3}
				circuitJson={prepareForInflation(layoutProfile)}
				{...placement}
			/>
			{Object.entries(connections).map(([port, target]) =>
				target ? (
					<trace
						key={port}
						name={`${name}_${port}_external`}
						from={`.${name} .${port} > .pin1`}
						to={target}
					/>
				) : null,
			)}
		</>
	);
}
export default F1C100SModule;