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 <set>
|
||||
|
||||
static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 );
|
||||
|
||||
|
@ -52,7 +53,7 @@ XNODE* NETLIST_EXPORTER_XML::makeRoot( unsigned aCtl )
|
|||
{
|
||||
XNODE* xroot = node( "export" );
|
||||
|
||||
xroot->AddAttribute( "version", "D" );
|
||||
xroot->AddAttribute( "version", "E" );
|
||||
|
||||
if( aCtl & GNL_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::multiset<SCH_COMPONENT*, decltype( cmp )> extra_units( cmp );
|
||||
|
||||
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.first ) )->GetUnit() > symbol->GetUnit() )
|
||||
if( ( *( test.first ) )->m_Uuid > symbol->m_Uuid )
|
||||
{
|
||||
extra_units.insert( *( test.first ) );
|
||||
ordered_symbols.erase( test.first );
|
||||
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( "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;
|
||||
}
|
||||
|
||||
bool operator>( KIID const& rhs ) const
|
||||
{
|
||||
return m_uuid > rhs.m_uuid;
|
||||
}
|
||||
|
||||
private:
|
||||
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
|
||||
|
||||
COMPONENT* component = new COMPONENT( footprint->GetFPID(), footprint->GetReference(),
|
||||
footprint->GetValue(), footprint->GetPath() );
|
||||
footprint->GetValue(), footprint->GetPath(), {} );
|
||||
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
{
|
||||
|
|
|
@ -645,7 +645,7 @@ bool DIALOG_BOARD_REANNOTATE::ReannotateBoard()
|
|||
|
||||
//add to the netlist
|
||||
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,
|
||||
|
|
|
@ -289,18 +289,21 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
|
|||
}
|
||||
|
||||
// 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." ),
|
||||
aPcbFootprint->GetReference(),
|
||||
aPcbFootprint->GetPath().AsString(),
|
||||
aNetlistComponent->GetPath().AsString() );
|
||||
new_path.AsString() );
|
||||
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
|
||||
|
||||
if( !m_isDryRun )
|
||||
{
|
||||
changed = true;
|
||||
aPcbFootprint->SetPath( aNetlistComponent->GetPath() );
|
||||
aPcbFootprint->SetPath( new_path );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -810,7 +813,19 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
|
|||
bool match = false;
|
||||
|
||||
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
|
||||
match = footprint->GetReference().CmpNoCase( component->GetReference() ) == 0;
|
||||
|
||||
|
|
|
@ -308,7 +308,8 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
|||
wxString library;
|
||||
wxString name;
|
||||
KIID_PATH path;
|
||||
KIID uuid;
|
||||
|
||||
std::vector<KIID> uuids;
|
||||
std::map<wxString, wxString> properties;
|
||||
|
||||
// The token comp was read, so the next data is (ref P1)
|
||||
|
@ -414,10 +415,15 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
|||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_tstamp:
|
||||
NeedSYMBOLorNUMBER();
|
||||
uuid = KIID( FROM_UTF8( CurText() ) );
|
||||
NeedRIGHT();
|
||||
case T_tstamps:
|
||||
while( ( token = NextTok() ) != T_EOF )
|
||||
{
|
||||
if( token == T_RIGHT )
|
||||
break;
|
||||
|
||||
uuids.emplace_back( FROM_UTF8( CurText() ) );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -436,8 +442,7 @@ void KICAD_NETLIST_PARSER::parseComponent()
|
|||
THROW_IO_ERROR( error );
|
||||
}
|
||||
|
||||
path.push_back( uuid );
|
||||
COMPONENT* component = new COMPONENT( fpid, ref, value, path );
|
||||
COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
|
||||
component->SetName( name );
|
||||
component->SetLibrary( library );
|
||||
component->SetProperties( properties );
|
||||
|
|
|
@ -168,7 +168,7 @@ COMPONENT* LEGACY_NETLIST_READER::loadComponent( char* aText )
|
|||
if( !footprintName.IsEmpty() )
|
||||
fpid.SetLibItemName( footprintName );
|
||||
|
||||
COMPONENT* component = new COMPONENT( fpid, reference, value, path );
|
||||
COMPONENT* component = new COMPONENT( fpid, reference, value, path, {} );
|
||||
component->SetName( name );
|
||||
m_netlist->AddComponent( 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
|
||||
// the library if it's needed. Nickname can be blank.
|
||||
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
|
||||
fpOnBoard = m_pcb->FindFootprintByReference( aNetlist.GetComponent( ii )->GetReference() );
|
||||
fpOnBoard = m_pcb->FindFootprintByReference( component->GetReference() );
|
||||
|
||||
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 )
|
||||
{
|
||||
m_footprint.reset( aFootprint );
|
||||
KIID_PATH path = m_path;
|
||||
|
||||
path.push_back( m_kiids.front() );
|
||||
|
||||
if( aFootprint == NULL )
|
||||
return;
|
||||
|
@ -47,7 +50,7 @@ void COMPONENT::SetFootprint( FOOTPRINT* aFootprint )
|
|||
aFootprint->SetReference( m_reference );
|
||||
aFootprint->SetValue( m_value );
|
||||
aFootprint->SetFPID( m_fpid );
|
||||
aFootprint->SetPath( m_path );
|
||||
aFootprint->SetPath( path );
|
||||
aFootprint->SetProperties( m_properties );
|
||||
}
|
||||
|
||||
|
@ -85,6 +88,9 @@ void COMPONENT::Format( OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl )
|
|||
for( const KIID& pathStep : m_path )
|
||||
path += '/' + pathStep.AsString();
|
||||
|
||||
if( !m_kiids.empty() )
|
||||
path += '/' + m_kiids.front().AsString();
|
||||
|
||||
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 )
|
||||
{
|
||||
KIID comp_uuid = aUuidPath.back();
|
||||
KIID_PATH base = aUuidPath;
|
||||
|
||||
if( !base.empty() )
|
||||
base.pop_back();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,9 +90,12 @@ class COMPONENT
|
|||
wxString m_reference; ///< The component reference designator 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;
|
||||
|
||||
/// 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..
|
||||
wxString m_name;
|
||||
|
||||
|
@ -116,16 +119,18 @@ class COMPONENT
|
|||
static COMPONENT_NET m_emptyNet;
|
||||
|
||||
public:
|
||||
COMPONENT( const LIB_ID& aFPID,
|
||||
const wxString& aReference,
|
||||
const wxString& aValue,
|
||||
const KIID_PATH& aPath )
|
||||
COMPONENT( const LIB_ID& aFPID,
|
||||
const wxString& aReference,
|
||||
const wxString& aValue,
|
||||
const KIID_PATH& aPath,
|
||||
const std::vector<KIID>& aKiids )
|
||||
{
|
||||
m_fpid = aFPID;
|
||||
m_reference = aReference;
|
||||
m_value = aValue;
|
||||
m_pinCount = 0;
|
||||
m_path = aPath;
|
||||
m_kiids = aKiids;
|
||||
}
|
||||
|
||||
virtual ~COMPONENT() { };
|
||||
|
@ -167,6 +172,8 @@ public:
|
|||
|
||||
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; }
|
||||
const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue