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-conventions.ts
import type { CircuitJson } from "circuit-json";
/** Inspect emitted copper, rather than relying on router settings. */
export function checkConventionalRouting(json: CircuitJson): string[] {
const errors: string[] = [];
for (const t of json as any[])
if (t.type === "pcb_trace") {
for (let i = 1; i < t.route.length; i++) {
const a = t.route[i - 1],
b = t.route[i];
// Include wire-to-via approaches as well as wire-to-wire runs.
// A layer change at one via has zero XY length.
const dx = Math.abs(b.x - a.x),
dy = Math.abs(b.y - a.y);
if (Math.min(dx, dy, Math.abs(dx - dy)) > 1e-6)
errors.push(`${t.pcb_trace_id}[${i}]: non-45-degree segment`);
}
}
const components = (json as any[]).filter(
(e) => e.type === "source_component",
);
const pcbComponents = (json as any[]).filter(
(e) => e.type === "pcb_component",
);
for (const e of json as any[]) {
if (e.type !== "pcb_component" && e.type !== "pcb_smtpad") continue;
const pcb =
e.type === "pcb_component"
? e
: pcbComponents.find((p) => p.pcb_component_id === e.pcb_component_id);
const c = components.find(
(c) => c.source_component_id === pcb?.source_component_id,
);
const underside =
c?.name.startsWith("C_B_") ||
["C_TV_VRN", "C_TV_VRP", "C_TV_REF"].includes(c?.name);
if (e.layer !== (underside ? "bottom" : "top"))
errors.push(`${c?.name}: component copper is on the wrong side`);
}
const nets = (json as any[]).filter(
(e) => e.type === "source_trace" && /^N_HOSC[IO]$/.test(e.name),
);
for (const net of nets) {
const routes = (json as any[]).filter(
(e) =>
e.type === "pcb_trace" && e.source_trace_id === net.source_trace_id,
);
if (
routes.some((t) =>
t.route.some((p: any) => p.route_type !== "wire" || p.layer !== "top"),
)
)
errors.push(
`${net.name}: crystal signal must remain on top without vias`,
);
for (const t of routes) {
const length = t.route.reduce(
(sum: number, b: any, i: number) =>
i
? sum + Math.hypot(b.x - t.route[i - 1].x, b.y - t.route[i - 1].y)
: sum,
0,
);
if (length > 10) errors.push(`${net.name}: crystal route exceeds 10 mm`);
}
}
return errors;
}