shibosoftwaredev/f1c100s-linux-nema17-stepper-controller

A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.

Version
0.4.56
License
unset
Stars
0

scripts/prepare-round9-net-repair.mjs

import fs from "node:fs"
import assert from "node:assert/strict"
const base="../../checkpoints/nema17-round8-validated-local-20261020-ii8Wrw/restore-verified"
const read=p=>JSON.parse(fs.readFileSync(p,"utf8"))
const c=read(process.env.ROUND9_BASE_CIRCUIT??`${base}/dist/index/circuit.json`),routes=read(process.env.ROUND9_BASE_ROUTES??`${base}/routing/complete-routes.json`)
const parent=new Map()
const root=id=>{if(!parent.has(id))parent.set(id,id);if(parent.get(id)!==id)parent.set(id,root(parent.get(id)));return parent.get(id)}
for(const e of c){const ids=e.type==="source_trace"?[...e.connected_source_port_ids,...e.connected_source_net_ids]:e.type==="source_component_internal_connection"?e.source_port_ids:[];for(const p of ids.slice(1))parent.set(root(p),root(ids[0]))}
const sources=new Map(c.filter(e=>e.type==="source_trace").map(e=>[e.source_trace_id,e]))
const net=s=>root([...s.connected_source_port_ids,...s.connected_source_net_ids][0])
const selected=new Set((process.env.ROUND9_TARGETS??"buck,rail,pd,rx").split(","))
const targets=Object.entries({buck:[-13.1,-7.1],rail:[11.32,-13.25],pd:[10.5,-14.1],rx:[-13.6,-5.35]}).filter(([k])=>selected.has(k)).map(([,v])=>v)
const nets=new Set(),removed=[]
const retained=routes.map(t=>({...t,route:t.route.filter(p=>{
  const bad=p.route_type==="via"&&targets.some(([x,y])=>Math.hypot(x-p.x,y-p.y)<1e-6)
  if(bad){nets.add(net(sources.get(t.source_trace_id)));removed.push([p.x,p.y])}
  return !bad
})}))
assert.equal(new Set(removed.map(p=>p.join(","))).size,targets.length)
const jobs=[...sources.values()].filter(s=>nets.has(net(s))).map(s=>({source:s.source_trace_id}))
for(const j of jobs)if(["source_trace_226","source_trace_342"].includes(j.source))j.target={x:5.2451,y:-7.4442,layers:["top","inner1","inner2","bottom"],pcb_port_id:"real_enable_barrel",connected_tree:true}
// Logic and Ethernet first; unchanged real copper is used as the goal tree.
// The router may skip already-connected sources, but may not infer layer
// joins where a drilled barrel has just been retired.
jobs.sort((a,b)=>({source_trace_226:0,source_trace_340:1,source_trace_341:2,source_trace_342:3,
  source_trace_124:4,source_trace_126:5,source_trace_127:6,source_trace_129:7,
  source_trace_197:8,source_trace_386:9}[a.source]??10)-({source_trace_226:0,source_trace_340:1,source_trace_341:2,source_trace_342:3,
  source_trace_124:4,source_trace_126:5,source_trace_127:6,source_trace_129:7,
  source_trace_197:8,source_trace_386:9}[b.source]??10))
for(const j of jobs)if(net(sources.get(j.source))===net(sources.get('source_trace_111')))j.constraints={allowed_layers:["top","bottom"]}
const write=(p,o)=>fs.writeFileSync(p,JSON.stringify(o,null,2)+"\n")
write("routing/round9-net-placement.circuit.json",c)
write("routing/round9-net-retained.json",retained)
write("routing/round9-net-plan.json",{prefix:process.env.ROUND9_PREFIX??"round9-net",candidateOnly:true,placement:"routing/round9-net-placement.circuit.json",
  retained:"routing/round9-net-retained.json",extent:[-20.9,-20.9,20.9,20.9],jobs})
console.log(JSON.stringify({retiredDrills:targets,nets:nets.size,jobs:jobs.map(j=>j.source)}))