Skip to content

FEAT: EDB Config - export component properties #810

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

Merged
merged 9 commits into from
Sep 24, 2024
2 changes: 1 addition & 1 deletion src/pyedb/configuration/cfg_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def get_attributes(self, exclude=None):
exclude = exclude if isinstance(exclude, list) else [exclude]
attrs = {i: j for i, j in attrs.items() if i not in exclude}
attrs = {i: j for i, j in attrs.items() if not i.startswith("_")}
attrs = {i: j for i, j in attrs.items() if j is not None}
attrs = {i: j for i, j in attrs.items() if j not in [None, [], {}]}
return attrs

def set_attributes(self, pedb_object):
Expand Down
102 changes: 28 additions & 74 deletions src/pyedb/configuration/cfg_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,6 @@
from pyedb.configuration.cfg_common import CfgBase


class CfgPortProperties(CfgBase):
def __init__(self, **kwargs):
self.reference_offset = kwargs.pop("reference_offset", 0)
self.reference_size_auto = kwargs.pop("reference_size_auto", 0)
self.reference_size_x = kwargs.pop("reference_size_x", 0)
self.reference_size_y = kwargs.pop("reference_size_y", 0)


class CfgSolderBallsProperties(CfgBase):
def __init__(self, **kwargs):
self.shape = kwargs.pop("shape", None)
self.diameter = kwargs.pop("diameter", None)
self.mid_diameter = kwargs.pop("mid_diameter", None)
self.height = kwargs.pop("height", None)
self.enabled = kwargs.pop("enabled", None)


class CfgRlcModel(CfgBase):
def __init__(self, **kwargs):
self.resistance = kwargs.get("resistance", None)
Expand All @@ -51,42 +34,17 @@ def __init__(self, **kwargs):


class CfgComponent(CfgBase):
protected_attributes = ["reference_designator", "definition", "location", "angle", "placement_layer"]

def __init__(self, **kwargs):
self.enabled = kwargs.get("enabled", None)

self.reference_designator = kwargs.get("reference_designator", None)
self.definition = kwargs.get("definition", None)
self.type = kwargs.get("part_type", None)
self.port_properties = CfgPortProperties(**kwargs["port_properties"]) if "port_properties" in kwargs else None
self.solder_ball_properties = (
CfgSolderBallsProperties(**kwargs["solder_ball_properties"]) if "solder_ball_properties" in kwargs else None
)
self.type = kwargs["part_type"].lower() if kwargs.get("part_type") else None
self.port_properties = kwargs.get("port_properties", {})
self.solder_ball_properties = kwargs.get("solder_ball_properties", {})
self.ic_die_properties = kwargs.get("ic_die_properties", {})
self.pin_pair_model = kwargs.get("pin_pair_model", None)

self.x_location, self.y_location = kwargs.get("location", [None, None])
self.angle = kwargs.get("angle", None)
self.placement_layer = kwargs.get("placement_layer", None)

def export_properties(self):
"""Export component properties.

Returns
-------
Dict
"""
data_comp = {}
data_comp["enabled"] = self.enabled
data_comp["reference_designator"] = self.reference_designator
data_comp["definition"] = self.definition
data_comp["type"] = self.type
data_comp["pin_pair_model"] = self.pin_pair_model
data_comp["x_location"] = self.x_location
data_comp["y_location"] = self.y_location
# data_comp["angle"] = self.angle
data_comp["placement_layer"] = self.placement_layer
return data_comp
self.spice_model = kwargs.get("spice_model", None)
self.s_parameter_model = kwargs.get("s_parameter_model", None)


class CfgComponents:
Expand All @@ -98,31 +56,22 @@ def apply(self):
comps_in_db = self._pedb.components
for comp in self.components:
c_db = comps_in_db[comp.reference_designator]

for attr, value in comp.get_attributes().items(): # All component properties
if attr == "solder_ball_properties":
solder_ball_properties = value
port_properties = comp.port_properties
self._pedb.components.set_solder_ball(
component=comp.reference_designator,
sball_diam=solder_ball_properties.diameter,
sball_mid_diam=solder_ball_properties.mid_diameter,
sball_height=solder_ball_properties.height,
shape=solder_ball_properties.shape,
auto_reference_size=port_properties.reference_size_auto,
reference_height=port_properties.reference_offset,
reference_size_x=port_properties.reference_size_x,
reference_size_y=port_properties.reference_size_y,
)
elif attr == "port_properties":
pass
elif attr == "pin_pair_model":
c_db.set_model_properties(pin_pair_model=comp.pin_pair_model)
else:
if attr in dir(c_db):
setattr(c_db, attr, value)
else:
raise AttributeError(f"'{attr}' is not valid component attribute.")
if comp.definition:
c_db.definition = comp.definition
if comp.type:
c_db.type = comp.type
if comp.solder_ball_properties:
c_db.set_solder_ball_properties(**comp.solder_ball_properties)
if comp.port_properties:
c_db.set_port_properties(**comp.port_properties)
if comp.ic_die_properties:
c_db.set_ic_die_properties(**comp.ic_die_properties)
if comp.pin_pair_model:
c_db.set_model_properties(pin_pair_model=comp.pin_pair_model)
if comp.spice_model:
c_db.set_model_properties(spice_model=comp.spice_model)
if comp.s_parameter_model:
c_db.set_model_properties(s_parameter_model=comp.s_parameter_model)

