gokul/lora-device
A compact LoRa/GNSS device PCB integrating an SX1262 radio, GNSS module, USB/UART interface, 1.5 µH inductor, LiPo battery connector with NTC, and supporting passives.
- Version
- 0.1.6
- License
- unset
- Stars
- 0
routing/autorouter.ts
import { AutoroutingPipelineSolver9_PreloadedTraceGraph } from "@tscircuit/capacity-autorouter";
import type { SimpleRouteJson } from "@tscircuit/capacity-autorouter";
import { pcb_trace } from "circuit-json";
import { z } from "zod";
import reviewedRoutes from "./reviewed-routes.json";
import reviewedInputHash from "./input-sha256.json";
// Generated with capacity-autorouter 0.0.988, then reviewed and locally corrected.
// Set false to regenerate with that same native solver after changing placement.
const useReviewedRoutes = true;
const traceSchema = pcb_trace.extend({
connection_name: z.string(),
connectsTo: z.array(z.string()),
});
const routes = reviewedRoutes.map((route) => traceSchema.parse(route));
type RouterEvent = {
traces?: typeof routes;
error?: Error;
progress?: number;
};
type Handler = (event: RouterEvent) => void;
async function hashRoutingInput(input: SimpleRouteJson) {
const bytes = new TextEncoder().encode(JSON.stringify(input));
const hash = await crypto.subtle.digest("SHA-256", bytes);
return Array.from(new Uint8Array(hash), (byte) =>
byte.toString(16).padStart(2, "0"),
).join("");
}
/** Replays reviewed native output only when every routing input is unchanged. */
export async function createTrackerAutorouter(input: SimpleRouteJson) {
const handlers = new Map<string, Handler[]>();
let stopped = false;
const emit = (name: string, event: RouterEvent) => {
for (const handler of handlers.get(name) ?? []) handler(event);
};
return {
on(name: string, handler: Handler) {
handlers.set(name, [...(handlers.get(name) ?? []), handler]);
},
stop() {
stopped = true;
},
async start() {
try {
if (useReviewedRoutes) {
if ((await hashRoutingInput(input)) !== reviewedInputHash) {
throw new Error(
"Routing inputs changed. Disable useReviewedRoutes in routing/autorouter.ts, regenerate with the native autorouter, and repeat fabrication validation.",
);
}
emit("complete", { traces: routes });
return;
}
const solver = new AutoroutingPipelineSolver9_PreloadedTraceGraph(
input,
{
effort: 5,
},
);
while (!solver.solved && !solver.failed && !stopped) {
for (
let step = 0;
step < 100 && !solver.solved && !solver.failed;
step++
) {
solver.step();
}
emit("progress", { progress: solver.computeProgress() });
await new Promise((resolve) => setTimeout(resolve, 0));
}
if (stopped) return;
if (solver.failed)
throw new Error(solver.error ?? "Native routing failed");
const generated = solver.getOutputSimplifiedPcbTraces();
emit("complete", {
traces: generated.map((route) => traceSchema.parse(route)),
});
} catch (error) {
emit("error", {
error: error instanceof Error ? error : new Error(String(error)),
});
}
},
};
}