mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
netlist: export/import symbol unit information to footprints
For upcoming gate swapping feature
This commit is contained in:
parent
1418b03c5a
commit
7e448c404a
@ -51,3 +51,5 @@ value
|
||||
version
|
||||
aliases
|
||||
alias
|
||||
unit
|
||||
units
|
||||
|
@ -481,6 +481,80 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
|
||||
// Output the primary UUID
|
||||
uuid = symbol->m_Uuid.AsString();
|
||||
xunits->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
|
||||
|
||||
// Emit unit information (per-unit name and pins) after tstamps
|
||||
XNODE* xunitInfo;
|
||||
xcomp->AddChild( xunitInfo = node( wxT( "units" ) ) );
|
||||
|
||||
// Emit all units defined by the library symbol, independent of placement
|
||||
const std::unique_ptr<LIB_SYMBOL>& libSym = symbol->GetLibSymbolRef();
|
||||
|
||||
if( libSym )
|
||||
{
|
||||
int unitCount = std::max( libSym->GetUnitCount(), 1 );
|
||||
|
||||
for( int unitIdx = 1; unitIdx <= unitCount; ++unitIdx )
|
||||
{
|
||||
wxString unitName = libSym->GetUnitDisplayName( unitIdx, false );
|
||||
|
||||
XNODE* xunit;
|
||||
xunitInfo->AddChild( xunit = node( wxT( "unit" ) ) );
|
||||
xunit->AddAttribute( wxT( "name" ), unitName );
|
||||
|
||||
XNODE* xpins;
|
||||
xunit->AddChild( xpins = node( wxT( "pins" ) ) );
|
||||
|
||||
// Gather all graphical pins for this unit across body styles
|
||||
std::vector<SCH_PIN*> pinList = libSym->GetGraphicalPins( unitIdx, 0 );
|
||||
|
||||
// Sort by X then Y to establish a stable, spatial order for matching pins
|
||||
// in the PCB editor when swapping gates
|
||||
std::sort( pinList.begin(), pinList.end(),
|
||||
[]( SCH_PIN* a, SCH_PIN* b )
|
||||
{
|
||||
auto pa = a->GetPosition();
|
||||
auto pb = b->GetPosition();
|
||||
|
||||
if( pa.x != pb.x )
|
||||
return pa.x < pb.x;
|
||||
|
||||
return pa.y < pb.y;
|
||||
} );
|
||||
|
||||
// Emit pins in this spatial order, deduping by number within the unit only
|
||||
std::unordered_set<wxString> seen;
|
||||
|
||||
for( SCH_PIN* basePin : pinList )
|
||||
{
|
||||
bool stackedValid = false;
|
||||
std::vector<wxString> expandedNums = basePin->GetStackedPinNumbers( &stackedValid );
|
||||
|
||||
if( stackedValid && !expandedNums.empty() )
|
||||
{
|
||||
for( const wxString& num : expandedNums )
|
||||
{
|
||||
if( seen.insert( num ).second )
|
||||
{
|
||||
XNODE* xpin;
|
||||
xpins->AddChild( xpin = node( wxT( "pin" ) ) );
|
||||
xpin->AddAttribute( wxT( "num" ), num );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString num = basePin->GetShownNumber();
|
||||
|
||||
if( seen.insert( num ).second )
|
||||
{
|
||||
XNODE* xpin;
|
||||
xpins->AddChild( xpin = node( wxT( "pin" ) ) );
|
||||
xpin->AddAttribute( wxT( "num" ), num );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -750,6 +750,15 @@ public:
|
||||
void ApplyDefaultSettings( const BOARD& board, bool aStyleFields, bool aStyleText,
|
||||
bool aStyleShapes );
|
||||
|
||||
struct FP_UNIT_INFO
|
||||
{
|
||||
wxString m_unitName; // e.g. A
|
||||
std::vector<wxString> m_pins; // pin numbers in this unit
|
||||
};
|
||||
|
||||
void SetUnitInfo( const std::vector<FP_UNIT_INFO>& aUnits ) { m_unitInfo = aUnits; }
|
||||
const std::vector<FP_UNIT_INFO>& GetUnitInfo() const { return m_unitInfo; }
|
||||
|
||||
bool IsBoardOnly() const { return m_attributes & FP_BOARD_ONLY; }
|
||||
void SetBoardOnly( bool aIsBoardOnly = true )
|
||||
{
|
||||
@ -1180,6 +1189,9 @@ private:
|
||||
|
||||
std::unordered_set<wxString> m_transientComponentClassNames;
|
||||
std::unique_ptr<COMPONENT_CLASS_CACHE_PROXY> m_componentClassCacheProxy;
|
||||
|
||||
// Optional unit mapping information for multi-unit symbols
|
||||
std::vector<FP_UNIT_INFO> m_unitInfo;
|
||||
};
|
||||
|
||||
#endif // FOOTPRINT_H
|
||||
|
@ -332,6 +332,8 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
||||
bool duplicatePinsAreJumpers = false;
|
||||
std::vector<std::set<wxString>> jumperPinGroups;
|
||||
|
||||
std::vector<COMPONENT::UNIT_INFO> parsedUnits;
|
||||
|
||||
// The token comp was read, so the next data is (ref P1)
|
||||
while( (token = NextTok() ) != T_RIGHT )
|
||||
{
|
||||
@ -496,6 +498,87 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
||||
|
||||
break;
|
||||
|
||||
case T_units:
|
||||
{
|
||||
// Parse a section like:
|
||||
// (units (unit (ref "U1A") (name "A") (pins (pin "1") (pin "2"))))
|
||||
while( ( token = NextTok() ) != T_RIGHT )
|
||||
{
|
||||
if( token == T_LEFT )
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_unit )
|
||||
{
|
||||
COMPONENT::UNIT_INFO info;
|
||||
|
||||
while( ( token = NextTok() ) != T_RIGHT )
|
||||
{
|
||||
if( token == T_LEFT )
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_name:
|
||||
NeedSYMBOLorNUMBER();
|
||||
info.m_unitName = From_UTF8( CurText() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_pins:
|
||||
while( ( token = NextTok() ) != T_RIGHT )
|
||||
{
|
||||
if( token == T_LEFT )
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_pin )
|
||||
{
|
||||
wxString pinNum;
|
||||
|
||||
// Parse pins in attribute style: (pin (num "1"))
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
if( token == T_LEFT )
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_num )
|
||||
{
|
||||
NeedSYMBOLorNUMBER();
|
||||
pinNum = From_UTF8( CurText() );
|
||||
NeedRIGHT();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignore other subfields of pin
|
||||
// leave bare tokens untouched; they are not supported in this context
|
||||
}
|
||||
}
|
||||
|
||||
if( !pinNum.IsEmpty() )
|
||||
info.m_pins.emplace_back( pinNum );
|
||||
}
|
||||
else
|
||||
{
|
||||
skipCurrent();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
skipCurrent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parsedUnits.push_back( info );
|
||||
}
|
||||
else
|
||||
{
|
||||
skipCurrent();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case T_component_classes:
|
||||
while( ( token = NextTok() ) != T_RIGHT )
|
||||
{
|
||||
@ -583,6 +666,7 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
||||
component->SetDuplicatePadNumbersAreJumpers( duplicatePinsAreJumpers );
|
||||
std::ranges::copy( jumperPinGroups, std::inserter( component->JumperPadGroups(),
|
||||
component->JumperPadGroups().end() ) );
|
||||
component->SetUnitInfo( parsedUnits );
|
||||
m_netlist->AddComponent( component );
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,14 @@ void COMPONENT::SetFootprint( FOOTPRINT* aFootprint )
|
||||
aFootprint->SetValue( m_value );
|
||||
aFootprint->SetFPID( m_fpid );
|
||||
aFootprint->SetPath( path );
|
||||
|
||||
// Copy over unit info
|
||||
std::vector<FOOTPRINT::FP_UNIT_INFO> fpUnits;
|
||||
|
||||
for( const UNIT_INFO& u : m_units )
|
||||
fpUnits.push_back( { u.m_unitName, u.m_pins } );
|
||||
|
||||
aFootprint->SetUnitInfo( fpUnits );
|
||||
}
|
||||
|
||||
|
||||
|
@ -206,6 +206,16 @@ public:
|
||||
NETLIST_GROUP* GetGroup() const { return m_group; }
|
||||
void SetGroup( NETLIST_GROUP* aGroup ) { m_group = aGroup; }
|
||||
|
||||
// Unit info for multi-unit symbols
|
||||
struct UNIT_INFO
|
||||
{
|
||||
wxString m_unitName; // e.g. A
|
||||
std::vector<wxString> m_pins; // pin numbers in this unit
|
||||
};
|
||||
|
||||
void SetUnitInfo( const std::vector<UNIT_INFO>& aUnits ) { m_units = aUnits; }
|
||||
const std::vector<UNIT_INFO>& GetUnitInfo() const { return m_units; }
|
||||
|
||||
private:
|
||||
std::vector<COMPONENT_NET> m_nets; ///< list of nets shared by the component pins
|
||||
|
||||
@ -260,6 +270,9 @@ private:
|
||||
NETLIST_GROUP* m_group;
|
||||
|
||||
static COMPONENT_NET m_emptyNet;
|
||||
|
||||
// Unit information parsed from the netlist (optional)
|
||||
std::vector<UNIT_INFO> m_units;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user