ShiboSoftwareDev/nema8-20mm-dual-usbc-stepper-controller
A compact 4-layer USB‑C PD stepper-motor controller PCB using a CH32X035 MCU, TMC2209 driver, dual USB‑C ports, power protection/regulation, ESD/TVS diodes, current-sense resistors, and NEMA‑8 motor connector.
- Version
- 1.0.13
- License
- unset
- Stars
- 0
scripts/test-manual-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 samePoint = (point, x, y) => Math.hypot(point.x - x, point.y - y) < 1e-5
const groundVia = circuit.find((element) => element.type === "pcb_via" && element.pcb_via_id === "pcb_via_24")
if (false && groundVia) {
circuit = circuit.map((element) => {
if (element.type === "pcb_via" && element.pcb_via_id === groundVia.pcb_via_id) {
return { ...element, x: -1.8, y: -4.7 }
}
if (element.type !== "pcb_trace" || element.pcb_trace_id !== groundVia.pcb_trace_id) return element
return {
...element,
route: element.route.map((point) => samePoint(point, groundVia.x, groundVia.y)
? { ...point, x: -1.8, y: -4.7 }
: point),
}
})
}
const wire = (layer, x, y, width = 0.15) => ({ route_type: "wire", layer, x, y, width })
const via = (fromLayer, toLayer, x, y) => ({
route_type: "via", x, y, from_layer: fromLayer, to_layer: toLayer,
via_diameter: 0.45, via_hole_diameter: 0.3,
})
const originalEnableBranch = circuit.find((element) =>
element.type === "pcb_trace" && element.pcb_trace_id === "source_trace_42__source_trace_43_mst1_0")
const firstInner2 = originalEnableBranch.route.findIndex((point) =>
point.route_type === "wire" && point.layer === "inner2")
const enableTail = originalEnableBranch.route.slice(firstInner2 + 1)
const replacements = {
source_trace_42__source_trace_43_mst0_0: [
wire("top", -1, -3),
wire("top", -1, -3.7),
wire("top", -1.6, -4.7),
via("top", "inner2", -1.6, -4.7),
wire("inner2", -1.6, -4.7),
wire("inner2", -4.5, -4),
via("inner2", "top", -4.5, -4),
wire("top", -4.5, -4),
wire("top", -3.69, -3),
],
source_trace_42__source_trace_43_mst1_0: [
wire("inner2", -1.6, -4.7),
...enableTail,
],
source_trace_14__source_trace_15__source_trace_16_mst1_0: [
wire("bottom", 8.2, 5.699998, 0.2),
wire("bottom", 8.4965, 4.2879, 0.2),
via("bottom", "inner2", 8.4965, 4.2879),
wire("inner2", 8.4965, 4.2879, 0.2),
wire("inner2", 9.5, 3.2, 0.2),
wire("inner2", 9.5, -0.5, 0.2),
wire("inner2", 8.5, -1.0, 0.2),
wire("inner2", 7.4, -3.7, 0.2),
via("inner2", "bottom", 7.4, -3.7),
wire("bottom", 7.4, -3.7, 0.2),
wire("bottom", 8.5, -3.375, 0.2),
],
}
const vioTraceId = "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"
circuit = circuit.map((element) => {
if (element.type !== "pcb_trace" || element.pcb_trace_id !== vioTraceId) return element
const route = [
...element.route.slice(0, 11),
{ ...element.route[10], x: -0.6, y: 5.7 },
{ ...element.route[10], x: 1.3, y: 5.7 },
...element.route.slice(12),
]
return { ...element, route }
})
const vmSenseBTraceId = "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_mst8_0"
circuit = circuit.map((element) => {
if (element.type !== "pcb_trace" || element.pcb_trace_id !== vmSenseBTraceId) return element
return {
...element,
route: element.route.flatMap((point) => point.route_type === "wire" && point.layer === "bottom" &&
samePoint(point, -2.3924, -2.575)
? [{ ...point, x: -2.3, y: -3.1113 }, point]
: [point]),
}
})
const replacementIds = new Set(Object.keys(replacements))
const viaTemplate = circuit.find((element) => element.type === "pcb_via")
const rEnPort = circuit.find((element) => element.type === "pcb_port" &&
samePoint(element, -3.69, -3) && element.layers?.includes("top"))
circuit = circuit.flatMap((element) => {
if (element.type === "pcb_via" && replacementIds.has(element.pcb_trace_id)) return []
if (element.type !== "pcb_trace" || !replacements[element.pcb_trace_id]) return [element]
const firstPort = element.pcb_trace_id === "source_trace_42__source_trace_43_mst1_0"
? undefined
: element.route.find((point) => point.start_pcb_port_id)?.start_pcb_port_id
const lastPort = [...element.route].reverse().find((point) => point.end_pcb_port_id)?.end_pcb_port_id
const route = replacements[element.pcb_trace_id].map((point, index, all) => ({
...point,
...(index === 0 && firstPort ? { start_pcb_port_id: firstPort } : {}),
...(index === all.length - 1 && lastPort ? { end_pcb_port_id: lastPort } : {}),
}))
const newVias = route.filter((point) => point.route_type === "via").map((point, index) => ({
...viaTemplate,
pcb_via_id: `manual_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 [{ ...element, route }, ...newVias]
})
const errors = await runAllRoutingChecks(circuit)
const hard = errors.filter((error) => error.type !== "pcb_trace_warning")
console.log(`hard=${hard.length} warnings=${errors.length - hard.length}`)
console.log(hard.map((error) => `${error.type}\t${error.message}`).join("\n"))
fs.writeFileSync("/tmp/nema8-manual-repairs.json", JSON.stringify(circuit))