abse/boostxl-ads7841-q1

The ADS7841ESQDBQRQ1 is a 16-pin touchscreen controller IC with voltage, ground, communication, and mode control pins designed for interfacing with touch sensors.

Version
1.0.6
License
unset
Stars
0

scripts/verify-release.mjs

import { existsSync, readFileSync } from "node:fs"
import { dirname, join } from "node:path"
import { fileURLToPath } from "node:url"

const root = join(dirname(fileURLToPath(import.meta.url)), "..")
const sourcePath = join(root, "index.circuit.tsx")
const circuitPath = join(root, "dist/index/circuit.json")
const guidePath = join(root, "reference/ti/BOOSTXL-ADS7841-Q1-user-guide-SNAU229.pdf")

const failures = []
const requireCheck = (condition, message) => {
  if (!condition) failures.push(message)
}

requireCheck(existsSync(circuitPath), "dist/index/circuit.json is missing; run bun run build")
requireCheck(existsSync(guidePath), "official TI SNAU229 reference PDF is missing")

if (!existsSync(circuitPath)) {
  console.error(failures.join("\n"))
  process.exit(1)
}

const source = readFileSync(sourcePath, "utf8")
const circuit = JSON.parse(readFileSync(circuitPath, "utf8"))
const elements = (type) => circuit.filter((element) => element.type === type)
const components = elements("source_component")
const componentByName = new Map(components.map((component) => [component.name, component]))
const pcbBySourceId = new Map(elements("pcb_component").map((component) => [component.source_component_id, component]))

const expectedRefs = [
  ...Array.from({ length: 30 }, (_, index) => `C${index + 1}`),
  ...Array.from({ length: 36 }, (_, index) => `R${index + 1}`),
  ...Array.from({ length: 9 }, (_, index) => `U${index + 1}`),
  ...Array.from({ length: 13 }, (_, index) => `TP${index + 1}`),
  "J1J3", "J2J4", "J5", "J6", "J7", "J8", "J9", "J10", "J11", "J12", "J13", "J14", "J15",
]

for (const ref of expectedRefs) requireCheck(componentByName.has(ref), `missing reference ${ref}`)
const names = components.map((component) => component.name)
requireCheck(new Set(names).size === names.length, "duplicate source-component reference designator")

const board = elements("pcb_board")[0]
requireCheck(board?.num_layers === 4, "board must have four copper layers")
requireCheck(board?.width === 63.5 && board?.height === 44.45, "board must retain the TI 63.5 mm × 44.45 mm outline")
requireCheck(board?.min_via_hole_diameter === 0.3, "minimum via hole must be 0.3 mm")
requireCheck(board?.min_via_pad_diameter === 0.45, "minimum via pad must be 0.45 mm")
requireCheck(elements("pcb_copper_pour").some((pour) => pour.layer === "bottom"), "bottom copper pour is missing")

const holes = elements("pcb_hole")
requireCheck(holes.length === 3, "TI board must have exactly three mechanical mounting holes")
const expectedHoleCenters = [[-26.1, 19.5], [28.9, 19.5], [-26.1, -19.5]]
for (const [x, y] of expectedHoleCenters) {
  requireCheck(holes.some((hole) => hole.x === x && hole.y === y && hole.hole_diameter === 3.2), `missing TI mounting hole at (${x}, ${y})`)
}

const expectedSheets = [
  "ADS7841 Power Supply",
  "ADS7841 LaunchPad and EEPROM",
  "ADS7841 SPI Level Translation",
  "ADS7841 Analog Input Buffers",
  "ADS7841 ADC and Voltage Reference",
]
const sheetNames = elements("schematic_sheet").map((sheet) => sheet.name)
requireCheck(JSON.stringify(sheetNames) === JSON.stringify(expectedSheets), "schematic must retain the five reviewed functional sheets")

const drcErrors = circuit.filter((element) => element.type.endsWith("_error"))
requireCheck(drcErrors.length === 0, `generated circuit contains ${drcErrors.length} DRC/error objects`)
requireCheck(elements("schematic_element_outside_sheet_warning").length === 0, "schematic contains elements outside a drawing sheet")
requireCheck(elements("pcb_trace").length >= 200, "routed board unexpectedly contains fewer than 200 PCB traces")
requireCheck(elements("pcb_via").length > 0, "routed board unexpectedly contains no vias")

