From c6c70d779af72b39ea3d88773c026d3b8f7f6faf Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:54:24 +0200 Subject: [PATCH 1/6] Add: Header picker --- src/faebryk/library/Header.py | 23 ++++-- src/faebryk/library/_F.py | 2 +- src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 8 +++ src/faebryk/libs/picker/jlcpcb/picker_lib.py | 76 ++++++++++++++++++++ test/libs/picker/test_jlcpcb.py | 12 ++++ 5 files changed, 113 insertions(+), 8 deletions(-) diff --git a/src/faebryk/library/Header.py b/src/faebryk/library/Header.py index 12e4f4ce..878795a0 100644 --- a/src/faebryk/library/Header.py +++ b/src/faebryk/library/Header.py @@ -30,14 +30,17 @@ def __init__( vertical_pin_count: int, ) -> None: super().__init__() - self.horizontal_pin_count = horizonal_pin_count - self.vertical_pin_count = vertical_pin_count + self._horizontal_pin_count = horizonal_pin_count + self._vertical_pin_count = vertical_pin_count def __preinit__(self): - self.pin_count_horizonal.merge(self.horizontal_pin_count) - self.pin_count_vertical.merge(self.vertical_pin_count) + self.pin_count_horizonal.merge(self._horizontal_pin_count) + self.pin_count_vertical.merge(self._vertical_pin_count) pin_pitch: F.TBD[Quantity] + mating_pin_lenght: F.TBD[Quantity] + conection_pin_lenght: F.TBD[Quantity] + spacer_height: F.TBD[Quantity] pin_type: F.TBD[PinType] pad_type: F.TBD[PadType] angle: F.TBD[Angle] @@ -46,7 +49,13 @@ def __preinit__(self): pin_count_vertical: F.TBD[int] @L.rt_field - def unnamed(self): - return times(self.horizonal_pin_count * self.vertical_pin_count, F.Electrical) + def contact(self): + return times( + self._horizontal_pin_count * self._vertical_pin_count, F.Electrical + ) - designator_prefix = L.f_field(F.has_designator_prefix_defined)("J") + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.J + ) + + attach_to_footprint: F.can_attach_to_footprint_symmetrically diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index 6c5bb6ec..8bed98ad 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -76,7 +76,6 @@ from faebryk.library.XtalIF import XtalIF from faebryk.library.has_pin_association_heuristic import has_pin_association_heuristic from faebryk.library.Common_Mode_Filter import Common_Mode_Filter -from faebryk.library.Header import Header from faebryk.library.PJ398SM import PJ398SM from faebryk.library.RJ45_Receptacle import RJ45_Receptacle from faebryk.library.Relay import Relay @@ -114,6 +113,7 @@ from faebryk.library.Capacitor import Capacitor from faebryk.library.Crystal import Crystal from faebryk.library.Fuse import Fuse +from faebryk.library.Header import Header from faebryk.library.Inductor import Inductor from faebryk.library.Resistor import Resistor from faebryk.library.Switch import Switch diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index 721754a8..f927e7a0 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -491,6 +491,14 @@ def filter_by_manufacturer_pn(self, partnumber: str) -> Self: self.Q &= Q(mfr__icontains=partnumber) return self + def filter_by_package(self, package: str | list[str]) -> Self: + assert self.Q + if isinstance(package, str): + self.Q &= Q(package__icontains=package) + elif isinstance(package, list): + self.Q &= Q(package__in=package) + return self + def filter_by_manufacturer(self, manufacturer: str) -> Self: assert self.Q if not manufacturer: diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index 49a421b4..bfdd0818 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -497,6 +497,81 @@ def find_ldo(cmp: Module): ) +def find_header(cmp: Module): + """ + Find a header part in the JLCPCB database that matches the parameters of the + provided header + """ + + assert isinstance(cmp, F.Header) + + def pin_structure_to_pin_count(vertical: bool) -> Callable[[str], F.Constant[int]]: + """ + Database data looks like: 1x3P + """ + + def f(x: str) -> F.Constant[int]: + if "x" not in x: + raise ValueError(f"Invalid pin structure: {x}") + if vertical: + return F.Constant(int(x.strip("P").split("x")[0])) + else: + return F.Constant(int(x.strip("P").split("x")[1])) + + return f + + mapping = [ + MappingParameterDB( + "pin_pitch", + [ + "Row Spacing", + "Pitch", + ], + ), + MappingParameterDB( + "mating_pin_lenght", + ["Length of Mating Pin"], + ), + MappingParameterDB( + "conection_pin_lenght", + ["Length of End Connection Pin"], + ), + MappingParameterDB( + "spacer_height", + ["Insulation Height"], + ), + # MappingParameterDB( + # "angle", + # ["Mounting Type"], + # transform_fn=str_to_enum_func(F.Header.Angle), + # ), #TODO + MappingParameterDB( + "pin_count_horizonal", + ["Pin Structure"], + transform_fn=pin_structure_to_pin_count(vertical=False), + ), + MappingParameterDB( + "pin_count_vertical", + ["Pin Structure"], + transform_fn=pin_structure_to_pin_count(vertical=True), + ), + ] + + ( + ComponentQuery() + .filter_by_category("Connectors", "Header") + .filter_by_package( + "SMD" + if cmp.pad_type == F.Header.PadType.SMD + else ["TH", "Plugin", "Push-Pull"] + ) + .filter_by_stock(qty) + .filter_by_traits(cmp) + .sort_by_price(qty) + .filter_by_module_params_and_attach(cmp, mapping, qty) + ) + + # -------------------------------------------------------------------------------------- TYPE_SPECIFIC_LOOKUP = { @@ -508,4 +583,5 @@ def find_ldo(cmp: Module): F.Diode: find_diode, F.MOSFET: find_mosfet, F.LDO: find_ldo, + F.Header: find_header, } diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index 7997221b..242978b2 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -356,6 +356,18 @@ def test_find_ldo(self): ], ) + def test_find_header(self): + self.TestRequirements( + self, + requirement=F.Header(horizonal_pin_count=3, vertical_pin_count=1).builder( + lambda h: ( + h.pad_type.merge(F.Constant(F.Header.PadType.THROUGH_HOLE)), + h.pin_pitch.merge(F.Constant(2.54 * P.mm)), + ) + ), + footprint=[("Plugin,P=2.54mm", 3)], + ) + def tearDown(self): # in test atexit not triggered, thus need to close DB manually JLCPCB_DB.get().close() From be2d2a6b5727ec7afbd4ae466556c4cdf0e3bea7 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:54:48 +0200 Subject: [PATCH 2/6] Fix: indentation --- src/faebryk/libs/picker/lcsc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/faebryk/libs/picker/lcsc.py b/src/faebryk/libs/picker/lcsc.py index 20b4d8c0..61e28a4e 100644 --- a/src/faebryk/libs/picker/lcsc.py +++ b/src/faebryk/libs/picker/lcsc.py @@ -203,8 +203,8 @@ def attach(component: Module, partno: str, get_model: bool = True): raise LCSC_PinmapException(partno, f"Failed to get pinmap: {e}") from e component.add(F.can_attach_to_footprint_via_pinmap(pinmap)) - sym = F.Symbol.with_component(component, pinmap) - sym.add(F.Symbol.has_kicad_symbol(f"lcsc:{easyeda_footprint.info.name}")) + sym = F.Symbol.with_component(component, pinmap) + sym.add(F.Symbol.has_kicad_symbol(f"lcsc:{easyeda_footprint.info.name}")) # footprint fp = F.KicadFootprint( From 6a88041610d7ecefd3b4930b5649446b5c1f604d Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Fri, 27 Sep 2024 10:32:10 +0200 Subject: [PATCH 3/6] WIP: male/female query, pad_type query --- src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 11 ++++++++--- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 16 +++++++++++----- test/libs/picker/test_jlcpcb.py | 7 ++++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index f927e7a0..d3fd6f23 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -493,10 +493,15 @@ def filter_by_manufacturer_pn(self, partnumber: str) -> Self: def filter_by_package(self, package: str | list[str]) -> Self: assert self.Q + + logger.debug(f"Possible package keywords: {package}") + description_query = Q() if isinstance(package, str): - self.Q &= Q(package__icontains=package) - elif isinstance(package, list): - self.Q &= Q(package__in=package) + package = [package] + for keyword in package: + description_query |= Q(description__icontains=keyword) + self.Q &= description_query + return self def filter_by_manufacturer(self, manufacturer: str) -> Self: diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index bfdd0818..0a2c276f 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -559,12 +559,18 @@ def f(x: str) -> F.Constant[int]: ( ComponentQuery() - .filter_by_category("Connectors", "Header") - .filter_by_package( - "SMD" - if cmp.pad_type == F.Header.PadType.SMD - else ["TH", "Plugin", "Push-Pull"] + .filter_by_category( + "Connectors", + "Headers", + # "Pin Headers" #TODO: fix + # if cmp.pin_type.get_most_narrow() == F.Header.PinType.MALE + # else "Female Headers", ) + # .filter_by_package( #TODO: fix + # "SMD" + # if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD + # else ["Plugin", "Push-Pull", "TH"] + # ) .filter_by_stock(qty) .filter_by_traits(cmp) .sort_by_price(qty) diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index 242978b2..0723cf8a 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -362,10 +362,15 @@ def test_find_header(self): requirement=F.Header(horizonal_pin_count=3, vertical_pin_count=1).builder( lambda h: ( h.pad_type.merge(F.Constant(F.Header.PadType.THROUGH_HOLE)), + h.pin_type.merge(F.Constant(F.Header.PinType.MALE)), + h.mating_pin_lenght.merge(F.Range.from_center_rel(6 * P.mm, 0.1)), h.pin_pitch.merge(F.Constant(2.54 * P.mm)), ) ), - footprint=[("Plugin,P=2.54mm", 3)], + footprint=[ + ("HDR-TH_3P-P2.54-V-M", 3), + ("Plugin,P=2.54mm", 3), + ], ) def tearDown(self): From 14ccd80a91aa39d4083469dadfbbcbe5845ee41a Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Sat, 28 Sep 2024 18:54:32 +0200 Subject: [PATCH 4/6] Fix pin and pad type filters --- src/faebryk/libs/picker/jlcpcb/jlcpcb.py | 2 +- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py index d3fd6f23..591d93bb 100644 --- a/src/faebryk/libs/picker/jlcpcb/jlcpcb.py +++ b/src/faebryk/libs/picker/jlcpcb/jlcpcb.py @@ -499,7 +499,7 @@ def filter_by_package(self, package: str | list[str]) -> Self: if isinstance(package, str): package = [package] for keyword in package: - description_query |= Q(description__icontains=keyword) + description_query |= Q(package__icontains=keyword) self.Q &= description_query return self diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index 0a2c276f..a1c6c486 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -561,16 +561,15 @@ def f(x: str) -> F.Constant[int]: ComponentQuery() .filter_by_category( "Connectors", - "Headers", - # "Pin Headers" #TODO: fix - # if cmp.pin_type.get_most_narrow() == F.Header.PinType.MALE - # else "Female Headers", + "Pin Headers" + if cmp.pin_type.get_most_narrow() == F.Header.PinType.MALE + else "Female Headers", + ) + .filter_by_package( + "SMD" + if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD + else ["Plugin", "Push-Pull", "TH"] ) - # .filter_by_package( #TODO: fix - # "SMD" - # if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD - # else ["Plugin", "Push-Pull", "TH"] - # ) .filter_by_stock(qty) .filter_by_traits(cmp) .sort_by_price(qty) From 830035ffcef890e1e64b9079f5f3a691b82f32bd Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Mon, 30 Sep 2024 22:51:50 +0200 Subject: [PATCH 5/6] Fix picker --- src/faebryk/library/Header.py | 3 +- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 162 +++++++++++++------ test/libs/picker/test_jlcpcb.py | 1 + 3 files changed, 112 insertions(+), 54 deletions(-) diff --git a/src/faebryk/library/Header.py b/src/faebryk/library/Header.py index 878795a0..58f032cb 100644 --- a/src/faebryk/library/Header.py +++ b/src/faebryk/library/Header.py @@ -21,8 +21,7 @@ class PadType(Enum): class Angle(Enum): STRAIGHT = auto() - VERTICAL90 = auto() - HORIZONTAL90 = auto() + ANGLE_90 = auto() def __init__( self, diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index a1c6c486..05684f0b 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -520,61 +520,119 @@ def f(x: str) -> F.Constant[int]: return f - mapping = [ - MappingParameterDB( - "pin_pitch", - [ - "Row Spacing", - "Pitch", - ], - ), - MappingParameterDB( - "mating_pin_lenght", - ["Length of Mating Pin"], - ), - MappingParameterDB( - "conection_pin_lenght", - ["Length of End Connection Pin"], - ), - MappingParameterDB( - "spacer_height", - ["Insulation Height"], - ), - # MappingParameterDB( - # "angle", - # ["Mounting Type"], - # transform_fn=str_to_enum_func(F.Header.Angle), - # ), #TODO - MappingParameterDB( - "pin_count_horizonal", - ["Pin Structure"], - transform_fn=pin_structure_to_pin_count(vertical=False), - ), - MappingParameterDB( - "pin_count_vertical", - ["Pin Structure"], - transform_fn=pin_structure_to_pin_count(vertical=True), - ), - ] + def angle_to_mount_type() -> Callable[[str], F.Constant[F.Header.Angle]]: + """ + Database data looks like: "Mounting Type": "Shrouded" or "Straight" + """ - ( - ComponentQuery() - .filter_by_category( - "Connectors", - "Pin Headers" - if cmp.pin_type.get_most_narrow() == F.Header.PinType.MALE - else "Female Headers", + def f(x: str) -> F.Constant[F.Header.Angle]: + if x == "Shrouded": + return F.Constant(F.Header.Angle.ANGLE_90) + elif x == "Straight": + return F.Constant(F.Header.Angle.STRAIGHT) + else: + raise ValueError(f"Invalid angle: {x}") + + return f + + pad_type = ( + "SMD" + if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD + else ["Plugin", "Push-Pull", "TH"] + ) + + if cmp.pin_type.get_most_narrow() == F.Header.PinType.FEMALE: + mapping = [ + MappingParameterDB( + "pin_pitch", + [ + "Row Spacing", + "Pitch", + ], + ), + MappingParameterDB( + "spacer_height", + ["Insulation Height"], + ), + MappingParameterDB( + "angle", + ["Mounting Type"], + transform_fn=angle_to_mount_type(), + ), + MappingParameterDB( + "pin_count_horizonal", + ["Holes Structure"], + transform_fn=pin_structure_to_pin_count(vertical=False), + ), + MappingParameterDB( + "pin_count_vertical", + ["Holes Structure"], + transform_fn=pin_structure_to_pin_count(vertical=True), + ), + ] + ( + ComponentQuery() + .filter_by_category( + "Connectors", + "Female Headers", + ) + .filter_by_package(pad_type) + .filter_by_stock(qty) + .filter_by_traits(cmp) + .sort_by_price(qty) + .filter_by_module_params_and_attach(cmp, mapping, qty) ) - .filter_by_package( - "SMD" - if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD - else ["Plugin", "Push-Pull", "TH"] + + elif cmp.pin_type.get_most_narrow() == F.Header.PinType.MALE: + mapping = [ + MappingParameterDB( + "pin_pitch", + [ + "Row Spacing", + "Pitch", + ], + ), + MappingParameterDB( + "spacer_height", + ["Insulation Height"], + ), + MappingParameterDB( + "angle", + ["Mounting Type"], + transform_fn=angle_to_mount_type(), + ), + MappingParameterDB( + "pin_count_horizonal", + ["Pin Structure"], + transform_fn=pin_structure_to_pin_count(vertical=False), + ), + MappingParameterDB( + "pin_count_vertical", + ["Pin Structure"], + transform_fn=pin_structure_to_pin_count(vertical=True), + ), + MappingParameterDB( + "mating_pin_lenght", + ["Length of Mating Pin"], + ), + MappingParameterDB( + "conection_pin_lenght", + ["Length of End Connection Pin"], + ), + ] + ( + ComponentQuery() + .filter_by_category("Connectors", "Pin Headers") + .filter_by_package(pad_type) + .filter_by_stock(qty) + .filter_by_traits(cmp) + .sort_by_price(qty) + .filter_by_module_params_and_attach(cmp, mapping, qty) + ) + else: + raise ValueError( + f"Invalid pin type: {cmp.pin_type.get_most_narrow()} for {cmp}" ) - .filter_by_stock(qty) - .filter_by_traits(cmp) - .sort_by_price(qty) - .filter_by_module_params_and_attach(cmp, mapping, qty) - ) # -------------------------------------------------------------------------------------- diff --git a/test/libs/picker/test_jlcpcb.py b/test/libs/picker/test_jlcpcb.py index 0723cf8a..50dcdb53 100644 --- a/test/libs/picker/test_jlcpcb.py +++ b/test/libs/picker/test_jlcpcb.py @@ -363,6 +363,7 @@ def test_find_header(self): lambda h: ( h.pad_type.merge(F.Constant(F.Header.PadType.THROUGH_HOLE)), h.pin_type.merge(F.Constant(F.Header.PinType.MALE)), + h.angle.merge(F.Constant(F.Header.Angle.STRAIGHT)), h.mating_pin_lenght.merge(F.Range.from_center_rel(6 * P.mm, 0.1)), h.pin_pitch.merge(F.Constant(2.54 * P.mm)), ) From ccf92a84477e7e9ab23903580cc58910e70f0bf7 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:05:38 +0200 Subject: [PATCH 6/6] Fix header pinmap and cleanup header picker --- src/faebryk/library/Header.py | 6 +- src/faebryk/libs/picker/jlcpcb/picker_lib.py | 126 +++++++------------ 2 files changed, 52 insertions(+), 80 deletions(-) diff --git a/src/faebryk/library/Header.py b/src/faebryk/library/Header.py index 58f032cb..ee384c98 100644 --- a/src/faebryk/library/Header.py +++ b/src/faebryk/library/Header.py @@ -57,4 +57,8 @@ def contact(self): F.has_designator_prefix.Prefix.J ) - attach_to_footprint: F.can_attach_to_footprint_symmetrically + @L.rt_field + def can_attach_to_footprint(self): + return F.can_attach_to_footprint_via_pinmap( + pinmap={f"{i+1}": self.contact[i] for i in range(len(self.contact))} + ) diff --git a/src/faebryk/libs/picker/jlcpcb/picker_lib.py b/src/faebryk/libs/picker/jlcpcb/picker_lib.py index 05684f0b..77d5917c 100644 --- a/src/faebryk/libs/picker/jlcpcb/picker_lib.py +++ b/src/faebryk/libs/picker/jlcpcb/picker_lib.py @@ -535,82 +535,27 @@ def f(x: str) -> F.Constant[F.Header.Angle]: return f - pad_type = ( - "SMD" - if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD - else ["Plugin", "Push-Pull", "TH"] - ) - - if cmp.pin_type.get_most_narrow() == F.Header.PinType.FEMALE: - mapping = [ - MappingParameterDB( - "pin_pitch", - [ - "Row Spacing", - "Pitch", - ], - ), - MappingParameterDB( - "spacer_height", - ["Insulation Height"], - ), + mapping = [] + if cmp.pad_type.get_most_narrow() == F.Header.PadType.SMD: + pad_type = "SMD" + logger.warning(f"Angle parameter is not supported for SMD header: {cmp}") + else: + pad_type = ["Plugin", "Push-Pull", "TH"] + mapping += [ MappingParameterDB( "angle", ["Mounting Type"], transform_fn=angle_to_mount_type(), ), - MappingParameterDB( - "pin_count_horizonal", - ["Holes Structure"], - transform_fn=pin_structure_to_pin_count(vertical=False), - ), - MappingParameterDB( - "pin_count_vertical", - ["Holes Structure"], - transform_fn=pin_structure_to_pin_count(vertical=True), - ), ] - ( - ComponentQuery() - .filter_by_category( - "Connectors", - "Female Headers", - ) - .filter_by_package(pad_type) - .filter_by_stock(qty) - .filter_by_traits(cmp) - .sort_by_price(qty) - .filter_by_module_params_and_attach(cmp, mapping, qty) - ) + if cmp.pin_type.get_most_narrow() == F.Header.PinType.FEMALE: + pin_type = "Female Headers" + pin_count_source = ["Holes Structure"] elif cmp.pin_type.get_most_narrow() == F.Header.PinType.MALE: + pin_type = "Pin Headers" + pin_count_source = ["Pin Structure"] mapping = [ - MappingParameterDB( - "pin_pitch", - [ - "Row Spacing", - "Pitch", - ], - ), - MappingParameterDB( - "spacer_height", - ["Insulation Height"], - ), - MappingParameterDB( - "angle", - ["Mounting Type"], - transform_fn=angle_to_mount_type(), - ), - MappingParameterDB( - "pin_count_horizonal", - ["Pin Structure"], - transform_fn=pin_structure_to_pin_count(vertical=False), - ), - MappingParameterDB( - "pin_count_vertical", - ["Pin Structure"], - transform_fn=pin_structure_to_pin_count(vertical=True), - ), MappingParameterDB( "mating_pin_lenght", ["Length of Mating Pin"], @@ -620,19 +565,42 @@ def f(x: str) -> F.Constant[F.Header.Angle]: ["Length of End Connection Pin"], ), ] - ( - ComponentQuery() - .filter_by_category("Connectors", "Pin Headers") - .filter_by_package(pad_type) - .filter_by_stock(qty) - .filter_by_traits(cmp) - .sort_by_price(qty) - .filter_by_module_params_and_attach(cmp, mapping, qty) - ) else: - raise ValueError( - f"Invalid pin type: {cmp.pin_type.get_most_narrow()} for {cmp}" - ) + pin_type = "Headers" + pin_count_source = ["Pin Structure", "Holes Structure"] + + mapping += [ + MappingParameterDB( + "pin_pitch", + [ + "Row Spacing", + "Pitch", + ], + ), + MappingParameterDB( + "spacer_height", + ["Insulation Height"], + ), + MappingParameterDB( + "pin_count_horizonal", + pin_count_source, + transform_fn=pin_structure_to_pin_count(vertical=False), + ), + MappingParameterDB( + "pin_count_vertical", + pin_count_source, + transform_fn=pin_structure_to_pin_count(vertical=True), + ), + ] + ( + ComponentQuery() + .filter_by_category("Connectors", pin_type) + .filter_by_package(pad_type) + .filter_by_stock(qty) + .filter_by_traits(cmp) + .sort_by_price(qty) + .filter_by_module_params_and_attach(cmp, mapping, qty) + ) # --------------------------------------------------------------------------------------