tscircuit/ti

ti tscircuit library

Version
1.0.191
License
unset
Stars
0

tests/MotorThermalProtection_TMP390.test.tsx

import { expect, test } from "bun:test";
import { Circuit } from "@tscircuit/core";
import {
  TMP390AQDRLRQ1,
  TMP390AQDRLRQ1_PIN_LABELS,
} from "../lib/chips/TMP390AQDRLRQ1.circuit.tsx";
import {
  MotorThermalProtection_TMP390,
  TMP390_FIGURE_8_3_DEFAULTS,
} from "../lib/subcircuits/MotorThermalProtection_TMP390.circuit.tsx";

const renderMotorThermalProtection = async () => {
  const circuit = new Circuit();
  circuit.add(<MotorThermalProtection_TMP390 name="thermalProtection" />);
  await circuit.renderUntilSettled();
  return circuit.getCircuitJson();
};

test("TMP390-Q1 pin map and Figure 8-3 thresholds match the datasheet", () => {
  expect(TMP390AQDRLRQ1_PIN_LABELS).toEqual({
    pin1: "SETA",
    pin2: "SETB",
    pin3: "GND",
    pin4: "OUTB",
    pin5: "VDD",
    pin6: "OUTA",
  });

  expect(TMP390_FIGURE_8_3_DEFAULTS).toEqual({
    hotTripCelsius: 90,
    hotResetCelsius: 80,
    coldTripCelsius: -25,
    coldResetCelsius: -15,
    hysteresisCelsius: 10,
    rSetAOhms: 78_700,
    rSetBOhms: 215_000,
    outputPullupOhms: 10_000,
    bypassCapacitanceFarads: 0.1e-6,
    sensorSupplyVolts: 3,
    outputPullupSupplyVolts: 3.3,
  });
  expect(
    TMP390_FIGURE_8_3_DEFAULTS.hotTripCelsius -
      TMP390_FIGURE_8_3_DEFAULTS.hysteresisCelsius,
  ).toBe(TMP390_FIGURE_8_3_DEFAULTS.hotResetCelsius);
  expect(
    TMP390_FIGURE_8_3_DEFAULTS.coldTripCelsius +
      TMP390_FIGURE_8_3_DEFAULTS.hysteresisCelsius,
  ).toBe(TMP390_FIGURE_8_3_DEFAULTS.coldResetCelsius);
});

test("TMP390AQDRLRQ1 uses the datasheet DRL land pattern", async () => {
  const circuit = new Circuit();
  circuit.add(<TMP390AQDRLRQ1 name="U1" pcbX={0} pcbY={0} />);
  await circuit.renderUntilSettled();

  const pads = circuit
    .getCircuitJson()
    .filter(
      (element) => element.type === "pcb_smtpad" && element.shape === "rect",
    )
    .map((pad) => ({
      pin: pad.port_hints?.[0],
      x: pad.x,
      y: pad.y,
      width: pad.width,
      height: pad.height,
    }));

  expect(pads).toEqual([
    { pin: "pin1", x: -0.74, y: 0.5, width: 0.67, height: 0.3 },
    { pin: "pin2", x: -0.74, y: 0, width: 0.67, height: 0.3 },
    { pin: "pin3", x: -0.74, y: -0.5, width: 0.67, height: 0.3 },
    { pin: "pin4", x: 0.74, y: -0.5, width: 0.67, height: 0.3 },
    { pin: "pin5", x: 0.74, y: 0, width: 0.67, height: 0.3 },
    { pin: "pin6", x: 0.74, y: 0.5, width: 0.67, height: 0.3 },
  ]);
});

