void PCB_EDIT_FRAME::LoadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) { wxString msg; LIB_ID lastFPID; COMPONENT* component; MODULE* module = 0; MODULE* fpOnBoard; if( aNetlist.IsEmpty() || Prj().PcbFootprintLibs()->IsEmpty() ) return; aNetlist.SortByFPID(); for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ ) { component = aNetlist.GetComponent( ii ); #if ALLOW_PARTIAL_FPID // The FPID is ok as long as there is a footprint portion coming // from eeschema. if( !component->GetFPID().GetLibItemName().size() ) #else if( component->GetFPID().empty() ) #endif { if( aReporter ) { msg.Printf( _( "No footprint defined for symbol \"%s\".\n" ), GetChars( component->GetReference() ) ); aReporter->Report( msg, REPORTER::RPT_ERROR ); } continue; } // 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->FindModule( aNetlist.GetComponent( ii )->GetTimeStamp(), true ); else fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetReference() ); bool footprintMisMatch = fpOnBoard && fpOnBoard->GetFPID() != component->GetFPID(); if( footprintMisMatch && !aNetlist.GetReplaceFootprints() ) { if( aReporter ) { msg.Printf( _( "Footprint of symbol \"%s\" changed: board footprint \"%s\", netlist footprint \"%s\"\n" ), GetChars( component->GetReference() ), GetChars( fpOnBoard->GetFPID().Format() ), GetChars( component->GetFPID().Format() ) ); aReporter->Report( msg, REPORTER::RPT_WARNING ); } continue; } if( !aNetlist.GetReplaceFootprints() ) footprintMisMatch = false; if( fpOnBoard && !footprintMisMatch ) // nothing else to do here continue; if( component->GetFPID() != lastFPID ) { module = NULL; #if ALLOW_PARTIAL_FPID // The LIB_ID is ok as long as there is a footprint portion coming // the library if it's needed. Nickname can be blank. if( !component->GetFPID().GetLibItemName().size() ) #else if( !component->GetFPID().IsValid() ) #endif { if( aReporter ) { msg.Printf( _( "Component \"%s\" footprint ID \"%s\" is not " "valid.\n" ), GetChars( component->GetReference() ), GetChars( component->GetFPID().Format() ) ); aReporter->Report( msg, REPORTER::RPT_ERROR ); } continue; } // loadFootprint() can find a footprint with an empty nickname in fpid. module = PCB_BASE_FRAME::loadFootprint( component->GetFPID() ); if( module ) { lastFPID = component->GetFPID(); } else { if( aReporter ) { msg.Printf( _( "Component \"%s\" footprint \"%s\" was not found in " "any libraries in the footprint library table.\n" ), GetChars( component->GetReference() ), GetChars( component->GetFPID().GetLibItemName() ) ); aReporter->Report( msg, REPORTER::RPT_ERROR ); } continue; } } else { // Footprint already loaded from a library, duplicate it (faster) if( module == NULL ) continue; // Module does not exist in any library. module = new MODULE( *module ); } if( module ) component->SetModule( module ); } }
bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) { wxString msg; m_errorCount = 0; m_warningCount = 0; if( !m_isDryRun ) { m_board->SetStatus( 0 ); } for( int i = 0; i < (int) aNetlist.GetCount(); i++ ) { COMPONENT* component = aNetlist.GetComponent( i ); MODULE* footprint = NULL; msg.Printf( _( "Processing component \"%s:%s:%s\".\n" ), GetChars( component->GetReference() ), GetChars( component->GetTimeStamp() ), GetChars( component->GetFPID().Format() ) ); m_reporter->Report( msg, REPORTER::RPT_INFO ); if( aNetlist.IsFindByTimeStamp() ) footprint = m_board->FindModule( component->GetTimeStamp(), true ); else footprint = m_board->FindModule( component->GetReference() ); if( footprint ) // An existing footprint. { MODULE* newFootprint = replaceComponent( aNetlist, footprint, component ); if( newFootprint ) footprint = newFootprint; } else { footprint = addNewComponent( component ); } if( footprint ) { updateComponentParameters( footprint, component ); updateComponentPadConnections( footprint, component ); } } //aNetlist.GetDeleteExtraFootprints() if( m_deleteUnusedComponents ) deleteUnusedComponents( aNetlist ); if( m_deleteSinglePadNets ) deleteSinglePadNets(); if( !m_isDryRun ) { m_commit.Push( _( "Update netlist" ) ); m_frame->Compile_Ratsnest( NULL, false ); m_board->GetRatsnest()->ProcessBoard(); testConnectivity( aNetlist ); } // Update the ratsnest m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION ); m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION ); msg.Printf( _( "Total warnings: %d, errors: %d." ), m_warningCount, m_errorCount ); m_reporter->Report( msg, REPORTER::RPT_ACTION ); if( m_errorCount ) { m_reporter->Report( _( "Errors occured during the netlist update. Unless you " "fix them, your board will not be consistent with the schematics." ), REPORTER::RPT_ERROR ); return false; } else { m_reporter->Report( _( "Netlist update successful!" ), REPORTER::RPT_ACTION ); } return true; }
bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist ) { // Last step: Some tests: // verify all pads found in netlist: // They should exist in footprints, otherwise the footprint is wrong // note also references or time stamps are updated, so we use only // the reference to find a footprint // // Also verify if zones have acceptable nets, i.e. nets with pads. // Zone with no pad belongs to a "dead" net which happens after changes in schematic // when no more pad use this net name. wxString msg; wxString padname; for( int i = 0; i < (int) aNetlist.GetCount(); i++ ) { const COMPONENT* component = aNetlist.GetComponent( i ); MODULE* footprint = m_board->FindModuleByReference( component->GetReference() ); if( footprint == NULL ) // It can be missing in partial designs continue; // Explore all pins/pads in component for( unsigned jj = 0; jj < component->GetNetCount(); jj++ ) { COMPONENT_NET net = component->GetNet( jj ); padname = net.GetPinName(); if( footprint->FindPadByName( padname ) ) continue; // OK, pad found // not found: bad footprint, report error msg.Printf( _( "Component %s pad %s not found in footprint %s\n" ), GetChars( component->GetReference() ), GetChars( padname ), GetChars( footprint->GetFPID().Format() ) ); m_reporter->Report( msg, REPORTER::RPT_ERROR ); ++m_errorCount; } } // Test copper zones to detect "dead" nets (nets without any pad): for( int i = 0; i < m_board->GetAreaCount(); i++ ) { ZONE_CONTAINER* zone = m_board->GetArea( i ); if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() ) continue; int nc = zone->GetNet()->GetNodesCount(); if( nc == 0 ) { msg.Printf( _( "Copper zone (net name %s): net has no pads connected." ), GetChars( zone->GetNet()->GetNetname() ) ); m_reporter->Report( msg, REPORTER::RPT_WARNING ); ++m_warningCount; } } return true; }
void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) throw( IO_ERROR, PARSE_ERROR ) { wxString msg; FPID lastFPID; COMPONENT* component; MODULE* module = 0; MODULE* fpOnBoard; if( aNetlist.IsEmpty() || FootprintLibs()->IsEmpty() ) return; aNetlist.SortByFPID(); for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ ) { component = aNetlist.GetComponent( ii ); #if ALLOW_PARTIAL_FPID // The FPID is ok as long as there is a footprint portion coming // from eeschema. if( !component->GetFPID().GetFootprintName().size() ) #else if( component->GetFPID().empty() ) #endif { if( aReporter ) { msg.Printf( _( "No footprint defined for component '%s'.\n" ), GetChars( component->GetReference() ) ); aReporter->Report( msg ); } continue; } // 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->FindModule( aNetlist.GetComponent( ii )->GetTimeStamp(), true ); else fpOnBoard = m_Pcb->FindModule( aNetlist.GetComponent( ii )->GetReference() ); bool footprintMisMatch = fpOnBoard && fpOnBoard->GetFPID() != component->GetFPID(); if( footprintMisMatch && !aNetlist.GetReplaceFootprints() ) { if( aReporter ) { msg.Printf( _( "* Warning: component '%s' has footprint '%s' and should be '%s'\n" ), GetChars( component->GetReference() ), fpOnBoard->GetFPID().GetFootprintName().c_str(), component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } continue; } if( !aNetlist.GetReplaceFootprints() ) footprintMisMatch = false; bool loadFootprint = (fpOnBoard == NULL) || footprintMisMatch; if( loadFootprint && (component->GetFPID() != lastFPID) ) { module = NULL; #if ALLOW_PARTIAL_FPID // The FPID is ok as long as there is a footprint portion coming // the library if it's needed. Nickname can be blank. if( !component->GetFPID().GetFootprintName().size() ) #else if( !component->GetFPID().IsValid() ) #endif { if( aReporter ) { msg.Printf( _( "*** Warning: Component '%s' footprint ID '%s' is not " "valid. ***\n" ), GetChars( component->GetReference() ), component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } continue; } // loadFootprint() can find a footprint with an empty nickname in fpid. module = PCB_BASE_FRAME::loadFootprint( component->GetFPID() ); if( module ) { lastFPID = component->GetFPID(); } else { if( aReporter ) { wxString msg; msg.Printf( _( "*** Warning: component '%s' footprint '%s' was not found in " "any libraries in the footprint library table. ***\n" ), GetChars( component->GetReference() ), component->GetFPID().GetFootprintName().c_str() ); aReporter->Report( msg ); } continue; } } else { // Footprint already loaded from a library, duplicate it (faster) if( module == NULL ) continue; // Module does not exist in any library. module = new MODULE( *module ); } if( loadFootprint && module != NULL ) component->SetModule( module ); } }
bool DIALOG_NETLIST::verifyFootprints( const wxString& aNetlistFilename, const wxString & aCmpFilename, std::vector< MODULE* >& aDuplicates, wxArrayString& aMissing, std::vector< MODULE* >& aNotInNetlist ) { wxString msg; MODULE* module; MODULE* nextModule; NETLIST netlist; wxBusyCursor dummy; // Shows an hourglass while calculating. NETLIST_READER* netlistReader; COMPONENT* component; try { netlistReader = NETLIST_READER::GetNetlistReader( &netlist, aNetlistFilename, aCmpFilename ); if( netlistReader == NULL ) { msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFilename ) ); wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR ); return false; } std::auto_ptr< NETLIST_READER > nlr( netlistReader ); netlistReader->LoadNetlist(); } catch( const IO_ERROR& ioe ) { msg.Printf( _( "Error loading netlist file:\n%s" ), ioe.errorText.GetData() ); wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR ); return false; } BOARD* pcb = m_parent->GetBoard(); // Search for duplicate footprints. module = pcb->m_Modules; for( ; module != NULL; module = module->Next() ) { nextModule = module->Next(); for( ; nextModule != NULL; nextModule = nextModule->Next() ) { if( module->GetReference().CmpNoCase( nextModule->GetReference() ) == 0 ) { aDuplicates.push_back( module ); break; } } } // Search for component footprints in the netlist but not on the board. for( unsigned ii = 0; ii < netlist.GetCount(); ii++ ) { component = netlist.GetComponent( ii ); module = pcb->FindModuleByReference( component->GetReference() ); if( module == NULL ) { aMissing.Add( component->GetReference() ); aMissing.Add( component->GetValue() ); } } // Search for component footprints found on board but not in netlist. module = pcb->m_Modules; for( ; module != NULL; module = module->Next() ) { component = netlist.GetComponentByReference( module->GetReference() ); if( component == NULL ) aNotInNetlist.push_back( module ); } return true; }
/** * Function convertFromLegacy * converts the footprint names in \a aNetList from the legacy format to the #FPID format. * * @param aNetList is the #NETLIST object to convert. * @param aLibNames is the list of legacy footprint library names from the currently loaded * project. * @param aReporter is the #REPORTER object to dump messages into. * @return true if all footprint names were successfully converted to a valid FPID. */ static bool convertFromLegacy( FP_LIB_TABLE* aTbl, SEARCH_STACK& aSStack, NETLIST& aNetList, const wxArrayString& aLibNames, REPORTER* aReporter = NULL ) throw( IO_ERROR ) { wxString msg; FPID lastFPID; COMPONENT* component; MODULE* module = 0; bool retv = true; if( aNetList.IsEmpty() ) return true; aNetList.SortByFPID(); wxString libPath; PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); for( unsigned ii = 0; ii < aNetList.GetCount(); ii++ ) { component = aNetList.GetComponent( ii ); // The footprint hasn't been assigned yet so ignore it. if( component->GetFPID().empty() ) continue; if( component->GetFPID() != lastFPID ) { module = NULL; for( unsigned ii = 0; ii < aLibNames.GetCount(); ii++ ) { wxFileName fn( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension ); libPath = aSStack.FindValidPath( fn.GetFullPath() ); if( !libPath ) { if( aReporter ) { msg.Printf( _( "Cannot find footprint library file '%s' in any of the " "KiCad legacy library search paths.\n" ), GetChars( fn.GetFullPath() ) ); aReporter->Report( msg ); } retv = false; continue; } module = pi->FootprintLoad( libPath, component->GetFPID().GetFootprintName() ); if( module ) { lastFPID = component->GetFPID(); break; } } } if( !module ) { if( aReporter ) { msg.Printf( _( "Component '%s' footprint '%s' was not found in any legacy " "library.\n" ), GetChars( component->GetReference() ), GetChars( component->GetFPID().Format() ) ); aReporter->Report( msg ); } // Clear the footprint assignment since the old library lookup method is no // longer valid. FPID emptyFPID; component->SetFPID( emptyFPID ); retv = false; continue; } else { wxString libNickname; const FP_LIB_TABLE::ROW* row; if( ( row = aTbl->FindRowByURI( libPath ) ) != NULL ) libNickname = row->GetNickName(); if( libNickname.IsEmpty() ) { if( aReporter ) { msg.Printf( _( "Component '%s' with footprint '%s' and legacy library path '%s' " "was not found in the footprint library table.\n" ), GetChars( component->GetReference() ), GetChars( component->GetFPID().Format() ), GetChars( libPath ) ); aReporter->Report( msg ); } retv = false; } else { FPID newFPID = lastFPID; newFPID.SetLibNickname( libNickname ); if( !newFPID.IsValid() ) { if( aReporter ) { msg.Printf( _( "Component '%s' FPID '%s' is not valid.\n" ), GetChars( component->GetReference() ), GetChars( newFPID.Format() ) ); aReporter->Report( msg ); } retv = false; } else { // The footprint name should already be set. component->SetFPID( newFPID ); } } } } return retv; }