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);