Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,14 @@ function traceHasEndpointMatchingConnectionSelector(
trace: Trace,
connectionSelectorEndpointKey: string,
): boolean {
return trace
.getTracePortPathSelectors()
.some(
(selector) =>
convertPortSelectorToEndpointKey(selector) ===
connectionSelectorEndpointKey,
)
return [
...trace.getTracePortPathSelectors(),
...trace.getTracePathNetSelectors(),
].some(
(selector) =>
convertPortSelectorToEndpointKey(selector) ===
connectionSelectorEndpointKey,
)
}

function getAutoroutersByPhaseIndex(
Expand Down Expand Up @@ -307,6 +308,19 @@ export function Group_getRoutingPhasePlans(
convertPortSelectorToEndpointKey,
)
plan.connectionSelectors = connectionSelectors
for (const selector of connectionSelectors) {
const net = group.selectOne<Net>(selector, { type: "net" })
if (!net || breakoutByNet.has(net)) continue
if (!phaseProps.reroute) {
for (const existingPlan of plansByPhaseIndex.values()) {
if (existingPlan === plan) continue
existingPlan.nets = existingPlan.nets.filter(
(existingNet) => existingNet !== net,
)
}
}
if (!plan.nets.includes(net)) plan.nets.push(net)
}

for (const trace of traces) {
if (breakoutByTrace.has(trace)) continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export function connectionIsInRoutingPhase(
for (const trace of phasePlan.traces) {
if (!trace.source_trace_id) continue
if (connection.source_trace_id === trace.source_trace_id) return true
// Breakouts use their split, group-owned connections, not the whole net.
if (
!phasePlan.routingPcbGroupId &&
connection.source_trace_ids?.includes(trace.source_trace_id)
)
return true
if (connection.name === trace.source_trace_id) return true
if (connection.rootConnectionName === trace.source_trace_id) return true
if (connection.mergedConnectionNames?.includes(trace.source_trace_id)) {
Expand Down
4 changes: 3 additions & 1 deletion lib/utils/autorouting/SimpleRouteJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {
SimpleRouteJson as AutorouterSimpleRouteJson,
SimplifiedPcbTrace as AutorouterSimplifiedPcbTrace,
} from "@tscircuit/capacity-autorouter"
import type { PcbGroup } from "circuit-json"
import type { PcbGroup, SourceTrace } from "circuit-json"
import type { CircuitJsonMetadata, Obstacle } from "../obstacles/types"

export type { CircuitJsonMetadata, Obstacle } from "../obstacles/types"
Expand Down Expand Up @@ -83,6 +83,8 @@ export type SimpleRouteConnection = {
name: SrjConnectionName
routingPcbGroupId?: PcbGroupId
source_trace_id?: string
/** Source traces combined into a net-based routing connection. */
source_trace_ids?: SourceTrace["source_trace_id"][]
rootConnectionName?: string
mergedConnectionNames?: string[]
isOffBoard?: boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,13 @@ const getDifferentialPairSrjConnectionNamesByCohortOrThrow = ({
const matchingSrjConnections: SimpleRouteConnection[] = []
for (const srjConnection of srjConnections) {
if (
srjConnection.source_trace_id &&
differentialPairSourceTraceIds.includes(srjConnection.source_trace_id)
(srjConnection.source_trace_id &&
differentialPairSourceTraceIds.includes(
srjConnection.source_trace_id,
)) ||
srjConnection.source_trace_ids?.some((sourceTraceId) =>
differentialPairSourceTraceIds.includes(sourceTraceId),
)
) {
matchingSrjConnections.push(srjConnection)
}
Expand Down
3 changes: 3 additions & 0 deletions lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,9 @@ export const getSimpleRouteJsonFromCircuitJson = ({
name:
net.source_net_id ??
sharedConnMap.getNetConnectedToId(net.source_net_id),
source_trace_ids: connectedSourceTraces.map(
(sourceTrace) => sourceTrace.source_trace_id,
),
nominalTraceWidth: nominalTraceWidthFromConnectedTraces,
width: nominalTraceWidthFromConnectedTraces,
pointsToConnect,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test } from "bun:test"
import { getSimpleRouteJsonFromCircuitJson } from "lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson"
import { getTestFixture } from "tests/fixtures/get-test-fixture"

test("does not warn for a two-terminal conductor split through a source net", (): void => {
Expand Down Expand Up @@ -30,4 +31,20 @@ test("does not warn for a two-terminal conductor split through a source net", ()
warning.property_name === "negativeConnection",
),
).toEqual([])

const board = circuit.firstChild
if (!board) throw new Error("Expected a board")
const { simpleRouteJson } = getSimpleRouteJsonFromCircuitJson({
db: circuit.db,
subcircuitComponent: board,
})
expect(simpleRouteJson.differentialPairs).toEqual([
{
connectionNames: [
circuit.db.source_net.getWhere({ name: "DP" })!.source_net_id,
circuit.db.source_trace.getWhere({ name: "DM" })!.source_trace_id,
],
lengthTolerance: 0.1,
},
])
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 8 additions & 12 deletions tests/repros/usb-c-breakout-net-pair.test.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import { expect, test } from "bun:test"
import { getSimpleRouteJsonFromCircuitJson } from "lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson"
import { createAutoroutingPhaseIoStack } from "tests/fixtures/create-autorouting-phase-io-stack"
import { getTestFixture } from "tests/fixtures/get-test-fixture"

import UsbBreakoutBoard from "./usb-c-breakout/board"

test("USB-C breakout pair wired through named nets", async () => {
const { circuit } = getTestFixture()
const phases = createAutoroutingPhaseIoStack(circuit)
circuit.add(<UsbBreakoutBoard />)
await circuit.renderUntilSettled()
expect(circuit.db.source_failed_to_create_component_error.list()).toEqual([])
expect(circuit.db.source_trace_not_connected_error.list()).toEqual([])
const board = circuit.firstChild
if (!board) throw new Error("Expected USB-C breakout board")
expect(() =>
getSimpleRouteJsonFromCircuitJson({
db: circuit.db,
subcircuitComponent: board,
}),
).toThrow(
'Could not find an SRJ connection for trace name or port selector ".R3 > .pin1"',
)
expect(circuit.db.pcb_trace.list()).toHaveLength(0)
expect(phases).toHaveLength(2)
expect(phases[0]?.startSimpleRouteJson?.differentialPairs).toHaveLength(1)
expect(phases[0]?.endSimpleRouteJson?.traces).toHaveLength(2)
expect(circuit.db.pcb_autorouting_error.list()).toEqual([])
expect(circuit.db.pcb_trace_error.list()).toEqual([])
expect(circuit.db.pcb_port_not_connected_error.list()).toEqual([])
await expect(circuit).toMatchPcbSnapshot(import.meta.path)
}, 30_000)
Loading