diff --git a/python/commands/pin_locator.py b/python/commands/pin_locator.py index e4ef9ee..96face0 100644 --- a/python/commands/pin_locator.py +++ b/python/commands/pin_locator.py @@ -143,7 +143,14 @@ class PinLocator: # KiCad lib_symbols may use a different name than the instance lib_id: # instance lib_id: "stat-tis-custom:BAT_18650" # lib_symbols name: "BAT_18650_3" (prefix stripped, unit suffix added) - # Strategy: exact match first, then bare-name prefix match. + # instance lib_id: "Regulator_Linear:AMS1117-3.3" + # lib_symbols name: "AMS1117-3.3_0_1" (multi-unit symbol) + # + # Strategy (in priority order): + # 1. Exact match on full lib_id + # 2. Bare name exact match (strip library prefix from both sides) + # 3. Bare name prefix match with unit suffix (_N) + # 4. Substring match (lib_id bare name appears inside symbol_name) bare_name = lib_id.split(":")[-1] if ":" in lib_id else lib_id best_match = None @@ -151,18 +158,31 @@ class PinLocator: if not (isinstance(item, list) and len(item) > 1 and item[0] == Symbol("symbol")): continue symbol_name = str(item[1]).strip('"') + sn_bare = symbol_name.split(":")[-1] if ":" in symbol_name else symbol_name + + # Strategy 1: Exact full lib_id match if symbol_name == lib_id: best_match = item break - if best_match is None: - sn_bare = symbol_name.split(":")[-1] if ":" in symbol_name else symbol_name - if sn_bare == bare_name or ( - sn_bare.startswith(bare_name) - and len(sn_bare) > len(bare_name) - and sn_bare[len(bare_name)] == "_" - and sn_bare[len(bare_name) + 1 :].isdigit() - ): - best_match = item + + # Strategy 2: Bare name exact match + if best_match is None and sn_bare == bare_name: + best_match = item + + # Strategy 3: Bare name prefix match with unit suffix (_N) + if best_match is None and ( + sn_bare.startswith(bare_name) + and len(sn_bare) > len(bare_name) + and sn_bare[len(bare_name)] == "_" + and sn_bare[len(bare_name) + 1 :].isdigit() + ): + best_match = item + + # Strategy 4: Substring match — lib_id bare name appears inside symbol_name + # (handles cases like "AMS1117-3.3" matching "AMS1117-3.3_0_1" or + # names with extra KiCad-generated suffixes beyond unit numbers) + if best_match is None and bare_name in sn_bare: + best_match = item if best_match is not None: matched_name = str(best_match[1]).strip('"') @@ -176,8 +196,17 @@ class PinLocator: logger.info(f"Extracted {len(pins)} pins from {lib_id}") return pins - logger.warning(f"Symbol {lib_id} not found in lib_symbols") - return {} + # When no match is found, list available symbol names for debugging + if best_match is None: + available = [] + for item in lib_symbols[1:]: + if isinstance(item, list) and len(item) > 1 and item[0] == Symbol("symbol"): + available.append(str(item[1]).strip('"')) + logger.warning( + f"Symbol {lib_id} (bare: '{bare_name}') not found in lib_symbols. " + f"Available ({len(available)}): {available[:10]}{'...' if len(available) > 10 else ''}" + ) + return {} except Exception as e: logger.error(f"Error getting symbol pins: {e}")