test("MotorThermalProtection_TMP390 uses the datasheet component values", async () => {
  const circuitJson = await renderMotorThermalProtection();
  const sourceComponents = circuitJson.filter(
    (element) => element.type === "source_component",
  );
  const component = (name: string) => {
    const match = sourceComponents.find((element) => element.name === name);
    expect(match).toBeDefined();
    return match!;
  };

  expect(component("U1").manufacturer_part_number).toBe("TMP390AQDRLRQ1");
  expect(component("C1")).toMatchObject({ capacitance: 0.1e-6 });
  expect(component("R1")).toMatchObject({ resistance: 78_700 });
  expect(component("R2")).toMatchObject({ resistance: 215_000 });
  expect(component("R3")).toMatchObject({ resistance: 10_000 });
  expect(component("R4")).toMatchObject({ resistance: 10_000 });
});

test("MotorThermalProtection_TMP390 exposes and connects every interface net", async () => {
  const circuitJson = await renderMotorThermalProtection();
  const sourceComponents = circuitJson.filter(
    (element) => element.type === "source_component",
  );
  const sourcePorts = circuitJson.filter(
    (element) => element.type === "source_port",
  );

  const componentId = (name: string) => {
    const component = sourceComponents.find((element) => element.name === name);
    expect(component).toBeDefined();
    return component!.source_component_id;
  };
  const portKey = (componentName: string | null, portName: string) => {
    const sourceComponentId = componentName ? componentId(componentName) : null;
    const port = sourcePorts.find(
      (element) =>
        element.source_component_id === sourceComponentId &&
        element.name === portName,
    );
    expect(port).toBeDefined();
    return port!.subcircuit_connectivity_map_key;
  };
  const schematicPortCenter = (
    componentName: string | null,
    portName: string,
  ) => {
    const sourceComponentId = componentName ? componentId(componentName) : null;
    const sourcePort = sourcePorts.find(
      (element) =>
        element.source_component_id === sourceComponentId &&
        element.name === portName,
    );
    expect(sourcePort).toBeDefined();
    const schematicPort = circuitJson.find(
      (element) =>
        element.type === "schematic_port" &&
        element.source_port_id === sourcePort!.source_port_id,
    );
    expect(schematicPort).toBeDefined();
    if (!schematicPort || schematicPort.type !== "schematic_port") {
      throw new Error(`Missing schematic port ${componentName}.${portName}`);
    }
    return schematicPort.center;
  };
  const expectSameNet = (
    expected: [string | null, string],
    ...members: Array<[string | null, string]>
  ) => {
    const expectedKey = portKey(...expected);
    for (const member of members) {
      expect(portKey(...member)).toBe(expectedKey);
    }
  };

  expectSameNet([null, "VDD"], ["U1", "VDD"], ["C1", "pin1"]);
  expectSameNet([null, "VDDIO"], ["R3", "pin1"], ["R4", "pin1"]);
  expectSameNet(
    [null, "GND"],
    ["U1", "GND"],
    ["C1", "pin2"],
    ["R1", "pin2"],
    ["R2", "pin2"],
  );
  expectSameNet(["U1", "SETA"], ["R1", "pin1"]);
  expectSameNet(["U1", "SETB"], ["R2", "pin1"]);
  expectSameNet([null, "OUTA"], ["U1", "OUTA"], ["R3", "pin2"]);
  expectSameNet([null, "OUTB"], ["U1", "OUTB"], ["R4", "pin2"]);

  const groundY = schematicPortCenter(null, "GND").y;
  expect(schematicPortCenter("R1", "pin2").y).toBeCloseTo(groundY);
  expect(schematicPortCenter("R2", "pin2").y).toBeCloseTo(groundY);
  expect(schematicPortCenter("U1", "OUTA").y).toBeCloseTo(
    schematicPortCenter(null, "OUTA").y,
  );
  expect(schematicPortCenter("U1", "OUTB").y).toBeCloseTo(
    schematicPortCenter(null, "OUTB").y,
  );

  expect(
    circuitJson.filter(
      (element) =>
        element.type.startsWith("schematic_") &&
        element.type.endsWith("_error"),
    ),
  ).toEqual([]);
});