mohan-bee/flight-controller-v2

A 64 mm STM32F405 flight-controller PCB with ICM-42688 IMU, SPI flash, USB-C/ESD, battery buck and 3.3 V regulation, four motor outputs, service I/O, and PETG standoff mounting hardware.

Version
0.1.0
License
ISC
Stars
0

validate.mjs

import { readFileSync } from "node:fs";
import assert from "node:assert/strict";

const file = process.argv[2] ?? "dist/index/circuit.json";
const circuit = JSON.parse(readFileSync(file, "utf8"));
const components = circuit.filter((item) => item.type === "source_component");
const nets = new Map(
  circuit
    .filter((item) => item.type === "source_net")
    .map((item) => [item.source_net_id, item.name]),
);
const ports = circuit.filter((item) => item.type === "source_port");
function portNet(componentName, pinNumber) {
  const component = components.find((item) => item.name === componentName);
  assert(component, `Missing component ${componentName}`);
  const port = ports.find(
    (item) =>
      item.source_component_id === component.source_component_id &&
      item.pin_number === pinNumber,
  );
  assert(port, `Missing ${componentName} pin ${pinNumber}`);
  const trace = circuit.find(
    (item) =>
      item.type === "source_trace" &&
      item.connected_source_port_ids.includes(port.source_port_id),
  );
  assert(trace, `Unconnected ${componentName} pin ${pinNumber}`);
  return nets.get(trace.connected_source_net_ids[0]);
}
for (const pin of [1, 19, 32, 48, 64]) assert.equal(portNet("U1", pin), "V3V3");
for (const pin of [12, 18, 63]) assert.equal(portNet("U1", pin), "GND");
assert.equal(portNet("U1", 13), "VDDA");
assert.equal(portNet("U1", 31), "VCAP1");
assert.equal(portNet("U1", 47), "VCAP2");
for (const [pin, net] of [
  [20, "GYRO_CS"],
  [21, "GYRO_SCK"],
  [22, "GYRO_MISO"],
  [23, "GYRO_MOSI"],
  [24, "GYRO_INT"],
  [29, "RX_TX"],
  [30, "RX_RX"],
  [44, "USB_DM_MCU"],
  [45, "USB_DP_MCU"],
])
  assert.equal(portNet("U1", pin), net);
for (let motor = 1; motor <= 4; motor++)
  assert.equal(portNet("U1", 36 + motor), `M${motor}`);
for (const pin of [5, 8]) assert.equal(portNet("U2", pin), "GYRO_3V3");
for (const pin of [2, 3, 6, 7, 9, 10, 11])
  assert.equal(portNet("U2", pin), "GND");
for (const [pin, net] of [
  [1, "FLASH_CS"],
  [2, "FLASH_MISO"],
  [3, "V3V3"],
  [4, "GND"],
  [5, "FLASH_MOSI"],
  [6, "FLASH_SCK"],
  [7, "V3V3"],
  [8, "V3V3"],
])
  assert.equal(portNet("U6", pin), net);
const board = circuit.find((item) => item.type === "pcb_board");
const usb = components.find((item) => item.name === "J_USB");
const ground = circuit.find((item) => item.type === "source_net" && item.name === "GND");
const shieldPorts = ports.filter(
  (port) => port.source_component_id === usb.source_component_id &&
    port.port_hints.some((hint) => hint === "SHELL1" || hint === "SHELL2"),
);
assert.equal(shieldPorts.length, 4, "USB connector must expose all four shield pads");
for (const port of shieldPorts)
  assert.equal(port.subcircuit_connectivity_map_key, ground.subcircuit_connectivity_map_key,
    `USB shield pad ${port.name} must connect to ground`);
assert.equal(board.width, 64);
assert.equal(board.height, 64);
assert.equal(board.num_layers, 4);
const errors = circuit.filter((item) => item.type.endsWith("_error"));
assert.equal(errors.length, 0, errors.map((item) => item.message).join("\n"));
for (const component of circuit.filter((item) => item.type === "pcb_component"))
  assert.equal(component.layer, "top", "All components must be on top");
const traces = circuit.filter((item) => item.type === "pcb_trace");
for (const trace of traces) {
  for (const point of trace.route) {
    assert(
      Number.isFinite(point.x) && Number.isFinite(point.y),
      "Non-finite route point",
    );
    if (point.route_type === "wire") {
      assert(
        Math.abs(point.x) + point.width / 2 <= 32 &&
          Math.abs(point.y) + point.width / 2 <= 32,
        "Copper extends beyond the rectangular board bounds",
      );
    }
  }
}
console.log(
  `${components.length} components; MCU power, IMU, flash, USB, CRSF and four motor nets verified; ${traces.length} PCB traces; no circuit-json errors.`,
);