-
Notifications
You must be signed in to change notification settings - Fork 12
feat: add DRC check to prevent I2C SDA and SCL from connecting #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
bb11088
5e375a7
fac8b37
e2407e2
a588b68
f82f71d
f78a1c2
4df7974
1270064
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||
| import type { | ||||||||
| AnyCircuitElement, | ||||||||
| SourceI2cMisconfiguredError, | ||||||||
| } from "circuit-json" | ||||||||
| import { getSourcePortConnectivityMapFromCircuitJson } from "circuit-json-to-connectivity-map" | ||||||||
|
|
||||||||
| type SourceComponent = Extract< | ||||||||
| AnyCircuitElement, | ||||||||
| { source_component_id: string; name: string } | ||||||||
| > | ||||||||
|
|
||||||||
| export function checkI2cSdaConnectedToSclMisconfigured( | ||||||||
| circuitJson: AnyCircuitElement[], | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
ctx ??= getDrcContext(circuitJson) type DrcContext = {
connMap: ConnectivityMap,
db: CircuitJsonUtil
}
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||
| ): SourceI2cMisconfiguredError[] { | ||||||||
| const errors: SourceI2cMisconfiguredError[] = [] | ||||||||
|
|
||||||||
| const sourceComponents = circuitJson.filter( | ||||||||
| (el): el is SourceComponent => | ||||||||
| "source_component_id" in el && | ||||||||
| (el.type === "source_component" || el.type.startsWith("source_simple_")), | ||||||||
| ) | ||||||||
|
|
||||||||
| // Get all source ports to easily look up their attributes | ||||||||
| const sourcePorts = circuitJson.filter( | ||||||||
| (el): el is Extract<AnyCircuitElement, { type: "source_port" }> => | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import SourcePort |
||||||||
| el.type === "source_port", | ||||||||
| ) | ||||||||
| const portMap = new Map(sourcePorts.map((p) => [p.source_port_id, p])) | ||||||||
|
|
||||||||
| const connMap = getSourcePortConnectivityMapFromCircuitJson(circuitJson) | ||||||||
|
|
||||||||
| for (const [netId, connectedPortIds] of Object.entries(connMap.netMap)) { | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inefficient mechanism. Find the ports first |
||||||||
| let hasSda = false | ||||||||
| let hasScl = false | ||||||||
|
|
||||||||
| const conflictingPortIds: string[] = [] | ||||||||
|
|
||||||||
| for (const portId of connectedPortIds) { | ||||||||
| const port = portMap.get(portId) | ||||||||
| if (!port) continue | ||||||||
|
|
||||||||
| let shouldAddPort = false | ||||||||
| if (port.is_configured_for_i2c_sda) { | ||||||||
| hasSda = true | ||||||||
| shouldAddPort = true | ||||||||
| } | ||||||||
| if (port.is_configured_for_i2c_scl) { | ||||||||
| hasScl = true | ||||||||
| shouldAddPort = true | ||||||||
| } | ||||||||
| if (shouldAddPort && !conflictingPortIds.includes(portId)) { | ||||||||
| conflictingPortIds.push(portId) | ||||||||
| } | ||||||||
techmannih marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| } | ||||||||
|
|
||||||||
| if (hasSda && hasScl) { | ||||||||
| // Sort conflicting port IDs to ensure deterministic ID generation | ||||||||
| const sortedConflicts = [...conflictingPortIds].sort() | ||||||||
| const conflictIdStr = sortedConflicts.join("_") | ||||||||
|
|
||||||||
| const portDetails = sortedConflicts.map((portId) => { | ||||||||
| const port = portMap.get(portId) | ||||||||
| const component = sourceComponents.find( | ||||||||
| (c) => c.source_component_id === port?.source_component_id, | ||||||||
| ) | ||||||||
| const componentName = component?.name ?? "Unknown" | ||||||||
| const portName = port?.name ?? "Unknown" | ||||||||
| const i2cRole = port?.is_configured_for_i2c_sda | ||||||||
| ? "I2C SDA" | ||||||||
| : port?.is_configured_for_i2c_scl | ||||||||
| ? "I2C SCL" | ||||||||
| : "Unknown" | ||||||||
| return `${componentName}.${portName} (${i2cRole})` | ||||||||
| }) | ||||||||
|
|
||||||||
| errors.push({ | ||||||||
| type: "source_i2c_misconfigured_error", | ||||||||
| source_i2c_misconfigured_error_id: `source_i2c_misconfigured_error_${conflictIdStr}`, | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these are normally generated or something- you should never create ids like this |
||||||||
| error_type: "source_i2c_misconfigured_error", | ||||||||
| message: `${portDetails.join(" is connected to ")} on the same net. To fix this, ensure SDA and SCL are routed to separate nets.`, | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bad. Give the user exact instructions for how to fix and use toMatchInlineSnapshot for the error in the test
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's just not a good error but i can't even see it until you have toMatchInlineSnapshot |
||||||||
| source_port_ids: conflictingPortIds, | ||||||||
| }) | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| return errors | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| import { expect, test } from "bun:test" | ||
| import { checkI2cSdaConnectedToSclMisconfigured } from "../../lib/check-i2c-sda-connected-to-scl" | ||
| import type { AnyCircuitElement } from "circuit-json" | ||
|
|
||
| test("checkI2cSdaConnectedToSclMisconfigured detects SDA connected to SCL", () => { | ||
| const circuitJson: AnyCircuitElement[] = [ | ||
| { | ||
| type: "source_port", | ||
| source_port_id: "port_sda", | ||
| name: "SDA", | ||
| is_configured_for_i2c_sda: true, | ||
| source_component_id: "comp_1", | ||
| }, | ||
| { | ||
| type: "source_component", | ||
| source_component_id: "comp_1", | ||
| name: "U1", | ||
| }, | ||
| { | ||
| type: "source_port", | ||
| source_port_id: "port_scl", | ||
| name: "SCL", | ||
| is_configured_for_i2c_scl: true, | ||
| source_component_id: "comp_2", | ||
| }, | ||
| { | ||
| type: "source_component", | ||
| source_component_id: "comp_2", | ||
| name: "U2", | ||
| }, | ||
| { | ||
| type: "source_trace", | ||
| source_trace_id: "trace_1", | ||
| connected_source_port_ids: ["port_sda", "port_scl"], | ||
| connected_source_net_ids: [], | ||
| }, | ||
| ] as AnyCircuitElement[] | ||
|
|
||
| const errors = checkI2cSdaConnectedToSclMisconfigured(circuitJson) | ||
| expect(errors).toHaveLength(1) | ||
| expect(errors[0].message).toEqual(expect.stringContaining("U2.SCL (I2C SCL)")) | ||
| expect(errors[0].message).toEqual(expect.stringContaining("U1.SDA (I2C SDA)")) | ||
| expect(errors[0].source_port_ids).toContain("port_sda") | ||
| expect(errors[0].source_port_ids).toContain("port_scl") | ||
| }) | ||
|
|
||
| test("checkI2cSdaConnectedToSclMisconfigured allows SDA connected to SDA", () => { | ||
| const circuitJson: AnyCircuitElement[] = [ | ||
| { | ||
| type: "source_port", | ||
| source_port_id: "port_sda1", | ||
| name: "SDA1", | ||
| is_configured_for_i2c_sda: true, | ||
| }, | ||
| { | ||
| type: "source_port", | ||
| source_port_id: "port_sda2", | ||
| name: "SDA2", | ||
| is_configured_for_i2c_sda: true, | ||
| }, | ||
| { | ||
| type: "source_trace", | ||
| source_trace_id: "trace_1", | ||
| connected_source_port_ids: ["port_sda1", "port_sda2"], | ||
| connected_source_net_ids: [], | ||
| }, | ||
| ] as AnyCircuitElement[] | ||
|
|
||
| const errors = checkI2cSdaConnectedToSclMisconfigured(circuitJson) | ||
| expect(errors).toHaveLength(0) | ||
| }) | ||
techmannih marked this conversation as resolved.
Show resolved
Hide resolved
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?