def _load_data_from_db(self):
self.components = []
Expand All @@ -133,15 +82,20 @@ def _load_data_from_db(self):
reference_designator=comp.name,
part_type=comp.type,
pin_pair_model=comp.get_model_properties().get("pin_pair_model"),
spice_model=comp.get_model_properties().get("spice_model"),
s_parameter_model=comp.get_model_properties().get("s_parameter_model"),
definition=comp.component_def,
location=comp.location,
placement_layer=comp.placement_layer,
solder_ball_properties=comp.get_solder_ball_properties(),
ic_die_properties=comp.get_ic_die_properties(),
port_properties=comp.get_port_properties(),
)
self.components.append(cfg_comp)

def get_data_from_db(self):
self._load_data_from_db()
data = []
for comp in self.components:
data.append(comp.export_properties())
data.append(comp.get_attributes())
return data
22 changes: 12 additions & 10 deletions src/pyedb/configuration/cfg_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ def __init__(self, pedb, **kwargs):

def get_data_from_db(self):
if "pyedb_cutout" in self._pedb.stackup.all_layers:
poly = self._pedb.layout.find_primitive(layer_name="pyedb_cutout")[0]
self.custom_extent = poly.polygon_data.points
polygons = self._pedb.layout.find_primitive(layer_name="pyedb_cutout")
if polygons:
poly = polygons[0]
self.custom_extent = poly.polygon_data.points

net_names = []
for name, obj in self._pedb.nets.nets.items():
if obj.primitives[0].layer.name == "pyedb_cutout":
continue
if len(obj.primitives) > 0:
net_names.append(name)
net_names = []
for name, obj in self._pedb.nets.nets.items():
if obj.primitives[0].layer.name == "pyedb_cutout":
continue
if len(obj.primitives) > 0:
net_names.append(name)

self.reference_list = []
self.signal_list = net_names
self.reference_list = []
self.signal_list = net_names
return self.export_properties()

def export_properties(self):
Expand Down
6 changes: 4 additions & 2 deletions src/pyedb/configuration/cfg_ports_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,15 @@ def create(self):
return circuit_elements

