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/check-bulk-top-regression.mjs
import fs from "node:fs"
import assert from "node:assert/strict"
import crypto from "node:crypto"
const baseline="../../checkpoints/nema17-before-rishabh-review-v053-DuFOGi/restore-verified/dist/index/circuit.json"
const input="dist/index/circuit.json"
const read=p=>JSON.parse(fs.readFileSync(p,"utf8"))
const before=read(baseline),after=read(input),moves=read("review-placement.json")
const sha=p=>crypto.createHash("sha256").update(fs.readFileSync(p)).digest("hex")
const of=(c,t)=>c.filter(e=>e.type===t)
const names=new Map(of(after,"source_component").map(e=>[e.source_component_id,e.name]))
const moved=new Set(of(after,"pcb_component").filter(e=>moves[names.get(e.source_component_id)]).map(e=>e.pcb_component_id))
assert.equal(moved.size,8)
for(const t of ["source_component","source_trace","source_net","source_component_internal_connection","pcb_board","pcb_hole"])
assert.deepEqual(of(after,t),of(before,t),t+" must remain unchanged")
for(const t of ["pcb_component","pcb_port","pcb_smtpad","pcb_plated_hole","pcb_courtyard_rect","pcb_courtyard_outline","cad_component"])
assert.deepEqual(of(after,t).filter(e=>!moved.has(e.pcb_component_id)),of(before,t).filter(e=>!moved.has(e.pcb_component_id)),"Unreviewed placement/model change: "+t)
for(const t of new Set(before.filter(e=>e.type.startsWith("cad_")&&e.type!=="cad_component").map(e=>e.type)))
assert.deepEqual(of(after,t),of(before,t),"Assembly change: "+t)
const parent=new Map()
function 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 after){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 id of ids.slice(1))parent.set(root(id),root(ids[0]))}
const mapping=read("routing/net-map.json").roots
function extract(c){
const sources=new Map(of(c,"source_trace").map(e=>[e.source_trace_id,e])),traces=new Map(of(c,"pcb_trace").map(e=>[e.pcb_trace_id,e]))
const wires=[],vias=[],seen=new Set()
function net(e){const s=sources.get(e.source_trace_id??traces.get(e.pcb_trace_id)?.source_trace_id);assert(s);return mapping[root([...(s.connected_source_port_ids??[]),...(s.connected_source_net_ids??[])][0])]}
for(const e of c){
if(e.type==="pcb_trace"&&e.source_trace_id)for(let i=1;i<e.route.length;i++){
const a=e.route[i-1],b=e.route[i]
if(a.route_type!=="wire"||b.route_type!=="wire"||a.layer!==b.layer||Math.hypot(a.x-b.x,a.y-b.y)<1e-8)continue
const points=[[a.x,a.y],[b.x,b.y]],width=Math.max(a.width,b.width),n=net(e)
const key=JSON.stringify([n,a.layer,width,[...points].sort((a,b)=>a[0]-b[0]||a[1]-b[1])])
if(!seen.has(key)){seen.add(key);wires.push({net:n,layer:a.layer,width,points})}
}
else if(e.type==="pcb_via"){
assert.equal(e.hole_diameter,.3);assert.equal(e.outer_diameter,.45);assert.deepEqual(e.layers,["top","inner1","inner2","bottom"])
const n=net(e),key=JSON.stringify([n,e.x,e.y]);if(!seen.has(key)){seen.add(key);vias.push({net:n,x:e.x,y:e.y})}
}
}
return {wires,vias}
}
for(const [p,v] of [["routing/bulk-top-baseline-physical.json",extract(before)],["routing/bulk-top-emitted-physical.json",extract(after)],["routing/physical-copper.json",extract(after)]])
fs.writeFileSync(p,JSON.stringify(v,null,2)+"\n")
const report={circuitSha256:sha(input),baselineSha256:sha(baseline),changedParts:Object.keys(moves).sort(),allOtherPlacementsAndAssemblyUnchanged:true,sourceGraphAndBOMUnchanged:true,physicalCopperSnapshotSha256:sha("routing/physical-copper.json"),published:false}
fs.writeFileSync("reports/bulk-top-regression.json",JSON.stringify(report,null,2)+"\n")
console.log(JSON.stringify(report))