requireCheck(!source.includes("<netlabel"), "explicit <netlabel> is forbidden")
requireCheck(!source.includes("<schematicrect"), "overlapping schematic region boxes must not return")
requireCheck(source.includes('minViaHoleDiameter="0.3mm"'), "source via-hole rule is missing")
requireCheck(source.includes('minViaPadDiameter="0.45mm"'), "source via-pad rule is missing")

const dnpRefs = ["C8", "C12", "C18", "C22", "C28", "J6", "J7", "J9", "J11", "J14", "R18", "R27", "R29", "R34"]
for (const ref of dnpRefs) {
  const component = componentByName.get(ref)
  const pcb = component && pcbBySourceId.get(component.source_component_id)
  requireCheck(pcb?.do_not_place === true, `${ref} must remain DNP`)
}

for (const component of components) {
  if (/^[CR]/.test(component.name)) {
    requireCheck(component.supplier_part_numbers?.jlcpcb?.length > 0, `${component.name} lacks JLCPCB/LCSC sourcing`)
  }
  if (/^(U|J)/.test(component.name)) {
    requireCheck(component.supplier_part_numbers?.jlcpcb?.length > 0, `${component.name} lacks imported JLCPCB/LCSC sourcing`)
  }
}

requireCheck(componentByName.get("U1")?.manufacturer_part_number === "REG71055IDDCRQ1", "U1 must use TI BOM REG71055IDDCRQ1")
requireCheck(componentByName.get("U1")?.supplier_part_numbers?.jlcpcb?.includes("C2071120"), "U1 JLCPCB source C2071120 is missing")
requireCheck(componentByName.get("U2")?.manufacturer_part_number === "TPS79901QDRVRQ1", "U2 must use TI BOM TPS79901QDRVRQ1")
requireCheck(componentByName.get("U2")?.supplier_part_numbers?.jlcpcb?.includes("C398922"), "U2 JLCPCB source C398922 is missing")
requireCheck(componentByName.get("U4")?.manufacturer_part_number === "BR24G32FVT-3AGE2", "U4 must use TI BOM BR24G32FVT-3AGE2")
requireCheck(componentByName.get("J10")?.manufacturer_part_number === "TSW-103-07-G-D", "J10 must use TI BOM TSW-103-07-G-D")
requireCheck(componentByName.get("J15")?.manufacturer_part_number === "PEC02DAAN", "J15 must use TI BOM PEC02DAAN")
for (const ref of ["J7", "J11"]) requireCheck(componentByName.get(ref)?.manufacturer_part_number === "5-1814832-1", `${ref} must use TI BOM SMA 5-1814832-1`)
requireCheck(source.includes("connections={{ pin1: N.VDD, pin2: N.LDO_FB, pin3: N.GND, pin4: N.V55, pin5: N.LDO_NR, pin6: N.V55, pin7: N.GND }}"), "U2 adjustable WSON pin mapping changed")
requireCheck(source.includes('connections={{ pin1: N.VDD, pin2: N.VREF, pin3: N.VREF45_RAW }}'), "J13 voltage-reference selector mapping changed")
requireCheck(source.includes('connections={{ pin1: N.VREF45_RAW, pin2: N.VREF45_FILTERED }}'), "R31 reference-filter mapping changed")
requireCheck(source.includes('connections={{ pin1: N.VREF45_FILTERED, pin2: N.GND }}'), "C30 reference-filter mapping changed")

const expectedResistance = { R2: 10, R4: 100000, R11: 31600, R13: 1000, R20: 0, R23: 49.9, R30: 100, R35: 68100, R36: 100000 }
for (const [ref, resistance] of Object.entries(expectedResistance)) {
  requireCheck(componentByName.get(ref)?.resistance === resistance, `${ref} resistance does not match TI BOM`)
}

if (failures.length) {
  console.error(`Release audit failed (${failures.length}):`)
  for (const failure of failures) console.error(`- ${failure}`)
  process.exit(1)
}

console.log("Electrical release audit passed with all populated non-passives sourced through JLCPCB/LCSC")