seveibar/am3352-dev-board-4layer-dogbone
Defines PCB footprints and pin mappings for a TI AM3352ZCZ100 processor, JST GH connectors, and assembly-part lookup helpers for capacitors, resistors, and headers.
- Version
- 0.1.5
- License
- unset
- Stars
- 0
scripts/verify.mjs
import fs from 'node:fs'
import assert from 'node:assert/strict'
import { getFullConnectivityMapFromCircuitJson } from 'circuit-json-to-connectivity-map'
import { createHash } from 'node:crypto'
const cj=JSON.parse(fs.readFileSync('dist/index/circuit.json','utf8'))
const src=cj.filter(e=>e.type==='source_component')
const ports=cj.filter(e=>e.type==='source_port')
const traces=cj.filter(e=>e.type==='source_trace')
const pcb=cj.filter(e=>e.type==='pcb_component')
const u1=src.find(e=>e.name==='U1')
const u3=src.find(e=>e.name==='U3')
assert.equal(ports.filter(e=>e.source_component_id===u1.source_component_id).length,324)
assert.equal(ports.filter(e=>e.source_component_id===u3.source_component_id).length,96)
assert.match(fs.readFileSync('index.circuit.tsx','utf8'),/routeRemaining=\{false\}/)
for(const n of ['DDR_A1','DDR_A12']) {
const net=cj.find(e=>e.type==='source_net' && e.name===n)
assert(net, n)
const connected=traces.filter(t=>t.connected_source_net_ids?.includes(net.source_net_id)).flatMap(t=>t.connected_source_port_ids)
assert(connected.some(p=>ports.find(e=>e.source_port_id===p)?.source_component_id===u1.source_component_id),n+' CPU')
assert(connected.some(p=>ports.find(e=>e.source_port_id===p)?.source_component_id===u3.source_component_id),n+' RAM')
}
const routed=cj.filter(e=>e.type==='pcb_trace')
const savedCopper=JSON.parse(fs.readFileSync('design/routed-copper.json','utf8'))
const compiledById=new Map(routed.map(t=>[t.pcb_trace_id,t]))
const routeShape=route=> {
const points=route.map(p=>Object.fromEntries(['route_type','x','y','width','layer','from_layer','to_layer','via_diameter','via_hole_diameter'].filter(k=>p[k]!==undefined).map(k=>[k,p[k]])))
// Endpoint inference may reverse a route without changing its copper.
return [JSON.stringify(points),JSON.stringify([...points].reverse())].sort()[0]
}
for(const [net,routes] of Object.entries(savedCopper.nets)) for(const [i,route] of routes.entries()) {
const id=`fr_${net}_${i}`
assert(compiledById.has(id),`Build is stale: missing ${id}`)
assert.deepEqual(routeShape(compiledById.get(id).route),routeShape(route),`Build is stale: route ${id} changed`)
}
assert.equal(routed.length,Object.values(savedCopper.nets).reduce((n,rs)=>n+rs.length,0),'Build contains stale copper records')
const issues=cj.filter(e=>/error$/.test(e.type))
const board=cj.find(e=>e.type==='pcb_board')
const declared=JSON.parse(fs.readFileSync('design/net-names.json','utf8'))
const actual=cj.filter(e=>e.type==='source_net').map(e=>e.name)
const connectivity=getFullConnectivityMapFromCircuitJson(cj)
assert.equal(new Set(cj.filter(e=>e.type==='source_net').map(e=>connectivity.getNetConnectedToId(e.source_net_id))).size,actual.length,'Named nets must not be aliased by pin labels or PCB endpoint annotations')
assert.deepEqual(new Set(declared),new Set(actual),'Every named net must have an explicit routing phase')
const sha=createHash('sha256').update(fs.readFileSync('dist/index/circuit.json')).digest('hex')
const audit=fs.existsSync('design/copper-audit.json')?JSON.parse(fs.readFileSync('design/copper-audit.json','utf8')):null
const auditFresh=audit?.circuitSha256===sha
const physicalComplete=auditFresh&&Object.keys(audit.incompleteNets).length===0&&audit.clearanceViolations.length===0
const summary={boardWidth:board.width,boardHeight:board.height,fullyRouted:issues.length===0&&routed.length>1&&physicalComplete,components:src.length,cpuPins:324,ramPins:96,sourceTraces:traces.length,pcbTraces:routed.length,physicalAuditCurrent:auditFresh,diagnostics:cj.filter(e=>/error$/.test(e.type)).reduce((a,e)=>(a[e.type]=(a[e.type]??0)+1,a),{})}
fs.writeFileSync('design/validation.json',JSON.stringify(summary,null,2)+'\n')
console.log(JSON.stringify(summary,null,2))
if (!process.argv.includes('--report')) {
assert.equal(issues.length,0,`Full routing validation failed: ${issues.length} DRC issues remain`)
assert(routed.length>1,'Copper routing is missing')
assert(physicalComplete,'The current circuit must pass the independent geometric copper audit')
}