ShiboSoftwareDev/nema8-20mm-dual-usbc-stepper-controller
A compact 4-layer USB‑C PD/data controller board using a CH32X035 MCU and TMC2209 driver to power and control a NEMA‑8 stepper motor, with 3.3‑V regulation, USB ESD/reverse-polarity/TVS protection, current sensing, and boot control.
- Version
- 1.0.12
- License
- unset
- Stars
- 0
scripts/test-vertical-route-repairs.mjs
import fs from "node:fs"
import { runAllRoutingChecks } from "@tscircuit/checks"
let circuit = JSON.parse(fs.readFileSync("dist/index/circuit.json", "utf8"))
.filter((element) => !String(element.type).endsWith("error"))
const repairs = {
source_trace_34_0: [
["bottom", 0.95, 8.3491], ["bottom", 1.6, 7.7], ["bottom", 2.4, 7.7],
["via", 2.4, 7.7, "bottom", "inner2"],
["inner2", 2.4, 7.7], ["inner2", 5.8, 7.7], ["inner2", 8.8, 4.7], ["inner2", 8.8, -2.5],
["via", 8.8, -2.5, "inner2", "bottom"],
["bottom", 8.8, -2.5], ["bottom", 6.5, -2.5], ["bottom", 6, -1.5],
],
source_trace_35__source_trace_36_mst1_0: [
["bottom", -0.95, 8.3491], ["bottom", -1.8, 7.5], ["bottom", -2.4, 7.5],
["via", -2.4, 7.5, "bottom", "inner2"],
["inner2", -2.4, 7.5], ["inner2", -2, 6.5], ["inner2", -2, 4.5],
["inner2", 3.5, 4.5], ["inner2", 6.5, 6.5], ["inner2", 9, 5.7],
["via", 9, 5.7, "inner2", "top"],
["top", 9, 5.7], ["top", 9.1183, 5.650492],
],
source_trace_17__source_trace_18__source_trace_19__source_trace_20__source_trace_21__source_trace_22__source_trace_23__source_trace_24__source_trace_25_mst8_0: [
["top", -4.71, -3], ["top", -5.2, -3.5],
["via", -5.2, -3.5, "top", "inner2"],
["inner2", -5.2, -3.5], ["inner2", -4, -4.2], ["inner2", 3.5, -4.2],
["inner2", 3.5, 2.6], ["inner2", 2.2854, 2.035],
["via", 2.2854, 2.035, "inner2", "top"],
["top", 2.2854, 2.035], ["top", 1.535, 2.035], ["top", 1.5, 2],
],
source_trace_14__source_trace_15__source_trace_16_mst1_0: [
["bottom", 8.2, 5.699998], ["bottom", 9, 5.7], ["bottom", 9, 2.4],
["bottom", 8.8, 2.2], ["bottom", 8.8, -2.8], ["bottom", 8.5, -3.375],
],
source_trace_12__source_trace_13_mst0_0: [
["top", -1.0974388, 8.679931], ["top", -1.0974388, 5.0],
["via", -1.0974388, 5.0, "top", "inner2"],
["inner2", -1.0974388, 5.0], ["inner2", 1.4024292, 5.0],
["via", 1.4024292, 5.0, "inner2", "top"],
["top", 1.4024292, 5.0], ["top", 1.4024292, 8.679931],
],
source_trace_3__source_trace_4__source_trace_5__source_trace_6__source_trace_7__source_trace_8__source_trace_9__source_trace_10__source_trace_11_mst6_0: [
["top", 7.79, -1.3], ["top", 7.2, -1.3],
["via", 7.2, -1.3, "top", "inner2"],
["inner2", 7.2, -1.3], ["inner2", 6.7, 0.5], ["inner2", 5.0, 1.0], ["inner2", 5.0, 2.0],
["via", 5.0, 2.0, "inner2", "top"],
["top", 5.0, 2.0], ["top", 4.2, 2.575],
],
}
const makeRoute = (original, spec) => {
const firstPort = original.route.find((point) => point.start_pcb_port_id)?.start_pcb_port_id
const lastPort = [...original.route].reverse().find((point) => point.end_pcb_port_id)?.end_pcb_port_id
const nominalWidth = original.route.find((point) => point.width)?.width ?? 0.15
return spec.map((point, index) => {
const [kind, x, y, fromLayer, toLayer] = point
if (kind === "via") return {
route_type: "via", x, y, from_layer: fromLayer, to_layer: toLayer,
via_diameter: 0.45, via_hole_diameter: 0.3,
}
return {
route_type: "wire", layer: kind, x, y, width: nominalWidth,
...(index === 0 && firstPort ? { start_pcb_port_id: firstPort } : {}),
...(index === spec.length - 1 && lastPort ? { end_pcb_port_id: lastPort } : {}),
}
})
}
const repairedTraceIds = new Set(Object.keys(repairs))
const viaTemplate = circuit.find((element) => element.type === "pcb_via")
circuit = circuit.flatMap((element) => {
if (element.type === "pcb_via" && repairedTraceIds.has(element.pcb_trace_id)) return []
if (element.type !== "pcb_trace" || !repairs[element.pcb_trace_id]) return [element]
const route = makeRoute(element, repairs[element.pcb_trace_id])
const replacement = { ...element, route }
const vias = route.filter((point) => point.route_type === "via").map((point, index) => ({
...viaTemplate,
pcb_via_id: `repair_${element.pcb_trace_id}_${index}`,
pcb_trace_id: element.pcb_trace_id,
x: point.x, y: point.y,
hole_diameter: 0.3, outer_diameter: 0.45,
layers: ["top", "inner1", "inner2", "bottom"],
from_layer: point.from_layer, to_layer: point.to_layer,
subcircuit_id: element.subcircuit_id,
}))
return [replacement, ...vias]
})
const errors = await runAllRoutingChecks(circuit)
console.log(errors.length)
console.log(Object.entries(Object.groupBy(errors, (error) => error.type))
.map(([kind, group]) => `${kind}\t${group.length}`).join("\n"))
console.log(errors.filter((error) => error.type !== "pcb_trace_warning")
.map((error) => `${error.pcb_trace_id ?? error.pcb_via_id ?? ""}\t${error.message}`).join("\n"))
fs.writeFileSync("/tmp/nema8-repaired-circuit.json", JSON.stringify(circuit))