From e7ed41593022b7ed33b78489783b09d509625994 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 6 Apr 2018 15:56:32 +0200 Subject: [PATCH] Eagle SCH import: handle implicit connections Each named power input pin in Eagle creates an implicit connection to a net with the name of the pin (e.g. GND, VCC). It is also done for the units (gates in Eagle nomenclature) that have not been instantiated in the schematics. To emulate this behaviour in KiCad: - Placed components are checked for power input pins, so they will have global net labels attached to create the described implicit connections. - As the components are placed, the remaining units of the symbol are checked for power inputs to see if they need to be instantiated together with global net labels. Fixes: lp:1755191 * https://bugs.launchpad.net/kicad/+bug/1755191 --- eeschema/sch_eagle_plugin.cpp | 135 ++++++++++++++++++++++++++++++++++ eeschema/sch_eagle_plugin.h | 37 ++++++++++ 2 files changed, 172 insertions(+) diff --git a/eeschema/sch_eagle_plugin.cpp b/eeschema/sch_eagle_plugin.cpp index f66fc30606..d6f54ee013 100644 --- a/eeschema/sch_eagle_plugin.cpp +++ b/eeschema/sch_eagle_plugin.cpp @@ -107,6 +107,13 @@ static EDA_RECT getSheetBbox( SCH_SHEET* aSheet ) } +///> Extracts the net name part from a pin name (e.g. return 'GND' for pin named 'GND@2') +static inline wxString extractNetName( const wxString& aPinName ) +{ + return aPinName.BeforeFirst( '@' ); +} + + wxString SCH_EAGLE_PLUGIN::getLibName() { if( m_libName.IsEmpty() ) @@ -590,6 +597,57 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode ) sheetNode = sheetNode->GetNext(); } } + + + // Handle the missing component units that need to be instantiated + // to create the missing implicit connections + + // Calculate the already placed items bounding box and the page size to determine + // placement for the new components + wxSize pageSizeIU = m_rootSheet->GetScreen()->GetPageSettings().GetSizeIU(); + EDA_RECT sheetBbox = getSheetBbox( m_rootSheet ); + wxPoint newCmpPosition( sheetBbox.GetLeft(), sheetBbox.GetBottom() ); + int maxY = sheetBbox.GetY(); + + SCH_SHEET_PATH sheetpath; + m_rootSheet->LocatePathOfScreen( m_rootSheet->GetScreen(), &sheetpath ); + + for( auto& cmp : m_missingCmps ) + { + const SCH_COMPONENT* origCmp = cmp.second.cmp; + + for( auto unitEntry : cmp.second.units ) + { + if( unitEntry.second == false ) + continue; // unit has been already processed + + // Instantiate the missing component unit + int unit = unitEntry.first; + const wxString& reference = origCmp->GetField( REFERENCE )->GetText(); + std::unique_ptr component( new SCH_COMPONENT( *origCmp ) ); + component->SetUnitSelection( &sheetpath, unit ); + component->SetUnit( unit ); + component->SetTimeStamp( EagleModuleTstamp( reference, origCmp->GetField( VALUE )->GetText(), unit ) ); + component->SetOrientation( 0 ); + component->AddHierarchicalReference( sheetpath.Path(), reference, unit ); + + // Calculate the placement position + EDA_RECT cmpBbox = component->GetBoundingBox(); + int posY = newCmpPosition.y + cmpBbox.GetHeight(); + component->SetPosition( wxPoint( newCmpPosition.x, posY ) ); + newCmpPosition.x += cmpBbox.GetWidth(); + maxY = std::max( maxY, posY ); + + if( newCmpPosition.x >= pageSizeIU.GetWidth() ) // reached the page boundary? + newCmpPosition = wxPoint( sheetBbox.GetLeft(), maxY ); // then start a new row + + // Add the global net labels to recreate the implicit connections + addImplicitConnections( component.get(), m_rootSheet->GetScreen(), false ); + m_rootSheet->GetScreen()->Append( component.release() ); + } + } + + m_missingCmps.clear(); } @@ -735,6 +793,15 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex ) item->SetPosition( item->GetPosition() + translation ); item->ClearFlags(); } + + // Add global net labels for the named power input pins in this sheet + for( SCH_ITEM* item = m_currentSheet->GetScreen()->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + addImplicitConnections( static_cast( item ), m_currentSheet->GetScreen(), true ); + } } @@ -2400,3 +2467,71 @@ const SEG* SCH_EAGLE_PLUGIN::SEG_DESC::LabelAttached( const SCH_TEXT* aLabel ) c return nullptr; } + + +void SCH_EAGLE_PLUGIN::addImplicitConnections( SCH_COMPONENT* aComponent, + SCH_SCREEN* aScreen, bool aUpdateSet ) +{ + auto& schLibTable = *m_kiway->Prj().SchSymbolLibTable(); + wxCHECK( aComponent->Resolve( schLibTable ), /*void*/ ); + aComponent->UpdatePinCache(); + auto partRef = aComponent->GetPartRef().lock(); + wxCHECK( partRef, /*void*/ ); + + // Normally power parts also have power input pins, + // but they already force net names on the attached wires + if( partRef->IsPower() ) + return; + + int unit = aComponent->GetUnit(); + const wxString& reference = aComponent->GetField( REFERENCE )->GetText(); + std::vector pins; + partRef->GetPins( pins ); + std::set missingUnits; + + // Search all units for pins creating implicit connections + for( const auto& pin : pins ) + { + if( pin->GetType() == PIN_POWER_IN ) + { + if( !unit || pin->GetUnit() == unit ) + { + // Create a net label to force the net name on the pin + SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL; + netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) ); + netLabel->SetText( extractNetName( pin->GetName() ) ); + netLabel->SetTextSize( wxSize( 10, 10 ) ); + netLabel->SetLabelSpinStyle( 0 ); + aScreen->Append( netLabel ); + } + + else if( aUpdateSet ) + { + // Found a pin creating implicit connection information in another unit. + // Such units will be instantiated if they do not appear in another sheet and + // processed later. + wxASSERT( pin->GetUnit() ); + missingUnits.insert( pin->GetUnit() ); + } + } + } + + if( aUpdateSet ) + { + auto cmpIt = m_missingCmps.find( reference ); + + // Set the flag indicating this unit has been processed + if( cmpIt != m_missingCmps.end() ) + cmpIt->second.units[unit] = false; + + // Save the units that need later processing + else if( !missingUnits.empty() ) + { + EAGLE_MISSING_CMP& entry = m_missingCmps[reference]; + entry.cmp = aComponent; + + for( int i : missingUnits ) + entry.units.emplace( i, true ); + } + } +} diff --git a/eeschema/sch_eagle_plugin.h b/eeschema/sch_eagle_plugin.h index 5397e640c1..2227a8bdf6 100644 --- a/eeschema/sch_eagle_plugin.h +++ b/eeschema/sch_eagle_plugin.h @@ -208,6 +208,43 @@ private: ///> Segments representing wires for intersection checking std::vector m_segments; + + + // Structure describing missing units containing pins creating implicit connections + // (named power pins in Eagle). + struct EAGLE_MISSING_CMP + { + EAGLE_MISSING_CMP( const SCH_COMPONENT* aComponent = nullptr ) + : cmp( aComponent ) + { + } + + ///> Link to the parent component + const SCH_COMPONENT* cmp; + + /* Map of the component units: for each unit there is a flag saying + * whether the unit needs to be instantiated with appropriate net labels to + * emulate implicit connections as is done in Eagle. + */ + std::map units; + }; + + ///> Map references to missing component units data + std::map m_missingCmps; + + /** + * Creates net labels to emulate implicit connections in Eagle. + * + * Each named power input pin creates an implicit connection in Eagle. To emulate this behavior + * one needs to attach global net labels to the mentioned pins. This is is also expected for the + * units that are not instantiated in the schematics, therefore such units need to be stored + * in order to create them at later stage. + * + * @param aComponent is the component to process. + * @param aScreen is the screen where net labels should be added. + * @param aUpdateSet decides whether the missing units data should be updated. + */ + void addImplicitConnections( SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen, bool aUpdateSet ); }; #endif // _SCH_EAGLE_PLUGIN_H_