def export_properties(self):
return {
data = {
"name": self.name,
"type": self.type,
"reference_designator": self.reference_designator,
"positive_terminal": self.positive_terminal_info.export_properties(),
"negative_terminal": self.negative_terminal_info.export_properties(),
}
if self.negative_terminal_info:
data.update({"negative_terminal": self.negative_terminal_info.export_properties()})
return data


class CfgSource(CfgCircuitElement):
Expand Down
4 changes: 4 additions & 0 deletions src/pyedb/configuration/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ def export(
nets=True,
pin_groups=True,
operations=True,
components=True,
):
"""Export the configuration data from layout to a file.

Expand All @@ -330,6 +331,8 @@ def export(
Whether to export pin groups.
operations : bool
Whether to export operations.
components : bool
Whether to export component.
Returns
-------
bool
Expand All @@ -345,6 +348,7 @@ def export(
nets=nets,
pin_groups=pin_groups,
operations=operations,
components=components,
)
with open(file_path, "w") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
Expand Down
112 changes: 110 additions & 2 deletions src/pyedb/dotnet/edb_core/cell/hierarchy/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from pyedb.dotnet.edb_core.cell.hierarchy.spice_model import SpiceModel
from pyedb.dotnet.edb_core.definition.package_def import PackageDef
from pyedb.dotnet.edb_core.edb_data.padstacks_data import EDBPadstackInstance
from pyedb.dotnet.edb_core.general import pascal_to_snake, snake_to_pascal

try:
import numpy as np
Expand Down Expand Up @@ -1034,8 +1035,10 @@ def get_model_properties(self):
temp["capacitance_enabled"] = rlc.CEnabled
pin_pair_model.append(temp)
elif model.GetModelType().ToString() == "SParameterModel":
s_parameter_model["reference_net"] = model.GetReferenceNet()
s_parameter_model["model_name"] = model.GetComponentModelName()
temp = dict()
temp["reference_net"] = model.GetReferenceNet()
temp["model_name"] = model.GetComponentModelName()
s_parameter_model.append(temp)
elif model.GetModelType().ToString() == "SPICEModel":
spice_model["model_name"] = model.GetModelName()
spice_model["model_path"] = model.GetModelPath()
Expand Down Expand Up @@ -1093,3 +1096,108 @@ def set_model_properties(self, **kwargs):
spice_model["sub_circuit"],
spice_model["terminal_pairs"],
)

def get_ic_die_properties(self):
temp = dict()
cp = self.component_property
c_type = self.type.lower()
if not c_type == "ic":
return temp
else:
ic_die_prop = cp.GetDieProperty().Clone()
die_type = pascal_to_snake(ic_die_prop.GetType().ToString())
temp["type"] = die_type
if not die_type == "no_die":
temp["orientation"] = pascal_to_snake(ic_die_prop.GetOrientation())
if die_type == "wire_bond":
temp["height"] = ic_die_prop.GetHeightValue().ToString()
return temp

def set_ic_die_properties(self, **kwargs):
cp = self.component_property
c_type = self.type.lower()
if not c_type == "ic":
return
else:
ic_die_prop = cp.GetDieProperty().Clone()
die_type = kwargs.get("type")
if not die_type == "no_die":
orientation = kwargs.get("orientation")
if orientation:
ic_die_prop.SetOrientation(getattr(self._edb.definition.DieType, snake_to_pascal(die_type)))
if die_type == "wire_bond":
height = kwargs.get("height")
if height:
ic_die_prop.SetHeight(self._pedb.edb_value(height))
cp.SetDieProperty(ic_die_prop)
self.component_property = cp

def get_solder_ball_properties(self):
temp = dict()
cp = self.component_property
c_type = self.type.lower()
if c_type not in ["io", "other"]:
return temp
else:
solder_ball_prop = cp.GetSolderBallProperty().Clone()
_, diam, mid_diam = solder_ball_prop.GetDiameterValue()
height = solder_ball_prop.GetHeightValue().ToString()
shape = solder_ball_prop.GetShape().ToString()
uses_solder_ball = solder_ball_prop.UsesSolderball()
temp["uses_solder_ball"] = uses_solder_ball
temp["shape"] = pascal_to_snake(shape)
temp["diameter"] = diam.ToString()
temp["mid_diameter"] = mid_diam.ToString()
temp["height"] = height
return temp

def set_solder_ball_properties(self, **kwargs):
cp = self.component_property
solder_ball_prop = cp.GetSolderBallProperty().Clone()
shape = kwargs.get("shape")
if shape:
solder_ball_prop.SetShape(getattr(self._edb.definition.SolderballShape, snake_to_pascal(shape)))
if shape == "cylinder":
diameter = kwargs["diameter"]
solder_ball_prop.SetDiameter(self._pedb.edb_value(diameter), self._pedb.edb_value(diameter))
elif shape == "spheroid":
diameter = kwargs["diameter"]
mid_diameter = kwargs["mid_diameter"]
solder_ball_prop.SetDiameter(self._pedb.edb_value(diameter), self._pedb.edb_value(mid_diameter))
else:
return
solder_ball_prop.SetHeight(self._get_edb_value(kwargs["height"]))
cp.SetSolderBallProperty(solder_ball_prop)
self.component_property = cp

def get_port_properties(self):
temp = dict()
cp = self.component_property
c_type = self.type.lower()
if c_type not in ["ic", "io", "other"]:
return temp
else:
port_prop = cp.GetPortProperty().Clone()
reference_height = port_prop.GetReferenceHeightValue().ToString()
reference_size_auto = port_prop.GetReferenceSizeAuto()
_, reference_size_x, reference_size_y = port_prop.GetReferenceSize()
temp["reference_height"] = reference_height
temp["reference_size_auto"] = reference_size_auto
temp["reference_size_x"] = str(reference_size_x)
temp["reference_size_y"] = str(reference_size_y)
return temp

def set_port_properties(self, **kwargs):
cp = self.component_property
port_prop = cp.GetPortProperty().Clone()
height = kwargs.get("reference_height")
if height:
port_prop.SetReferenceHeight(self._pedb.edb_value(height))
reference_size_auto = kwargs.get("reference_size_auto")
if reference_size_auto:
port_prop.SetReferenceSizeAuto(reference_size_auto)
reference_size_x = kwargs.get("reference_size_x", 0)
reference_size_y = kwargs.get("reference_size_y", 0)
port_prop.SetReferenceSize(self._pedb.edb_value(reference_size_x), self._pedb.edb_value(reference_size_y))
cp.SetPortProperty(port_prop)
self.component_property = cp
7 changes: 4 additions & 3 deletions src/pyedb/dotnet/edb_core/cell/terminal/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,10 @@ def ref_terminal(self):
"""Get reference terminal."""

edb_terminal = self._edb_object.GetReferenceTerminal()
terminal = self._pedb.terminals[edb_terminal.GetName()]
if not terminal.is_null:
return terminal
if not edb_terminal.IsNull():
return self._pedb.terminals[edb_terminal.GetName()]
else:
return None

@ref_terminal.setter
def ref_terminal(self, value):
Expand Down
Loading