krishnax12/watchy-eink-smartwatch

Unfinished prototype (not production-ready): 4 native DRC errors, 2 display-flex intersections, and missing antenna radiator copper remain

Version
1.2.7
License
MIT
Stars
1

scripts/check-reference-connectivity.mjs

import fs from "node:fs/promises";
import { XMLParser } from "fast-xml-parser";

const netlistPath = process.argv[2] ?? "reports/official-v3-netlist.xml";
const circuitPath = process.argv[3] ?? "dist/index/circuit.json";
const reference = new XMLParser({
	ignoreAttributes: false,
	attributeNamePrefix: "",
}).parse(await fs.readFile(netlistPath, "utf8"));
const circuit = JSON.parse(await fs.readFile(circuitPath, "utf8"));
const referenceComponents = new Set(
	reference.export.components.comp.map((component) => component.ref),
);
const boardComponents = new Map(
	circuit
		.filter((element) => element.type === "source_component")
		.map((component) => [component.source_component_id, component.name]),
);
const referenceNets = reference.export.nets.net
	.filter((net) => !net.name.startsWith("unconnected-"))
	.map((net) => ({
		name: net.name,
		pins: (Array.isArray(net.node) ? net.node : [net.node])
			.filter((node) => !node.ref.startsWith("#"))
			.map((node) => `${node.ref}.${node.pin}`)
			.sort(),
	}))
	.filter((net) => net.pins.length > 1);
const referencePins = new Set(referenceNets.flatMap((net) => net.pins));
const boardNets = new Map();
const additionalConnectedPins = [];
const connectedPortIds = new Set(
	circuit
		.filter((element) => element.type === "source_trace")
		.flatMap((trace) => trace.connected_source_port_ids),
);
for (const port of circuit.filter(
	(element) => element.type === "source_port",
)) {
	const componentName = boardComponents.get(port.source_component_id);
	const pin = `${componentName}.${port.pin_number}`;
	if (!referencePins.has(pin)) {
		if (
			!referenceComponents.has(componentName) &&
			connectedPortIds.has(port.source_port_id)
		)
			additionalConnectedPins.push(pin);
		continue;
	}
	const netKey = port.subcircuit_connectivity_map_key;
	if (!netKey) throw new Error(`Missing connectivity for ${pin}`);
	boardNets.set(netKey, [...(boardNets.get(netKey) ?? []), pin]);
}
const boardNetSignatures = new Set(
	[...boardNets.values()].map((pins) => pins.sort().join("|")),
);
const mismatches = referenceNets.filter(
	(net) => !boardNetSignatures.has(net.pins.join("|")),
);
const missingComponents = [...referenceComponents].filter(
	(name) =>
		!name.startsWith("#") && ![...boardComponents.values()].includes(name),
);
const report = {
	netlistPath,
	circuitPath,
	scope:
		"Pin-to-pin reference connectivity, not PCB routing or functional qualification. Additional test points are reported separately, not silently included in the official reference.",
	matchedReferenceNets: referenceNets.length - mismatches.length,
	referenceConnectedPins: referencePins.size,
	additionalComponents: [...boardComponents.values()].filter(
		(name) => !referenceComponents.has(name),
	),
	additionalConnectedPins,
	missingComponents,
	mismatches,
};
await fs.writeFile(
	"reports/reference-connectivity.json",
	JSON.stringify(report, null, 2),
);
console.log(report);
if (mismatches.length || missingComponents.length) process.exitCode = 1;