imrishabh18/rp2040-motor-controller
An RP2040-based NEMA17 stepper-motor controller with USB-C programming and PD motor-power negotiation, DRV8825 dual H-bridge drive, current/temperature telemetry, protected power filtering, status RGB LED, buzzer alarm, and optional magnetic encoder.
- Version
- 1.0.42
- License
- unset
- Stars
- 3
tests/schematic-style.test.tsx
import { descriptions } from "../schematic/ChipDescriptions";
import { expect, test } from "bun:test";
import { Circuit } from "tscircuit";
import { analyzeSchematicPlacement } from "../vendor/schematic-style-analysis";
import Board from "../index.circuit";
test("automatic schematic refinement clears all style issues on all sheets", async () => {
const circuit = new Circuit({ platform: { pcbDisabled: true } });
circuit.add(<Board routingDisabled />);
await circuit.renderUntilSettled();
const json = circuit.getCircuitJson();
const traceLabelKeys = json
.filter((e: any) => e.type === "schematic_text" && e.source_trace_id)
.map((e: any) =>
JSON.stringify([
e.source_trace_id,
e.schematic_sheet_id,
e.text,
e.position,
e.anchor,
e.rotation,
]),
);
expect(new Set(traceLabelKeys).size).toBe(traceLabelKeys.length);
const headings = json.filter(
(e: any) =>
e.type === "schematic_text" &&
!e.schematic_component_id &&
!e.schematic_symbol_id &&
!e.source_trace_id,
);
const headingKeys = headings.map(
(e: any) => `${e.schematic_sheet_id}:${e.text}`,
);
expect(new Set(headingKeys).size).toBe(headingKeys.length);
expect(
headings.filter((e: any) => e.text === "Current-sense Supply Bypass"),
).toHaveLength(1);
const alarmSheet = json
.filter((e) => e.type === "schematic_sheet")
.find((e) => e.name === "position_alarm")!;
const pwmLabel = json.find(
(e: any) =>
e.type === "schematic_net_label" &&
e.text === "BUZZER_PWM" &&
e.schematic_sheet_id === alarmSheet.schematic_sheet_id,
) as any;
const labelLeft = 2 * pwmLabel.center.x - pwmLabel.anchor_position.x;
const alarmDivider = json
.filter(
(e: any) =>
e.type === "schematic_line" &&
e.is_dashed &&
e.schematic_sheet_id === alarmSheet.schematic_sheet_id &&
e.x1 === e.x2 &&
e.x1 < pwmLabel.anchor_position.x,
)
.sort((a: any, b: any) => b.x1 - a.x1)[0] as any;
expect(alarmDivider.x1).toBeLessThan(labelLeft - 0.2);
const text = json
.filter((e) => e.type === "schematic_text")
.map((e) => e.text)
.join(" ");
for (const description of descriptions)
for (const line of description.lines) expect(text).toContain(line);
for (const heading of [
"RP2040 & Power",
"Clock",
"Controls, Status & SWD",
"QSPI Flash",
"3.3 V Supply",
"Programming USB-C",
"USB-C PD Negotiation",
"Power Filtering",
"Temperature Sensing & MCU Alert",
"RP2040-selectable USB-PD voltage",
])
expect(text).toContain(heading);
expect(text).toContain(
"GPIO4/5/6: 000 = 5 V; 111 = 9 V; 110 = 12 V; 100 = 15 V; 101 = 20 V.",
);
expect(json.filter((e) => e.type === "schematic_sheet")).toHaveLength(10);
for (const sheet of json.filter((e) => e.type === "schematic_sheet")) {
expect(sheet.sheet_width).toBe(297);
expect(sheet.sheet_height).toBe(210);
}
expect(
json.some(
(e) => e.type === "schematic_sheet" && e.name === "controller_controls",
),
).toBe(true);
expect(analyzeSchematicPlacement(json).getIssues()).toEqual([]);
expect(
json.filter(
(e) =>
e.type.endsWith("_error") ||
e.type === "schematic_element_outside_sheet_warning",
),
).toEqual([]);
// Rerouting must still connect the design, not merely clear the visible drawing.
expect(
json.filter((e) => e.type === "schematic_trace").length,
).toBeGreaterThan(100);
for (const trace of json.filter((e) => e.type === "schematic_trace")) {
for (let i = 0; i < trace.edges.length; i++) {
const edge = trace.edges[i]!;
expect(
[edge.from.x, edge.from.y, edge.to.x, edge.to.y].every(Number.isFinite),
).toBe(true);
if (i > 0) {
const previous = trace.edges[i - 1]!;
expect(edge.from.x).toBeCloseTo(previous.to.x, 6);
expect(edge.from.y).toBeCloseTo(previous.to.y, 6);
}
}
}
}, 120000);
