diff --git a/docs/CIRCUIT_JSON_SOURCE_COMPONENT_OVERVIEW.md b/docs/CIRCUIT_JSON_SOURCE_COMPONENT_OVERVIEW.md new file mode 100644 index 0000000..302281a --- /dev/null +++ b/docs/CIRCUIT_JSON_SOURCE_COMPONENT_OVERVIEW.md @@ -0,0 +1,151 @@ +# Circuit JSON Specification: Source Component Overview + +> Created at 2024-11-12T19:07:05.930Z +> Latest Version: https://github.com/tscircuit/circuit-json/blob/main/docs/SOURCE_COMPONENT_OVERVIEW.md + +Any type below can be imported from `circuit-json`. Every type has a corresponding +snake_case version which is a zod type that can be used to parse unknown json, +for example `SourceComponent` has a `source_component.parse` function that you +can also import. + +```ts +interface SourceSimpleChip { + type: "source_component" + ftype: "simple_chip" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string +} + +interface SourceSimpleInductor { + type: "source_component" + ftype: "simple_inductor" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string + inductance: number +} + +interface SourceLed { + type: "source_component" + ftype: "led" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string +} + +interface SourceTrace { + type: "source_trace" + source_trace_id: string + connected_source_port_ids: string[] + connected_source_net_ids: string[] + subcircuit_connectivity_map_key?: string +} + +interface SourceSimpleGround { + type: "source_component" + ftype: "simple_ground" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string +} + +interface SourceSimpleResistor { + type: "source_component" + ftype: "simple_resistor" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string + resistance: number +} + +interface SourceSimpleBattery { + type: "source_component" + ftype: "simple_battery" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string + capacity: number +} + +interface SourceNet { + type: "source_net" + source_net_id: string + name: string + member_source_group_ids: string[] + is_power?: boolean + is_ground?: boolean + is_digital_signal?: boolean + is_analog_signal?: boolean + trace_width?: number +} + +interface SourceSimpleDiode { + type: "source_component" + ftype: "simple_diode" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string +} + +interface SourceGroup { + type: "source_group" + source_group_id: string + name?: string +} + +interface SourcePort { + type: "source_port" + pin_number?: number + port_hints?: string[] + name: string + source_port_id: string + source_component_id: string +} + +interface SourceSimplePowerSource { + type: "source_component" + ftype: "simple_power_source" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string + voltage: number +} + +interface SourceSimpleCapacitor { + type: "source_component" + ftype: "simple_capacitor" + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string + capacitance: number +} + +interface SourceComponentBase { + type: "source_component" + ftype?: string + source_component_id: string + name: string + manufacturer_part_number?: string + supplier_part_numbers?: Partial> + display_value?: string +} +``` diff --git a/lib/dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-session.ts b/lib/dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-session.ts new file mode 100644 index 0000000..2ae77e7 --- /dev/null +++ b/lib/dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-session.ts @@ -0,0 +1,85 @@ +import type { AnyCircuitElement, PcbTraceRoutePointWire } from "circuit-json" +import type { DsnPcb, DsnSession, Wire } from "../types" +import { su } from "@tscircuit/soup-util" +import { convertCircuitJsonToDsnJson } from "./convert-circuit-json-to-dsn-json" +import { applyToPoint, scale } from "transformation-matrix" + +export function convertCircuitJsonToDsnSession( + dsnPcb: DsnPcb, + circuitJson: AnyCircuitElement[], +): DsnSession { + // First convert to DSN PCB to reuse component/pad processing + // const dsnPcb = convertCircuitJsonToDsnJson(circuitJson) + + // console.dir(dsnPcb, { depth: null }) + + const pcb_traces = su(circuitJson as any).pcb_trace.list() + const source_traces = su(circuitJson as any).source_trace.list() + const source_ports = su(circuitJson as any).source_port.list() + const nets = su(circuitJson as any).source_net.list() + + const transformMmToDsnUnit = scale(1000) + const session: DsnSession = { + is_dsn_session: true, + filename: dsnPcb.filename || "session", + placement: { + resolution: dsnPcb.resolution, + components: dsnPcb.placement.components, + }, + routes: { + resolution: dsnPcb.resolution, + parser: dsnPcb.parser, + library_out: { + // TODO Just add vias here + padstacks: [], + }, + network_out: { + nets: dsnPcb.network.nets + .map((net) => { + const source_net = nets.find((n) => n.name === net.name) + if (!source_net) return null + const pcb_traces_for_net = pcb_traces.filter((pcb_trace) => { + const source_trace = source_traces.find( + (st) => st.source_trace_id === pcb_trace.source_trace_id, + ) + + return source_trace?.connected_source_net_ids.includes( + source_net.source_net_id, + ) + }) + + return { + name: net.name, + wires: pcb_traces_for_net.flatMap((trace): Wire => { + // TODO whenever the pcb trace changes layers or changes width, + // we have to create a new wire + return { + path: { + layer: "F.Cu", + width: 0.1, // TODO get width + coordinates: trace.route + .filter( + (rp): rp is PcbTraceRoutePointWire => + rp.route_type === "wire", + ) + .map((rp) => + applyToPoint(transformMmToDsnUnit, { + x: rp.x, + y: rp.y, + }), + ) + .flatMap((trp) => [trp.x, trp.y]), + }, + } + }), + } + }) + .filter((net): net is { name: string; wires: Wire[] } => + Boolean(net), + ), + }, + }, + } + + return session +} diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-json-to-circuit-json.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-json-to-circuit-json.ts index ce28027..d6b1ae8 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-json-to-circuit-json.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-json-to-circuit-json.ts @@ -2,12 +2,15 @@ import { fromTriangles, scale, applyToPoint } from "transformation-matrix" import type { AnyCircuitElement, PcbBoard } from "circuit-json" import type { DsnPcb, DsnSession } from "../types" -import { convertPadstacksToSmtPads } from "./convert-padstacks-to-smtpads" -import { convertWiresToPcbTraces } from "./convert-wire-to-trace" +import { convertPadstacksToSmtPads } from "./dsn-component-converters/convert-padstacks-to-smtpads" +import { convertWiresToPcbTraces } from "./dsn-component-converters/convert-wire-to-trace" import { pairs } from "lib/utils/pairs" import { convertDsnPcbToCircuitJson } from "./convert-dsn-pcb-to-circuit-json" import { convertDsnSessionToCircuitJson } from "./convert-dsn-session-to-circuit-json" +/** + * @deprecated use convertDsnPcbToCircuitJson instead + */ export function convertDsnJsonToCircuitJson( dsnPcb: DsnPcb, ): AnyCircuitElement[] { diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-pcb-to-circuit-json.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-pcb-to-circuit-json.ts index 0a15a2f..7e9594e 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-pcb-to-circuit-json.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-pcb-to-circuit-json.ts @@ -2,9 +2,12 @@ import { fromTriangles, scale, applyToPoint } from "transformation-matrix" import type { AnyCircuitElement, PcbBoard } from "circuit-json" import type { DsnPcb } from "../types" -import { convertPadstacksToSmtPads } from "./convert-padstacks-to-smtpads" -import { convertWiresToPcbTraces } from "./convert-wire-to-trace" +import { convertPadstacksToSmtPads } from "./dsn-component-converters/convert-padstacks-to-smtpads" +import { convertWiresToPcbTraces } from "./dsn-component-converters/convert-wire-to-trace" import { pairs } from "lib/utils/pairs" +import { convertNetsToSourceNetsAndTraces } from "./dsn-component-converters/convert-nets-to-source-nets-and-traces" +import { convertDsnPcbComponentsToSourceComponentsAndPorts } from "./dsn-component-converters/convert-dsn-pcb-components-to-source-components-and-ports" +import { su } from "@tscircuit/soup-util" export function convertDsnPcbToCircuitJson( dsnPcb: DsnPcb, @@ -12,7 +15,7 @@ export function convertDsnPcbToCircuitJson( const elements: AnyCircuitElement[] = [] // TODO use pcb.resolution.unit and pcb.resolution.value - const transformUmToMm = scale(1 / 1000) + const transformDsnUnitToMm = scale(1 / 1000) // Add the board // You must use the dsnPcb.boundary to get the center, width and height @@ -31,12 +34,12 @@ export function convertDsnPcbToCircuitJson( const minX = Math.min(...boundaryPath.map(([x]) => x)) const maxY = Math.max(...boundaryPath.map(([, y]) => y)) const minY = Math.min(...boundaryPath.map(([, y]) => y)) - board.center = applyToPoint(transformUmToMm, { + board.center = applyToPoint(transformDsnUnitToMm, { x: (maxX + minX) / 2, y: (maxY + minY) / 2, }) - board.width = (maxX - minX) * transformUmToMm.a - board.height = (maxY - minY) * transformUmToMm.a + board.width = (maxX - minX) * transformDsnUnitToMm.a + board.height = (maxY - minY) * transformDsnUnitToMm.a } else { throw new Error( `Couldn't read DSN boundary, add support for dsnPcb.structure.boundary["${Object.keys(dsnPcb.structure.boundary).join(",")}"]`, @@ -46,7 +49,7 @@ export function convertDsnPcbToCircuitJson( elements.push(board) // Convert padstacks to SMT pads using the transformation matrix - elements.push(...convertPadstacksToSmtPads(dsnPcb, transformUmToMm)) + elements.push(...convertPadstacksToSmtPads(dsnPcb, transformDsnUnitToMm)) // Convert wires to PCB traces using the transformation matrix if (dsnPcb.wiring && dsnPcb.network) { @@ -54,10 +57,23 @@ export function convertDsnPcbToCircuitJson( ...convertWiresToPcbTraces( dsnPcb.wiring, dsnPcb.network, - transformUmToMm, + transformDsnUnitToMm, ), ) } + elements.push( + ...convertDsnPcbComponentsToSourceComponentsAndPorts({ + dsnPcb, + transformDsnUnitToMm, + }), + ) + elements.push( + ...convertNetsToSourceNetsAndTraces({ + dsnPcb, + source_ports: su(elements as any).source_port.list(), + }), + ) + return elements } diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-session-to-circuit-json.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-session-to-circuit-json.ts index 3348dd5..79da0ce 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-session-to-circuit-json.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/convert-dsn-session-to-circuit-json.ts @@ -1,10 +1,10 @@ import { scale, applyToPoint } from "transformation-matrix" import type { AnyCircuitElement, PcbBoard } from "circuit-json" import type { DsnJson, DsnPcb, DsnSession } from "../types" -import { convertWiresToPcbTraces } from "./convert-wire-to-trace" +import { convertWiresToPcbTraces } from "./dsn-component-converters/convert-wire-to-trace" import Debug from "debug" import { convertDsnPcbToCircuitJson } from "./convert-dsn-pcb-to-circuit-json" -import { convertWiringPathToPcbTraces } from "./convert-wiring-path-to-pcb-traces" +import { convertWiringPathToPcbTraces } from "./dsn-component-converters/convert-wiring-path-to-pcb-traces" const debug = Debug("dsn-converter") diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-dsn-pcb-components-to-source-components-and-ports.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-dsn-pcb-components-to-source-components-and-ports.ts new file mode 100644 index 0000000..0e367d8 --- /dev/null +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-dsn-pcb-components-to-source-components-and-ports.ts @@ -0,0 +1,62 @@ +import type { AnySourceComponent, PcbPort, SourcePort } from "circuit-json" +import { applyToPoint, type Matrix } from "transformation-matrix" +import type { DsnPcb, Image, Pin } from "lib/dsn-pcb/types" + +export const convertDsnPcbComponentsToSourceComponentsAndPorts = ({ + dsnPcb, + transformDsnUnitToMm, +}: { + dsnPcb: DsnPcb + transformDsnUnitToMm: Matrix +}): Array => { + const result: Array = [] + + // Map to store image definitions for component lookup + const imageMap = new Map(dsnPcb.library.images.map((img) => [img.name, img])) + + for (const component of dsnPcb.placement.components) { + const image = imageMap.get(component.name) + if (!image) continue + + // Create source component + const sourceComponent: AnySourceComponent = { + type: "source_component", + source_component_id: `sc_${component.name}_${component.place.refdes}`, + name: component.place.refdes, + display_value: component.place.PN, + // Default to simple_chip if no specific type can be determined + ftype: "simple_chip", + } + result.push(sourceComponent) + + // Create ports for each pin in the image + if (image.pins) { + for (const pin of image.pins) { + const port: SourcePort = { + type: "source_port", + source_port_id: `source_port_${component.name}-Pad${pin.pin_number}`, + source_component_id: sourceComponent.source_component_id, + name: `${component.place.refdes}-${pin.pin_number}`, + pin_number: pin.pin_number, + port_hints: [], + } + const pcb_port_center = applyToPoint(transformDsnUnitToMm, { + x: component.place.x + pin.x, + y: component.place.y + pin.y, + }) + const pcb_port: PcbPort = { + pcb_port_id: `pcb_port_${component.name}-Pad${pin.pin_number}`, + type: "pcb_port", + source_port_id: port.source_port_id, + pcb_component_id: component.name, + x: pcb_port_center.x, + y: pcb_port_center.y, + layers: [component.place.side === "back" ? "bottom" : "top"], + } + result.push(port, pcb_port) + } + } + } + + return result +} diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-nets-to-source-nets-and-traces.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-nets-to-source-nets-and-traces.ts new file mode 100644 index 0000000..11edde9 --- /dev/null +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-nets-to-source-nets-and-traces.ts @@ -0,0 +1,37 @@ +import type { SourceNet, SourcePort, SourceTrace } from "circuit-json" +import type { DsnPcb } from "lib/dsn-pcb/types" + +export const convertNetsToSourceNetsAndTraces = ({ + dsnPcb, + source_ports, +}: { dsnPcb: DsnPcb; source_ports: SourcePort[] }) => { + const result: Array = [] + const { nets } = dsnPcb.network + + for (const { name, pins } of nets) { + if (name.startsWith("unconnected-")) continue + const source_net: SourceNet = { + type: "source_net", + name, + source_net_id: `source_net_${name}`, + member_source_group_ids: [], + } + + const connected_source_port_ids: string[] = [] + for (const pin of pins) { + const source_port = source_ports.find((sp) => sp.name === pin) + if (source_port) + connected_source_port_ids.push(source_port.source_port_id) + } + + const source_trace: SourceTrace = { + type: "source_trace", + connected_source_net_ids: [source_net.source_net_id], + connected_source_port_ids, + source_trace_id: `source_trace_${name}`, + } + result.push(source_net, source_trace) + } + + return result +} diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-padstacks-to-smtpads.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-padstacks-to-smtpads.ts similarity index 98% rename from lib/dsn-pcb/dsn-json-to-circuit-json/convert-padstacks-to-smtpads.ts rename to lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-padstacks-to-smtpads.ts index 48e5ccd..a1e1b8e 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-padstacks-to-smtpads.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-padstacks-to-smtpads.ts @@ -1,5 +1,5 @@ import type { AnyCircuitElement } from "circuit-json" -import type { DsnPcb } from "../types" +import type { DsnPcb } from "lib/dsn-pcb/types" import { applyToPoint } from "transformation-matrix" export function convertPadstacksToSmtPads( diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-polyline-path-to-pcb-traces.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-polyline-path-to-pcb-traces.ts similarity index 97% rename from lib/dsn-pcb/dsn-json-to-circuit-json/convert-polyline-path-to-pcb-traces.ts rename to lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-polyline-path-to-pcb-traces.ts index 19bc31d..a0966fd 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-polyline-path-to-pcb-traces.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-polyline-path-to-pcb-traces.ts @@ -1,5 +1,5 @@ import type { PcbTrace } from "circuit-json" -import type { Wiring } from "../types" +import type { Wiring } from "../../types" import { type Matrix, applyToPoint } from "transformation-matrix" import { chunks } from "lib/utils/chunks" import { computeSegIntersection } from "lib/utils/compute-seg-intersection" diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-wire-to-trace.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-wire-to-trace.ts similarity index 93% rename from lib/dsn-pcb/dsn-json-to-circuit-json/convert-wire-to-trace.ts rename to lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-wire-to-trace.ts index c43381e..83b7923 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-wire-to-trace.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-wire-to-trace.ts @@ -4,7 +4,7 @@ import type { PcbTraceRoutePointWire, } from "circuit-json" import { type Matrix, applyToPoint } from "transformation-matrix" -import type { Network, Wiring } from "../types" +import type { Network, Wiring } from "../../types" import { convertPolylinePathToPcbTraces } from "./convert-polyline-path-to-pcb-traces" import { convertWiringPathToPcbTraces } from "./convert-wiring-path-to-pcb-traces" @@ -18,6 +18,7 @@ export function convertWiresToPcbTraces( wiring.wires?.forEach((wire) => { const netName = wire.net + if (!netName) return if (processedNets.has(netName) || wire.type === "shove_fixed") { return diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-wiring-path-to-pcb-traces.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-wiring-path-to-pcb-traces.ts similarity index 97% rename from lib/dsn-pcb/dsn-json-to-circuit-json/convert-wiring-path-to-pcb-traces.ts rename to lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-wiring-path-to-pcb-traces.ts index 17f95c9..c8544a3 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/convert-wiring-path-to-pcb-traces.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/dsn-component-converters/convert-wiring-path-to-pcb-traces.ts @@ -4,7 +4,7 @@ import type { PcbTraceRoutePointWire, } from "circuit-json" import { type Matrix, applyToPoint } from "transformation-matrix" -import type { Network, Wiring } from "../types" +import type { Wiring } from "../../types" export const convertWiringPathToPcbTraces = ({ wire, diff --git a/lib/dsn-pcb/dsn-json-to-circuit-json/parse-dsn-to-dsn-json.ts b/lib/dsn-pcb/dsn-json-to-circuit-json/parse-dsn-to-dsn-json.ts index 6c884b9..a1b2d21 100644 --- a/lib/dsn-pcb/dsn-json-to-circuit-json/parse-dsn-to-dsn-json.ts +++ b/lib/dsn-pcb/dsn-json-to-circuit-json/parse-dsn-to-dsn-json.ts @@ -10,6 +10,7 @@ import type { Class, Clearance, Component, + ComponentPlacement, DsnJson, DsnPcb, DsnSession, @@ -409,7 +410,7 @@ export function processPlacement(nodes: ASTNode[]): Placement { return placement as Placement } -function processComponent(nodes: ASTNode[]): Component { +function processComponent(nodes: ASTNode[]): ComponentPlacement { const component: Partial = {} if (nodes[1].type === "Atom" && typeof nodes[1].value === "string") { component.name = nodes[1].value @@ -425,7 +426,7 @@ function processComponent(nodes: ASTNode[]): Component { } }) - return component as Component + return component as ComponentPlacement } function processPlace(nodes: ASTNode[]): Place { diff --git a/lib/dsn-pcb/types.ts b/lib/dsn-pcb/types.ts index 024856a..fc4266a 100644 --- a/lib/dsn-pcb/types.ts +++ b/lib/dsn-pcb/types.ts @@ -40,17 +40,7 @@ export interface DsnPcb { } } placement: { - components: Array<{ - name: string - place: { - refdes: string - PN?: string - x: number - y: number - side: "front" | "back" - rotation: number - } - }> + components: Array } library: { images: Image[] @@ -93,6 +83,18 @@ export interface DsnPcb { } } +export interface ComponentPlacement { + name: string + place: { + refdes: string + PN?: string + x: number + y: number + side: "front" | "back" + rotation: number + } +} + export interface Parser { string_quote: string space_in_quoted_tokens: string @@ -154,7 +156,7 @@ export interface Clearance { } export interface Placement { - components: Component[] + components: ComponentPlacement[] } export interface Component { @@ -265,7 +267,7 @@ export interface Wire { width: number coordinates: number[] } - net: string + net?: string clearance_class?: string type?: string } @@ -276,10 +278,7 @@ export interface DsnSession { filename: string placement: { resolution: Resolution - components: Array<{ - name: string - place: Place - }> + components: Array } routes: { resolution: Resolution diff --git a/lib/index.ts b/lib/index.ts index 20a1504..eb73376 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,5 +1,7 @@ export * from "./dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-json.ts" export * from "./dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-string.ts" +export * from "./dsn-pcb/circuit-json-to-dsn-json/convert-circuit-json-to-dsn-session.ts" +export * from "./dsn-pcb/dsn-json-to-circuit-json/convert-dsn-pcb-to-circuit-json.ts" export * from "./dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-json.ts" export * from "./dsn-pcb/circuit-json-to-dsn-json/stringify-dsn-session.ts" export * from "./dsn-pcb/dsn-json-to-circuit-json/convert-dsn-json-to-circuit-json.ts" diff --git a/tests/dsn-pcb/circuit-json-to-dsn-session.test.ts b/tests/dsn-pcb/circuit-json-to-dsn-session.test.ts new file mode 100644 index 0000000..4db8af3 --- /dev/null +++ b/tests/dsn-pcb/circuit-json-to-dsn-session.test.ts @@ -0,0 +1,88 @@ +import { su } from "@tscircuit/soup-util" +import { expect, test } from "bun:test" +import { + convertCircuitJsonToDsnSession, + convertDsnJsonToCircuitJson, + convertDsnPcbToCircuitJson, + parseDsnToDsnJson, + type DsnPcb, +} from "lib" +// @ts-ignore +import dsnPcbContent from "../assets/testkicadproject/testkicadproject.dsn" with { + type: "text", +} +import type { AnyCircuitElement, PcbTrace } from "circuit-json" + +test("convert circuit json to dsn session", () => { + const dsnPcb = parseDsnToDsnJson(dsnPcbContent) as DsnPcb + + const circuitJson = convertDsnPcbToCircuitJson(dsnPcb) + const source_traces = su(circuitJson as any).source_trace.list() + const pcb_traces = su(circuitJson as any).pcb_trace.list() + const nets = su(circuitJson as any).source_net.list() + const source_ports = su(circuitJson as any).source_port.list() + const pcb_ports = su(circuitJson as any).pcb_port.list() + const source_components = su(circuitJson as any).source_component.list() + + expect(nets[0].name).toBe("Net-(C1-Pad1)") + expect(source_traces[0].connected_source_net_ids).toContain( + nets[0].source_net_id, + ) + expect(pcb_traces).toHaveLength(0) + + // Create a direct-line connection between the pads that need to be connected + const pcbTracesFromAutorouting: PcbTrace[] = [ + { + pcb_trace_id: "pcb_trace_1", + type: "pcb_trace", + source_trace_id: source_traces[0].source_trace_id, + route: [ + { + start_pcb_port_id: pcb_ports[0].pcb_port_id, + route_type: "wire", + x: pcb_ports[0].x, + y: pcb_ports[0].y, + width: 0.1, + layer: pcb_ports[0].layers[0], + }, + { + end_pcb_port_id: pcb_ports[1].pcb_port_id, + route_type: "wire", + x: pcb_ports[1].x, + y: pcb_ports[1].y, + width: 0.1, + layer: pcb_ports[1].layers[0], + start_pcb_port_id: pcb_ports[1].pcb_port_id, + }, + ], + }, + ] + + const session = convertCircuitJsonToDsnSession( + dsnPcb, + circuitJson.concat(pcbTracesFromAutorouting), + ) + + // console.log(session) + + // console.dir(session, { depth: null }) + + // Verify basic session structure + expect(session.is_dsn_session).toBe(true) + expect(session.placement.components).toBeDefined() + expect(session.routes.network_out.nets).toBeDefined() + + // Check components were converted + expect(session.placement.components).toHaveLength(2) + const componentNames = session.placement.components.map((c) => c.name) + expect(componentNames.join(",")).toContain("Resistor_SMD") + expect(componentNames.join(",")).toContain("Capacitor_SMD") + + // Check resolution + expect(session.placement.resolution.unit).toBe("um") + expect(session.placement.resolution.value).toBe(10) + + // Check nets were converted + expect(session.routes.network_out.nets).toHaveLength(1) + expect(session.routes.network_out.nets[0].name).toBe("Net-(C1-Pad1)") +})