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/review-bom-values.mjs
import fs from "node:fs"
import crypto from "node:crypto"
const path = "dist/index/circuit.json"
const bytes = fs.readFileSync(path)
const circuit = JSON.parse(bytes)
const catalog = JSON.parse(fs.readFileSync("reports/jlcpcb-stock-audit.json", "utf8"))
const baseline = JSON.parse(fs.readFileSync("reports/published-comparison/latest-dist_index_circuit.json", "utf8"))
const component = (items, name) => items.find(e => e.type === "source_component" && e.name === name)
const codeValue = code => Number(code.slice(0, -1)) * 10 ** Number(code.at(-1))
function nominalValue(part) {
const mpn = part.manufacturerPartNumber
const resistor = mpn.match(/^(?:0402WGF|0603WAF)(\d{4})/)
if (resistor) return { kind: "resistance", value: codeValue(resistor[1]), method: "four-digit manufacturer value code" }
if (mpn === "0402WGF100JTCE") return { kind: "resistance", value: 10, method: "three-digit manufacturer value code" }
if (mpn === "HoLRT1206-1W-300mR-1%") return { kind: "resistance", value: .3, method: "explicit manufacturer milliohm value" }
if (mpn === "RC0201JR-070RL") return { kind: "resistance", value: 0, method: "explicit zero-ohm link" }
if (mpn === "CR0402F51R0Q10Z") return { kind: "resistance", value: 51, method: "explicit manufacturer R notation" }
if (mpn === "FRC0603F1002TS") return { kind: "resistance", value: 10000, method: "four-digit manufacturer value code" }
if (mpn === "RC0402FR-0749R9L") return { kind: "resistance", value: 49.9, method: "verified JLC catalog value" }
if (mpn === "RC0402FR-079K1L") return { kind: "resistance", value: 9100, method: "verified JLC catalog value" }
const cap = mpn.match(/^CL\d{2}[A-Z](\d{3})/) ?? mpn.match(/^TCC\d{4}X7R(\d{3})/) ??
mpn.match(/^CC\d{4}.*?(\d{3})$/)
if (cap) return { kind: "capacitance", value: codeValue(cap[1]) * 1e-12, method: "manufacturer capacitance code in pF" }
if (mpn.startsWith("GRM") && /^\d{3}$/.test(mpn.slice(10, 13)))
return { kind: "capacitance", value: codeValue(mpn.slice(10, 13)) * 1e-12, method: "Murata capacitance code in pF" }
if (mpn === "0402B223K500NT") return { kind: "capacitance", value: 22e-9, method: "manufacturer capacitance code in pF" }
if (mpn === "EEFCX1E220R") return { kind: "capacitance", value: 22e-6, method: "Panasonic product specification" }
if (mpn === "CA55-D050M226TE100") return { kind: "capacitance", value: 22e-6, method: "Xiangyee product specification" }
return null
}
const checked = [], mismatches = [], unknown = []
for (const part of catalog.parts) {
for (const name of part.designators) {
const source = component(circuit, name)
if (!["simple_resistor", "simple_capacitor"].includes(source?.ftype)) continue
const nominal = nominalValue(part)
if (!nominal) { unknown.push({ name, code: part.code, mpn: part.manufacturerPartNumber }); continue }
const intended = source[nominal.kind]
const same = Math.abs(intended - nominal.value) <= Math.max(1e-15, Math.abs(intended) * 1e-8)
const old = component(baseline, name)
const entry = { name, code: part.code, mpn: part.manufacturerPartNumber, catalogPackage: part.package,
kind: nominal.kind, intended, selectedNominal: nominal.value, method: nominal.method,
url: part.url, inheritedFromV046: old?.[nominal.kind] === intended &&
old?.supplier_part_numbers?.jlcpcb?.[0] === part.code }
checked.push(entry)
if (!same) mismatches.push(entry)
}
}
const report = { checkedAt: new Date().toISOString(),
circuitSha256: crypto.createHash("sha256").update(bytes).digest("hex"),
scope: "Nominal R/C values decoded from exact manufacturer numbers in today's JLC catalog audit; not a complete package, voltage, power, tolerance or active-part signoff.",
checkedPassiveComponents: checked.length, unknown, mismatchCount: mismatches.length, mismatches,
rxCapacitorPackages: catalog.parts.filter(p => p.designators.some(n => ["C_ETH_RXN_AC", "C_ETH_RXP_AC"].includes(n)))
.map(p => ({code:p.code, designed:"0402", selected:p.package, match:p.package==="0402"})),
stockIsNotElectricalSignoff: true }
fs.writeFileSync("reports/bom-value-review.json", JSON.stringify(report, null, 2) + "\n")
console.log(JSON.stringify(report, null, 2))