imrishabh18/pcbgolf

A complete 4-layer PCBGolf controller PCB with STM32H7 MCU, USB/SD and CAN interfaces, power regulation, protection, connectors, switches, LEDs, clocking, and supporting passives.

Version
1.6.1
License
unset
Stars
0

saved-autorouter.ts

/** Restore externally routed copper while keeping the complete authored circuit.
 * Unlike this core version's pcbRouteCache, this adapter preserves net separation.
 * Pass makeSavedAutorouter(cache) as the board/phase autorouter configuration.
 */
export function makeSavedAutorouter(cache: any) {
  const close = (a: any, b: any) => Math.hypot(a.x - b.x, a.y - b.y) < 0.0001
  return {
    algorithmFn: async (srj: any) => {
      const handlers: Record<string, Array<(event: any) => void>> = {}
      return {
        on(event: string, callback: (event: any) => void) {
          ;(handlers[event] ??= []).push(callback)
        },
        stop() {},
        start() {
          try {
            const traces: any[] = []
            const usedNets = new Set<string>()
            for (const connection of srj.connections) {
              const candidates = Object.entries(cache.nets).filter(([, value]: any) =>
                connection.pointsToConnect.every((point: any) =>
                  value.ports.some((port: any) => close(point, port) &&
                    (!point.port_selector || port.selectors.includes(point.port_selector) ||
                      point.port_selector.startsWith(port.reference + "."))) ||
                  (!point.port_selector && value.routes.some((saved: any) =>
                    saved.route.some((contact: any) => close(point, contact))))))
              if (candidates.length !== 1) {
                throw new Error(`Saved routing does not match current pins/placement for ${connection.name}; regenerate routing`)
              }
              const [netName, net]: any = candidates[0]
              if (usedNets.has(netName)) continue
              usedNets.add(netName)
              if (!net.routes.length && connection.pointsToConnect.length > 1) {
                throw new Error(`No saved copper for ${netName}`)
              }
              for (const [index, saved] of net.routes.entries()) {
                const route = saved.route.map((p: any) => ({ ...p }))
                // Endpoint IDs supplement the geometric contacts where an
                // external router ends exactly at a logical port center.
                for (const [end, key] of [[0, "start_pcb_port_id"], [route.length - 1, "end_pcb_port_id"]] as const) {
                  const point = route[end]
                  const port = connection.pointsToConnect.find((p: any) => close(point, p))
                  if (port?.pcb_port_id && point.route_type === "wire") point[key] = port.pcb_port_id
                }
                traces.push({
                  type: "pcb_trace",
                  pcb_trace_id: `saved_${net.id}_${index}`,
                  connection_name: connection.name,
                  source_trace_id: connection.source_trace_id,
                  route,
                })
              }
            }
            for (const cb of handlers.complete ?? []) cb({ traces })
          } catch (error) {
            for (const cb of handlers.error ?? []) cb({ error })
          }
        },
      }
    },
  }
}