Handle unit changes in the netlist
Each symbol unit in eeschema has a unique identifier. But we don't have a unique identifier for the entire symbol. So changing which symbol instance was unit A (our default base for matching), changed the UUID that we were using to match the footprints. This commit adds all UUIDs to the netlist, allowing us to match symbol to footprint without worrying about which unit is referenced. This still does not handle changing different units on different sheets. Fixes https://gitlab.com/kicad/code/kicad/issues/7604
This commit is contained in:
parent
2a9d76f1e3
commit
8a12aa4e3a
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
#include <symbol_lib_table.h>
|
#include <symbol_lib_table.h>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 );
|
static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 );
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ XNODE* NETLIST_EXPORTER_XML::makeRoot( unsigned aCtl )
|
||||||
{
|
{
|
||||||
XNODE* xroot = node( "export" );
|
XNODE* xroot = node( "export" );
|
||||||
|
|
||||||
xroot->AddAttribute( "version", "D" );
|
xroot->AddAttribute( "version", "E" );
|
||||||
|
|
||||||
if( aCtl & GNL_HEADER )
|
if( aCtl & GNL_HEADER )
|
||||||
// add the "design" header
|
// add the "design" header
|
||||||
|
@ -237,6 +238,7 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
|
||||||
};
|
};
|
||||||
|
|
||||||
std::set<SCH_COMPONENT*, decltype( cmp )> ordered_symbols( cmp );
|
std::set<SCH_COMPONENT*, decltype( cmp )> ordered_symbols( cmp );
|
||||||
|
std::multiset<SCH_COMPONENT*, decltype( cmp )> extra_units( cmp );
|
||||||
|
|
||||||
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
|
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
|
||||||
{
|
{
|
||||||
|
@ -245,11 +247,16 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
|
||||||
|
|
||||||
if( !test.second )
|
if( !test.second )
|
||||||
{
|
{
|
||||||
if( ( *( test.first ) )->GetUnit() > symbol->GetUnit() )
|
if( ( *( test.first ) )->m_Uuid > symbol->m_Uuid )
|
||||||
{
|
{
|
||||||
|
extra_units.insert( *( test.first ) );
|
||||||
ordered_symbols.erase( test.first );
|
ordered_symbols.erase( test.first );
|
||||||
ordered_symbols.insert( symbol );
|
ordered_symbols.insert( symbol );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
extra_units.insert( symbol );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +330,20 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
|
||||||
|
|
||||||
xsheetpath->AddAttribute( "names", sheet.PathHumanReadable() );
|
xsheetpath->AddAttribute( "names", sheet.PathHumanReadable() );
|
||||||
xsheetpath->AddAttribute( "tstamps", sheet.PathAsString() );
|
xsheetpath->AddAttribute( "tstamps", sheet.PathAsString() );
|
||||||
xcomp->AddChild( node( "tstamp", symbol->m_Uuid.AsString() ) );
|
|
||||||
|
XNODE* xunits; // Node for extra units
|
||||||
|
xcomp->AddChild( xunits = node( "tstamps" ) );
|
||||||
|
|
||||||
|
auto range = extra_units.equal_range( symbol );
|
||||||
|
|
||||||
|
// Output a series of children with all UUIDs associated with the REFDES
|
||||||
|
for( auto it = range.first; it != range.second; ++it )
|
||||||
|
xunits->AddChild(
|
||||||
|
new XNODE( wxXML_TEXT_NODE, wxEmptyString, ( *it )->m_Uuid.AsString() ) );
|
||||||
|
|
||||||
|
// Output the primary UUID
|
||||||
|
xunits->AddChild(
|
||||||
|
new XNODE( wxXML_TEXT_NODE, wxEmptyString, symbol->m_Uuid.AsString() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,11 @@ public:
|
||||||
return m_uuid < rhs.m_uuid;
|
return m_uuid < rhs.m_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator>( KIID const& rhs ) const
|
||||||
|
{
|
||||||
|
return m_uuid > rhs.m_uuid;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::uuids::uuid m_uuid;
|
boost::uuids::uuid m_uuid;
|
||||||
|
|
||||||
|
|
|
@ -516,7 +516,7 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
||||||
continue; // Don't add board-only footprints to the netlist
|
continue; // Don't add board-only footprints to the netlist
|
||||||
|
|
||||||
COMPONENT* component = new COMPONENT( footprint->GetFPID(), footprint->GetReference(),
|
COMPONENT* component = new COMPONENT( footprint->GetFPID(), footprint->GetReference(),
|
||||||
footprint->GetValue(), footprint->GetPath() );
|
footprint->GetValue(), footprint->GetPath(), {} );
|
||||||
|
|
||||||
for( PAD* pad : footprint->Pads() )
|
for( PAD* pad : footprint->Pads() )
|
||||||
{
|
{
|
||||||
|
|
|
@ -645,7 +645,7 @@ bool DIALOG_BOARD_REANNOTATE::ReannotateBoard()
|
||||||
|
|
||||||
//add to the netlist
|
//add to the netlist
|
||||||
netlist.AddComponent( new COMPONENT( footprint->GetFPID(), newref->NewRefDes,
|
netlist.AddComponent( new COMPONENT( footprint->GetFPID(), newref->NewRefDes,
|
||||||
footprint->GetValue(), footprint->GetPath() ) );
|
footprint->GetValue(), footprint->GetPath(), { footprint->m_Uuid } ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
netlist.Format( "pcb_netlist", &stringformatter, 0,
|
netlist.Format( "pcb_netlist", &stringformatter, 0,
|
||||||
|
|
|
@ -289,18 +289,21 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for time stamp change.
|
// Test for time stamp change.
|
||||||
if( aPcbFootprint->GetPath() != aNetlistComponent->GetPath() )
|
KIID_PATH new_path = aNetlistComponent->GetPath();
|
||||||
|
new_path.push_back( aNetlistComponent->GetKIIDs().front() );
|
||||||
|
|
||||||
|
if( aPcbFootprint->GetPath() != new_path )
|
||||||
{
|
{
|
||||||
msg.Printf( _( "Update %s symbol association from %s to %s." ),
|
msg.Printf( _( "Update %s symbol association from %s to %s." ),
|
||||||
aPcbFootprint->GetReference(),
|
aPcbFootprint->GetReference(),
|
||||||
aPcbFootprint->GetPath().AsString(),
|
aPcbFootprint->GetPath().AsString(),
|
||||||
aNetlistComponent->GetPath().AsString() );
|
new_path.AsString() );
|
||||||
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
|
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
|
||||||
|
|
||||||
if( !m_isDryRun )
|
if( !m_isDryRun )
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
aPcbFootprint->SetPath( aNetlistComponent->GetPath() );
|
aPcbFootprint->SetPath( new_path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,7 +813,19 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
|
||||||
bool match = false;
|
bool match = false;
|
||||||
|
|
||||||
if( m_lookupByTimestamp )
|
if( m_lookupByTimestamp )
|
||||||
match = footprint->GetPath() == component->GetPath();
|
{
|
||||||
|
for( auto& uuid : component->GetKIIDs() )
|
||||||
|
{
|
||||||
|
KIID_PATH base = component->GetPath();
|
||||||
|
base.push_back( uuid );
|
||||||
|
|
||||||
|
if( footprint->GetPath() == base )
|
||||||
|
{
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
match = footprint->GetReference().CmpNoCase( component->GetReference() ) == 0;
|
match = footprint->GetReference().CmpNoCase( component->GetReference() ) == 0;
|
||||||
|
|
||||||
|
|
|
@ -308,7 +308,8 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
||||||
wxString library;
|
wxString library;
|
||||||
wxString name;
|
wxString name;
|
||||||
KIID_PATH path;
|
KIID_PATH path;
|
||||||
KIID uuid;
|
|
||||||
|
std::vector<KIID> uuids;
|
||||||
std::map<wxString, wxString> properties;
|
std::map<wxString, wxString> properties;
|
||||||
|
|
||||||
// The token comp was read, so the next data is (ref P1)
|
// The token comp was read, so the next data is (ref P1)
|
||||||
|
@ -414,10 +415,15 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
||||||
NeedRIGHT();
|
NeedRIGHT();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_tstamp:
|
case T_tstamps:
|
||||||
NeedSYMBOLorNUMBER();
|
while( ( token = NextTok() ) != T_EOF )
|
||||||
uuid = KIID( FROM_UTF8( CurText() ) );
|
{
|
||||||
NeedRIGHT();
|
if( token == T_RIGHT )
|
||||||
|
break;
|
||||||
|
|
||||||
|
uuids.emplace_back( FROM_UTF8( CurText() ) );
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -436,8 +442,7 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
||||||
THROW_IO_ERROR( error );
|
THROW_IO_ERROR( error );
|
||||||
}
|
}
|
||||||
|
|
||||||
path.push_back( uuid );
|
COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
|
||||||
COMPONENT* component = new COMPONENT( fpid, ref, value, path );
|
|
||||||
component->SetName( name );
|
component->SetName( name );
|
||||||
component->SetLibrary( library );
|
component->SetLibrary( library );
|
||||||
component->SetProperties( properties );
|
component->SetProperties( properties );
|
||||||
|
|
|
@ -168,7 +168,7 @@ COMPONENT* LEGACY_NETLIST_READER::loadComponent( char* aText )
|
||||||
if( !footprintName.IsEmpty() )
|
if( !footprintName.IsEmpty() )
|
||||||
fpid.SetLibItemName( footprintName );
|
fpid.SetLibItemName( footprintName );
|
||||||
|
|
||||||
COMPONENT* component = new COMPONENT( fpid, reference, value, path );
|
COMPONENT* component = new COMPONENT( fpid, reference, value, path, {} );
|
||||||
component->SetName( name );
|
component->SetName( name );
|
||||||
m_netlist->AddComponent( component );
|
m_netlist->AddComponent( component );
|
||||||
return component;
|
return component;
|
||||||
|
|
|
@ -161,9 +161,18 @@ void PCB_EDIT_FRAME::LoadFootprints( NETLIST& aNetlist, REPORTER& aReporter )
|
||||||
// Check if component footprint is already on BOARD and only load the footprint from
|
// Check if component footprint is already on BOARD and only load the footprint from
|
||||||
// the library if it's needed. Nickname can be blank.
|
// the library if it's needed. Nickname can be blank.
|
||||||
if( aNetlist.IsFindByTimeStamp() )
|
if( aNetlist.IsFindByTimeStamp() )
|
||||||
fpOnBoard = m_pcb->FindFootprintByPath( aNetlist.GetComponent( ii )->GetPath() );
|
{
|
||||||
|
for( const KIID& uuid : component->GetKIIDs() )
|
||||||
|
{
|
||||||
|
KIID_PATH path = component->GetPath();
|
||||||
|
path.push_back( uuid );
|
||||||
|
|
||||||
|
if( ( fpOnBoard = m_pcb->FindFootprintByPath( path ) ) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fpOnBoard = m_pcb->FindFootprintByReference( aNetlist.GetComponent( ii )->GetReference() );
|
fpOnBoard = m_pcb->FindFootprintByReference( component->GetReference() );
|
||||||
|
|
||||||
bool footprintMisMatch = fpOnBoard && fpOnBoard->GetFPID() != component->GetFPID();
|
bool footprintMisMatch = fpOnBoard && fpOnBoard->GetFPID() != component->GetFPID();
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,9 @@ int COMPONENT_NET::Format( OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl )
|
||||||
void COMPONENT::SetFootprint( FOOTPRINT* aFootprint )
|
void COMPONENT::SetFootprint( FOOTPRINT* aFootprint )
|
||||||
{
|
{
|
||||||
m_footprint.reset( aFootprint );
|
m_footprint.reset( aFootprint );
|
||||||
|
KIID_PATH path = m_path;
|
||||||
|
|
||||||
|
path.push_back( m_kiids.front() );
|
||||||
|
|
||||||
if( aFootprint == NULL )
|
if( aFootprint == NULL )
|
||||||
return;
|
return;
|
||||||
|
@ -47,7 +50,7 @@ void COMPONENT::SetFootprint( FOOTPRINT* aFootprint )
|
||||||
aFootprint->SetReference( m_reference );
|
aFootprint->SetReference( m_reference );
|
||||||
aFootprint->SetValue( m_value );
|
aFootprint->SetValue( m_value );
|
||||||
aFootprint->SetFPID( m_fpid );
|
aFootprint->SetFPID( m_fpid );
|
||||||
aFootprint->SetPath( m_path );
|
aFootprint->SetPath( path );
|
||||||
aFootprint->SetProperties( m_properties );
|
aFootprint->SetProperties( m_properties );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +88,9 @@ void COMPONENT::Format( OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl )
|
||||||
for( const KIID& pathStep : m_path )
|
for( const KIID& pathStep : m_path )
|
||||||
path += '/' + pathStep.AsString();
|
path += '/' + pathStep.AsString();
|
||||||
|
|
||||||
|
if( !m_kiids.empty() )
|
||||||
|
path += '/' + m_kiids.front().AsString();
|
||||||
|
|
||||||
aOut->Print( nl+1, "(timestamp %s)\n", aOut->Quotew( path ).c_str() );
|
aOut->Print( nl+1, "(timestamp %s)\n", aOut->Quotew( path ).c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,9 +166,20 @@ COMPONENT* NETLIST::GetComponentByReference( const wxString& aReference )
|
||||||
|
|
||||||
COMPONENT* NETLIST::GetComponentByPath( const KIID_PATH& aUuidPath )
|
COMPONENT* NETLIST::GetComponentByPath( const KIID_PATH& aUuidPath )
|
||||||
{
|
{
|
||||||
|
KIID comp_uuid = aUuidPath.back();
|
||||||
|
KIID_PATH base = aUuidPath;
|
||||||
|
|
||||||
|
if( !base.empty() )
|
||||||
|
base.pop_back();
|
||||||
|
|
||||||
for( COMPONENT& component : m_components )
|
for( COMPONENT& component : m_components )
|
||||||
{
|
{
|
||||||
if( component.GetPath() == aUuidPath )
|
const std::vector<KIID>& kiids = component.GetKIIDs();
|
||||||
|
|
||||||
|
if( base != component.GetPath() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( std::find( kiids.begin(), kiids.end(), comp_uuid ) != kiids.end() )
|
||||||
return &component;
|
return &component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,12 @@ class COMPONENT
|
||||||
wxString m_reference; ///< The component reference designator found in netlist.
|
wxString m_reference; ///< The component reference designator found in netlist.
|
||||||
wxString m_value; ///< The component value found in netlist.
|
wxString m_value; ///< The component value found in netlist.
|
||||||
|
|
||||||
/// A fully specified path to the component: [ sheetUUID, sheetUUID, .., componentUUID ]
|
/// A fully specified path to the component (but not the component: [ sheetUUID, sheetUUID, .. ]
|
||||||
KIID_PATH m_path;
|
KIID_PATH m_path;
|
||||||
|
|
||||||
|
/// A vector of possible KIIDs corresponding to all units in a symbol
|
||||||
|
std::vector<KIID> m_kiids;
|
||||||
|
|
||||||
/// The name of the component in #m_library used when it was placed on the schematic..
|
/// The name of the component in #m_library used when it was placed on the schematic..
|
||||||
wxString m_name;
|
wxString m_name;
|
||||||
|
|
||||||
|
@ -119,13 +122,15 @@ public:
|
||||||
COMPONENT( const LIB_ID& aFPID,
|
COMPONENT( const LIB_ID& aFPID,
|
||||||
const wxString& aReference,
|
const wxString& aReference,
|
||||||
const wxString& aValue,
|
const wxString& aValue,
|
||||||
const KIID_PATH& aPath )
|
const KIID_PATH& aPath,
|
||||||
|
const std::vector<KIID>& aKiids )
|
||||||
{
|
{
|
||||||
m_fpid = aFPID;
|
m_fpid = aFPID;
|
||||||
m_reference = aReference;
|
m_reference = aReference;
|
||||||
m_value = aValue;
|
m_value = aValue;
|
||||||
m_pinCount = 0;
|
m_pinCount = 0;
|
||||||
m_path = aPath;
|
m_path = aPath;
|
||||||
|
m_kiids = aKiids;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~COMPONENT() { };
|
virtual ~COMPONENT() { };
|
||||||
|
@ -167,6 +172,8 @@ public:
|
||||||
|
|
||||||
const KIID_PATH& GetPath() const { return m_path; }
|
const KIID_PATH& GetPath() const { return m_path; }
|
||||||
|
|
||||||
|
const std::vector<KIID>& GetKIIDs() const { return m_kiids; }
|
||||||
|
|
||||||
void SetFootprintFilters( const wxArrayString& aFilters ) { m_footprintFilters = aFilters; }
|
void SetFootprintFilters( const wxArrayString& aFilters ) { m_footprintFilters = aFilters; }
|
||||||
const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; }
|
const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue