AnasSarkiz/magnetic-shutter-remote-r8

A USB‑C rechargeable battery-powered ESP32‑C3 wireless controller with Li‑ion charging, protected 3.3‑V buck‑boost regulation, thermal/safety monitoring, status LEDs, buttons, programming UART, crystal clock, and 2.4‑GHz antenna matching network.

Version
0.4.0-prototype
License
unset
Stars
0

src/r9-control-trace-paths.ts

import { upperV3BranchRoute } from "./r9-core-trace-paths";
import { z } from "zod";
import { applyToPoint, translate } from "transformation-matrix";
import type { FanoutTracePath } from "@tscircuit/core";
import {
	r8MosfetPaths,
	r8UsbDisablePaths,
	r8PowerPaths,
	r8TsBiasPaths,
	sensorCapEscapePaths,
	sensorEscapePaths,
	r8ChargeStatPaths,
	r8BatteryCapEscapePaths,
} from "./trace-paths";

// Same verified gate/drain escapes. The source ground now drops locally before
// the RF feed corridor, rather than crossing the antenna transmission line.
export const r9MosfetTracePaths: FanoutTracePath[] = [
	...r8MosfetPaths.filter((path) => path.connection !== "Q2.pin2"),
	{
		connection: "Q2.pin2",
		route: [
			{
				route_type: "wire",
				x: 8.999998,
				y: 6.94996,
				width: 0.15,
				layer: "top",
			},
			{ route_type: "wire", x: 9.95, y: 7.8, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: 9.95,
				y: 7.8,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];

// Move ordinary via ends off wide capacitor/resistor lands; preserve all
// other manufacturer-reviewed R8 power/sensor escapes in the R9 candidate.
// VINA already touches C13 mid-path. Its saved fanout must expose the same
// input-reservoir exit, so the root router does not target that occupied pad.
const regulatorBiasSupplyPath = r8PowerPaths.find(
	(path) => path.connection === "U3.pin8",
);
if (!regulatorBiasSupplyPath)
	throw new Error("Missing retained regulator VINA path");
const regulatorBiasSupplyBranch = regulatorBiasSupplyPath.route.slice(2);

// Reserve the high-current battery trunk before signal routing. Board XY mm.
function batteryInputTrunkRoute(): FanoutTracePath["route"] {
	return [
		{ route_type: "wire", x: -10.999998, y: 0, width: 0.508, layer: "top" },
		{ route_type: "wire", x: -10.999998, y: -1.5, width: 0.508, layer: "top" },
		{
			route_type: "via",
			x: -10.999998,
			y: -1.5,
			from_layer: "top",
			to_layer: "bottom",
			via_diameter: 0.45,
			via_hole_diameter: 0.3,
		},
		{
			route_type: "wire",
			x: -10.999998,
			y: -1.5,
			width: 0.508,
			layer: "bottom",
		},
		{ route_type: "wire", x: -12, y: -2.5, width: 0.508, layer: "bottom" },
		{ route_type: "wire", x: -14.0, y: -2.5, width: 0.508, layer: "bottom" },
		{ route_type: "wire", x: -14.0, y: 11.2, width: 0.508, layer: "bottom" },
		{
			route_type: "wire",
			x: -1.9998075,
			y: 11.2,
			width: 0.508,
			layer: "bottom",
		},
		{
			route_type: "wire",
			x: -0.9998075,
			y: 10.2,
			width: 0.508,
			layer: "bottom",
		},
	];
}

// Full 0.508mm regulated output feed, above the reservoir then around the
// switching input trunk. World XY mm; both copper layers only.
function regulatorOutputTrunkRoute(): FanoutTracePath["route"] {
	return [
		{ route_type: "wire", x: -10.999998, y: 8.5, width: 0.508, layer: "top" },
		{ route_type: "wire", x: -10.999998, y: 9.9, width: 0.508, layer: "top" },
		{
			route_type: "via",
			x: -10.999998,
			y: 9.9,
			from_layer: "top",
			to_layer: "bottom",
			via_diameter: 0.45,
			via_hole_diameter: 0.3,
		},
		{
			route_type: "wire",
			x: -10.999998,
			y: 9.9,
			width: 0.508,
			layer: "bottom",
		},
		{ route_type: "wire", x: -8.7, y: 9.9, width: 0.508, layer: "bottom" },
		{ route_type: "wire", x: -8.7, y: -4.5, width: 0.508, layer: "bottom" },
		{ route_type: "wire", x: -0.6, y: -4.5, width: 0.508, layer: "bottom" },
		...upperV3BranchRoute().slice(5),
	];
}
function regulatorOutputBypassRoute(): FanoutTracePath["route"] {
	return [
		{ route_type: "wire", x: -10.999998, y: 6, width: 0.6, layer: "top" },
		...regulatorOutputTrunkRoute(),
	];
}
const regulatorPowerLoopPaths: FanoutTracePath[] = [
	{ connection: "C12.pin1", route: regulatorOutputTrunkRoute() },
	{ connection: "C4.pin1", route: regulatorOutputBypassRoute() },

	...r8PowerPaths.filter(
		(path) => path.connection !== "C3.pin2" && path.connection !== "U3.pin6",
	),
	{ connection: "C13.pin1", route: regulatorBiasSupplyBranch },
	{
		connection: "C3.pin2",
		route: [
			{ route_type: "wire", x: -9.000002, y: 0, width: 0.15, layer: "top" },
			{ route_type: "wire", x: -7.6, y: 0, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: -7.6,
				y: 0,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
	{
		connection: "U3.pin6",
		route: [
			{
				route_type: "wire",
				x: -8.842522,
				y: 2.000002,
				width: 0.15,
				layer: "top",
			},
			{ route_type: "wire", x: -7.65, y: 1.1, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: -7.65,
				y: 1.1,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];
export const r9PowerTracePaths: FanoutTracePath[] = regulatorPowerLoopPaths.map(
	(path): FanoutTracePath => {
		if (path.connection === "U3.pin1")
			return {
				...path,
				route: [...path.route, ...regulatorOutputTrunkRoute().slice(1)],
			};
		if (path.connection === "U3.pin10")
			return {
				...path,
				route: [...path.route, ...regulatorOutputBypassRoute().slice(1)],
			};
		if (path.connection === "C3.pin1")
			return { ...path, route: batteryInputTrunkRoute() };
		if (
			["U3.pin5", "U3.pin8", "C11.pin1", "C13.pin1"].includes(path.connection)
		) {
			return {
				...path,
				route: [...path.route.slice(0, -1), ...batteryInputTrunkRoute()],
			};
		}
		return path;
	},
);

// Explicit physical region uses the measured original component bounds. Saved
// completed power branches may leave it; all component world poses are retained.
export const r9PowerLoopAnchor = { x: -11.12750065, y: 3.75 };
export const r9PowerLoopFanoutPaths: FanoutTracePath[] = r9PowerTracePaths.map(
	(path) => ({
		...path,
		route: path.route.map((point) => ({
			...point,
			...applyToPoint(translate(-r9PowerLoopAnchor.x, -r9PowerLoopAnchor.y), {
				x: z.number().parse(point.x),
				y: z.number().parse(point.y),
			}),
		})),
	}),
);

export const r9TsBiasTracePaths: FanoutTracePath[] = [
	...r8TsBiasPaths.filter((path) => path.connection !== "R9.pin1"),
	{
		connection: "R9.pin1",
		route: [
			{ route_type: "wire", x: 0.246636, y: 17, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 0.05, y: 18.03, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: 0.05,
				y: 18.03,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];
export const r9SensorCapTracePaths: FanoutTracePath[] = [
	...sensorCapEscapePaths.filter((path) => path.connection !== "C7.pin1"),
	{
		connection: "C7.pin1",
		route: [
			{ route_type: "wire", x: 0.799976, y: 8.5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 0.5, y: 9.55, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: 0.5,
				y: 9.55,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];

// The qualified charge-status corridor remains clear of R9 RF/clock reference
// regions. Raise its ordinary via0.05mm to retain the declared0.35mm pad gap.
export const r9ChargeStatTracePaths: FanoutTracePath[] = r8ChargeStatPaths.map(
	(path) => ({
		...path,
		route: path.route.map((point) =>
			point.x === 7.249938 && point.y === 24 ? { ...point, y: 24.05 } : point,
		),
	}),
);

// Complete low-current charge LED connection, saved in the early phase so
// all following routers preserve its copper. Board XY mm,+Z top.
export const r9ChargeLedTracePaths: FanoutTracePath[] = [
	{
		connection: "R4.pin2",
		route: [
			{ route_type: "wire", x: 8.753364, y: 16.5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 8.753364, y: 15.35, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: 8.753364,
				y: 15.35,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
			{
				route_type: "wire",
				x: 8.753364,
				y: 15.35,
				width: 0.15,
				layer: "bottom",
			},
			{
				route_type: "wire",
				x: 8.753364,
				y: 23.65,
				width: 0.15,
				layer: "bottom",
			},
			{
				route_type: "via",
				x: 8.753364,
				y: 23.65,
				from_layer: "bottom",
				to_layer: "top",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
			{ route_type: "wire", x: 8.753364, y: 23.65, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 8.750062, y: 26, width: 0.15, layer: "top" },
		],
	},
];
// R4's1k LED feed carries <4.2mA even with a shorted LED. Share the already
// authored bypass branch and expose the same battery exit as C2.
export const r9ChargeVbatTracePaths: FanoutTracePath[] = [
	{
		connection: "R4.pin1",
		route: [
			{ route_type: "wire", x: 7.246636, y: 16.5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 6.246636, y: 15.5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 3, y: 15.5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 2.8, y: 15.3, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 2.8, y: 11.5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 3.799976, y: 11.5, width: 0.15, layer: "top" },
			...r8BatteryCapEscapePaths[0].route
				.slice(1)
				.map((point) => ({ ...point })),
		],
	},
];

export const r9StatusLedTracePaths: FanoutTracePath[] = [
	{
		connection: "R7.pin2",
		route: [
			{ route_type: "wire", x: -15.753364, y: -5, width: 0.15, layer: "top" },
			{ route_type: "wire", x: -18.249938, y: -5, width: 0.15, layer: "top" },
		],
	},
];

// Complete boot-strap connections; retained10k pull-ups and GPIO boot levels.
export const r9StrapTracePaths: FanoutTracePath[] = [
	{
		connection: "U1.pin14",
		route: [
			{
				route_type: "wire",
				x: -0.750062,
				y: -8.022484,
				width: 0.15,
				layer: "top",
			},
			{
				route_type: "wire",
				x: -0.750062,
				y: -7.449938,
				width: 0.15,
				layer: "top",
			},
			{ route_type: "wire", x: -1.2, y: -7, width: 0.15, layer: "top" },
			{ route_type: "wire", x: -1.2, y: -5.546636, width: 0.15, layer: "top" },
			{ route_type: "wire", x: -2, y: -4.746636, width: 0.15, layer: "top" },
		],
	},
	{
		connection: "U1.pin6",
		route: [
			{
				route_type: "wire",
				x: 2.477516,
				y: -9.749938,
				width: 0.15,
				layer: "top",
			},
			{ route_type: "wire", x: 4.1, y: -9.78, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: 4.1,
				y: -9.78,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
			{ route_type: "wire", x: 4.1, y: -9.78, width: 0.15, layer: "bottom" },
			{ route_type: "wire", x: 4.8, y: -9.08, width: 0.15, layer: "bottom" },
			{ route_type: "wire", x: 4.8, y: -5, width: 0.15, layer: "bottom" },
			{ route_type: "wire", x: 5.4, y: -4.4, width: 0.15, layer: "bottom" },
			{ route_type: "wire", x: 5.4, y: 0.4, width: 0.15, layer: "bottom" },
			{ route_type: "wire", x: 4.4, y: 1.4, width: 0.15, layer: "bottom" },
			{
				route_type: "via",
				x: 4.4,
				y: 1.4,
				from_layer: "bottom",
				to_layer: "top",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
			{ route_type: "wire", x: 4.4, y: 1.4, width: 0.15, layer: "top" },
			{ route_type: "wire", x: 4.5, y: 0.253364, width: 0.15, layer: "top" },
		],
	},
];

// Local frame of the explicit R4 fanout; physical board geometry is unchanged.
export const r9ChargeLedFanoutPaths: FanoutTracePath[] = [
	...r9ChargeVbatTracePaths,
	...r9ChargeLedTracePaths,
].map((path) => ({
	...path,
	route: path.route.map((point) => ({
		...point,
		...applyToPoint(translate(-8, -16.5), {
			x: z.number().parse(point.x),
			y: z.number().parse(point.y),
		}),
	})),
}));

// Complete charger programming-current filter branch; board XY mm,+Z top.
export const r9ProgFilterTracePaths: FanoutTracePath[] = [
	{
		connection: "C9.pin1",
		route: [
			{ route_type: "wire", x: -4.299976, y: 11, width: 0.15, layer: "top" },
			{ route_type: "wire", x: -3.3, y: 12.3, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: -3.3,
				y: 12.3,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
			{ route_type: "wire", x: -3.3, y: 12.3, width: 0.15, layer: "bottom" },
			{ route_type: "wire", x: -3.3, y: 16.7, width: 0.15, layer: "bottom" },
			{
				route_type: "wire",
				x: -0.0003175,
				y: 16.7,
				width: 0.15,
				layer: "bottom",
			},
			{
				route_type: "wire",
				x: -0.0003175,
				y: 15.8,
				width: 0.15,
				layer: "bottom",
			},
		],
	},
	{
		connection: "C9.pin2",
		route: [
			{ route_type: "wire", x: -5.700024, y: 11, width: 0.15, layer: "top" },
			{ route_type: "wire", x: -6.7, y: 9.8, width: 0.15, layer: "top" },
			{
				route_type: "via",
				x: -6.7,
				y: 9.8,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];
export const r9ProgFilterFanoutPaths: FanoutTracePath[] =
	r9ProgFilterTracePaths.map((path) => ({
		...path,
		route: path.route.map((point) => ({
			...point,
			...applyToPoint(translate(5, -11), {
				x: z.number().parse(point.x),
				y: z.number().parse(point.y),
			}),
		})),
	}));

export const r9UsbDisablePaths: FanoutTracePath[] = r8UsbDisablePaths.map(
	(path): FanoutTracePath => {
		if (path.connection !== "R6.pin2") return path;
		return {
			...path,
			route: [
				...path.route,
				{
					route_type: "via",
					x: -1.5,
					y: 3.3,
					from_layer: "top",
					to_layer: "bottom",
					via_diameter: 0.45,
					via_hole_diameter: 0.3,
				},
			],
		};
	},
);

// U5's saved top return reaches the same physical barrel as C7 ground.
// Expose that existing layer transition to the plane routing phase.
export const r9SensorTracePaths: FanoutTracePath[] = sensorEscapePaths.map(
	(path) =>
		path.connection === "U5.pin3"
			? {
					...path,
					route: [
						...path.route,
						{
							route_type: "via",
							x: 3.2,
							y: 8.5,
							from_layer: "top",
							to_layer: "bottom",
							via_diameter: 0.45,
							via_hole_diameter: 0.3,
						},
					],
				}
			: path,
);

const batteryGroundWorldPaths: FanoutTracePath[] = [
	{
		connection: "J2.pin1",
		route: [
			{
				route_type: "wire",
				x: -15.9999913,
				y: 13.499999,
				width: 0.508,
				layer: "top",
			},
			{
				route_type: "wire",
				x: -14.6,
				y: 13.499999,
				width: 0.508,
				layer: "top",
			},
			{
				route_type: "via",
				x: -14.6,
				y: 13.499999,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},

	{
		connection: "J2.pin3",
		route: [
			{
				route_type: "wire",
				x: -19.8750153,
				y: 11.200029,
				width: 0.3,
				layer: "top",
			},
			{ route_type: "wire", x: -19.8750153, y: 9.9, width: 0.3, layer: "top" },
			{
				route_type: "via",
				x: -19.8750153,
				y: 9.9,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
	{
		connection: "J2.pin4",
		route: [
			{
				route_type: "wire",
				x: -19.8750153,
				y: 14.799971,
				width: 0.3,
				layer: "top",
			},
			{ route_type: "wire", x: -19.8750153, y: 16.1, width: 0.3, layer: "top" },
			{
				route_type: "via",
				x: -19.8750153,
				y: 16.1,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];
const switchFrameWorldPaths: FanoutTracePath[] = [
	{
		connection: "SW1.pin4_internal_1",
		route: [
			{
				route_type: "wire",
				x: 20.90602235,
				y: 8.599942,
				width: 0.3,
				layer: "top",
			},
			{ route_type: "wire", x: 20.9, y: 9.8, width: 0.3, layer: "top" },
			{
				route_type: "via",
				x: 20.9,
				y: 9.8,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];
export const r9BatteryGroundWorldPaths = batteryGroundWorldPaths;
export const r9SwitchFrameWorldPaths = switchFrameWorldPaths;
export const r9BatteryGroundPaths = batteryGroundWorldPaths.map((path) => ({
	...path,
	route: path.route.map((point) => {
		const moved = applyToPoint(translate(18, -13), {
			x: z.number().parse(point.x),
			y: z.number().parse(point.y),
		});
		return {
			...point,
			x: z.number().parse(moved.x),
			y: z.number().parse(moved.y),
		};
	}),
}));
export const r9SwitchFramePaths = switchFrameWorldPaths.map((path) => ({
	...path,
	route: path.route.map((point) => {
		const moved = applyToPoint(translate(-19, -5), {
			x: z.number().parse(point.x),
			y: z.number().parse(point.y),
		});
		return {
			...point,
			x: z.number().parse(moved.x),
			y: z.number().parse(moved.y),
		};
	}),
}));

export const r9ChargeStatFanoutPaths = r9ChargeStatTracePaths.map((path) => ({
	...path,
	route: path.route.map((point) => {
		const moved = applyToPoint(translate(-8, -26), {
			x: z.number().parse(point.x),
			y: z.number().parse(point.y),
		});
		return { ...point, x: moved.x, y: moved.y };
	}),
}));
export const r9StatusLedFanoutPaths = r9StatusLedTracePaths.map((path) => ({
	...path,
	route: path.route.map((point) => {
		const moved = applyToPoint(translate(15, 5), {
			x: z.number().parse(point.x),
			y: z.number().parse(point.y),
		});
		return { ...point, x: moved.x, y: moved.y };
	}),
}));

export const r9ProgramGroundPaths: FanoutTracePath[] = [
	{
		connection: "J3.pin5",
		route: [
			{
				route_type: "wire",
				x: 14.200157,
				y: 14.7999897,
				width: 0.3,
				layer: "top",
			},
			{ route_type: "wire", x: 12.9, y: 14.7999897, width: 0.3, layer: "top" },
			{
				route_type: "via",
				x: 12.9,
				y: 14.7999897,
				from_layer: "top",
				to_layer: "bottom",
				via_diameter: 0.45,
				via_hole_diameter: 0.3,
			},
		],
	},
];