|
|
/**
* @file pcbnew/netlist_reader_common.cpp *//*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 1992-2011 Jean-Pierre Charras. * Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
#include <fctsys.h>
#include <wxPcbStruct.h>
#include <richio.h>
#include <macros.h>
#include <class_board.h>
#include <class_module.h>
#include <pcbnew.h>
#include <netlist_reader.h>
#include <algorithm>
/*
* Function ReadNetList * The main function to detect the netlist format,and run the right netlist reader * aFile = the already opened file (will be closed by the netlist reader) */bool NETLIST_READER::ReadNetList( FILE* aFile ){ // Try to determine the netlist type:
// Beginning of the first line of known formats, without spaces
#define HEADERS_COUNT 3
#define HEADER_ORCADPCB "({EESchemaNetlist"
#define HEADER_PCBNEW "#EESchemaNetlist"
#define HEADER_KICAD_NETFMT "(export"
const std::string headers[HEADERS_COUNT] = { HEADER_ORCADPCB, HEADER_PCBNEW, HEADER_KICAD_NETFMT };
int format = -1; for ( int jj = 0; jj < HEADERS_COUNT; jj++ ) { int imax = headers[jj].size(); int ii = 0; for( ; ii < imax; ii++ ) { int data; // Read header, and skip blanks to avoid errors if an header changes
do { data = fgetc( aFile ); } while ( ( data == ' ' ) &&( EOF != data ) ) ;
if( (int)headers[jj][ii] == data ) continue; break; } if( ii == imax ) // header found
{ format = jj; break; } rewind( aFile ); }
rewind( aFile ); bool success = false; switch( format ) { case 0: m_typeNetlist = NETLIST_TYPE_ORCADPCB2; success = ReadOldFmtdNetList( aFile ); break;
case 1: m_typeNetlist = NETLIST_TYPE_PCBNEW; success = ReadOldFmtdNetList( aFile ); break;
case 2: m_typeNetlist = NETLIST_TYPE_KICAD; success = ReadKicadNetList( aFile ); break;
default: // Unrecognized format:
break;
}
return success;}
/**
* Function GetComponentInfoList * @return a reference to the libpart info corresponding to a given part * @param aPartname = the name of the libpart */LIPBART_INFO* NETLIST_READER::GetLibpart(const wxString & aPartname){ for( unsigned ii = 0; ii < m_libpartList.size(); ii++ ) { if( m_libpartList[ii]->m_Libpart == aPartname ) return m_libpartList[ii]; }
return NULL;}
bool NETLIST_READER::InitializeModules(){ if( m_UseCmpFile ) // Try to get footprint name from .cmp file
{ readModuleComponentLinkfile(); }
if( m_pcbframe == NULL ) return true;
for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ ) { COMPONENT_INFO* currcmp_info = m_componentsInNetlist[ii]; // Test if module is already loaded.
wxString * idMod = m_UseTimeStamp? &currcmp_info->m_TimeStamp : &currcmp_info->m_Reference;
MODULE* module = FindModule( *idMod ); if( module == NULL ) // not existing, load it
{ m_newModulesList.push_back( currcmp_info ); } }
bool success = loadNewModules();
// Update modules fields
for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ ) { COMPONENT_INFO* currcmp_info = m_componentsInNetlist[ii]; // Test if module is already loaded.
wxString * idMod = m_UseTimeStamp? &currcmp_info->m_TimeStamp : &currcmp_info->m_Reference;
MODULE* module = FindModule( *idMod ); if( module ) { // Update current module ( reference, value and "Time Stamp")
module->m_Reference->m_Text = currcmp_info->m_Reference; module->m_Value->m_Text = currcmp_info->m_Value; module->SetPath( currcmp_info->m_TimeStamp ); } else // not existing
{ } }
// clear pads netnames
for( MODULE* module = m_pcbframe->GetBoard()->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->m_Pads; pad; pad = pad->Next() ) pad->SetNetname( wxEmptyString ); }
return success;}
void NETLIST_READER::TestFootprintsMatchingAndExchange(){#ifdef PCBNEW
// If a module is "exchanged", the new module is added to the end of
// module list.
// Calculates the module count
int moduleCount = m_pcbframe->GetBoard()->m_Modules.GetCount();
MODULE* nextmodule; MODULE *module = m_pcbframe->GetBoard()->m_Modules; for( ; module && moduleCount; module = nextmodule, moduleCount-- ) { // Module can be deleted if exchanged, so store the next module.
nextmodule = module->Next();
// Search for the corresponding module info
COMPONENT_INFO * cmp_info = NULL; for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ ) { COMPONENT_INFO * candidate = m_componentsInNetlist[ii]; // Test if cmp_info matches the current module:
if( candidate->m_Reference.CmpNoCase( module->GetReference() ) == 0 ) { cmp_info = candidate; break; } } if( cmp_info == NULL ) // not found in netlist
continue;
if( module->GetLibRef().CmpNoCase( cmp_info->m_Footprint ) != 0 ) { if( m_ChangeFootprints ) // footprint exchange allowed.
{ MODULE* newModule = m_pcbframe->GetModuleLibrary( wxEmptyString, cmp_info->m_Footprint, false );
if( newModule ) { // Change old module to the new module (and delete the old one)
m_pcbframe->Exchange_Module( module, newModule, NULL ); } else if( m_messageWindow ) { wxString msg; msg.Printf( _( "Component \"%s\": module [%s] not found\n" ), GetChars( cmp_info->m_Reference ), GetChars( cmp_info->m_Footprint ) );
m_messageWindow->AppendText( msg ); } } else if( m_messageWindow ) { wxString msg; msg.Printf( _( "Component \"%s\": Mismatch! module is [%s] and netlist said [%s]\n" ), GetChars( cmp_info->m_Reference ), GetChars( module->GetLibRef() ), GetChars( cmp_info->m_Footprint ) );
m_messageWindow->AppendText( msg ); } } }#endif
}
/**
* Function SetPadNetName * Update a pad netname * @param aModule = module reference * @param aPadname = pad name (pad num) * @param aNetname = new net name of the pad * @return a pointer to the pad or NULL if the pad is not found */D_PAD* NETLIST_READER::SetPadNetName( const wxString & aModule, const wxString & aPadname, const wxString & aNetname ){ if( m_pcbframe == NULL ) return NULL;
MODULE* module = m_pcbframe->GetBoard()->FindModuleByReference( aModule ); if( module ) { D_PAD * pad = module->FindPadByName( aPadname ); if( pad ) { pad->SetNetname( aNetname ); return pad; } if( m_messageWindow ) { wxString msg; msg.Printf( _( "Module [%s]: Pad [%s] not found" ), GetChars( aModule ), GetChars( aPadname ) ); m_messageWindow->AppendText( msg + wxT( "\n" ) ); } }
return NULL;}
/* function RemoveExtraFootprints
* Remove (delete) not locked footprints found on board, but not in netlist */void NETLIST_READER::RemoveExtraFootprints(){ MODULE* nextModule;
MODULE* module = m_pcbframe->GetBoard()->m_Modules; for( ; module != NULL; module = nextModule ) { unsigned ii; nextModule = module->Next();
if( module->m_ModuleStatus & MODULE_is_LOCKED ) continue;
for( ii = 0; ii < m_componentsInNetlist.size(); ii++ ) { COMPONENT_INFO* cmp_info = m_componentsInNetlist[ii]; if( module->m_Reference->m_Text.CmpNoCase( cmp_info->m_Reference ) == 0 ) break; // Module is found in net list.
}
if( ii == m_componentsInNetlist.size() ) // Module not found in netlist.
module->DeleteStructure(); }}
/* Search for a module id the modules existing in the current BOARD.
* aId is a key to identify the module to find: * The reference or the full time stamp, according to m_UseTimeStamp * Returns the module is found, NULL otherwise. */MODULE* NETLIST_READER::FindModule( const wxString& aId ){ MODULE* module = m_pcbframe->GetBoard()->m_Modules; for( ; module != NULL; module = module->Next() ) { if( m_UseTimeStamp ) // identification by time stamp
{ if( aId.CmpNoCase( module->m_Path ) == 0 ) return module; } else // identification by Reference
{ if( aId.CmpNoCase( module->m_Reference->m_Text ) == 0 ) return module; } }
return NULL;}
/*
* function readModuleComponentLinkfile * read the *.cmp file ( filename in m_cmplistFullName ) * giving the equivalence Footprint_names / components * to find the footprint name corresponding to aCmpIdent * return true if the file can be read * * Sample file: * * Cmp-Mod V01 Genere by Pcbnew 29/10/2003-13: 11:6 * * BeginCmp * TimeStamp = /32307DE2/AA450F67; * Reference = C1; * ValeurCmp = 47uF; * IdModule = CP6; * EndCmp * */
bool NETLIST_READER::readModuleComponentLinkfile(){ wxString refcurrcmp; // Stores value read from line like Reference = BUS1;
wxString timestamp; // Stores value read from line like TimeStamp = /32307DE2/AA450F67;
wxString footprint; // Stores value read from line like IdModule = CP6;
FILE* cmpFile = wxFopen( m_cmplistFullName, wxT( "rt" ) );
if( cmpFile == NULL ) { wxString msg; msg.Printf( _( "File <%s> not found, use Netlist for footprints selection" ), GetChars( m_cmplistFullName ) );
if( m_messageWindow ) m_messageWindow->AppendText( msg ); return false; }
// netlineReader dtor will close cmpFile
FILE_LINE_READER netlineReader( cmpFile, m_cmplistFullName ); wxString buffer; wxString value;
while( netlineReader.ReadLine() ) { buffer = FROM_UTF8( netlineReader.Line() );
if( ! buffer.StartsWith( wxT("BeginCmp") ) ) continue;
// Begin component description.
refcurrcmp.Empty(); footprint.Empty(); timestamp.Empty();
while( netlineReader.ReadLine() ) { buffer = FROM_UTF8( netlineReader.Line() );
if( buffer.StartsWith( wxT("EndCmp") ) ) break;
// store string value, stored between '=' and ';' delimiters.
value = buffer.AfterFirst( '=' ); value = value.BeforeLast( ';'); value.Trim(true); value.Trim(false);
if( buffer.StartsWith( wxT("Reference") ) ) { refcurrcmp = value; continue; }
if( buffer.StartsWith( wxT("IdModule =" ) ) ) { footprint = value; continue; }
if( buffer.StartsWith( wxT("TimeStamp =" ) ) ) { timestamp = value; continue; } }
// Find the corresponding item in module info list:
for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ ) { COMPONENT_INFO * cmp_info = m_componentsInNetlist[ii]; if( m_UseTimeStamp ) // Use schematic timestamp to locate the footprint
{ if( cmp_info->m_TimeStamp.CmpNoCase( timestamp ) == 0 && !timestamp.IsEmpty() ) { // Found
if( !footprint.IsEmpty() ) cmp_info->m_Footprint = footprint; break; } } else // Use schematic reference to locate the footprint
{ if( cmp_info->m_Reference.CmpNoCase( refcurrcmp ) == 0 ) // Found!
{ if( !footprint.IsEmpty() ) cmp_info->m_Footprint = footprint; break; } } } }
return true;}
/* Function to sort the footprint list, used by loadNewModules.
* the given list is sorted by name */#ifdef PCBNEW
static bool SortByLibName( COMPONENT_INFO* ref, COMPONENT_INFO* cmp ){ int ii = ref->m_Footprint.CmpNoCase( cmp->m_Footprint ); return ii > 0;}#endif
/* Load new modules from library.
* If a new module is already loaded it is duplicated, which avoid multiple * unnecessary disk or net access to read libraries. * return false if a footprint is not found, true if OK */bool NETLIST_READER::loadNewModules(){ bool success = true;#ifdef PCBNEW
COMPONENT_INFO* ref, * cmp; MODULE* Module = NULL; wxPoint ModuleBestPosition; BOARD* pcb = m_pcbframe->GetBoard();
if( m_newModulesList.size() == 0 ) return true;
sort( m_newModulesList.begin(), m_newModulesList.end(), SortByLibName );
// Calculate the footprint "best" position:
EDA_RECT bbbox = pcb->ComputeBoundingBox( true );
if( bbbox.GetWidth() || bbbox.GetHeight() ) { ModuleBestPosition = bbbox.GetEnd(); ModuleBestPosition.y += 5000; }
ref = cmp = m_newModulesList[0];
for( unsigned ii = 0; ii < m_newModulesList.size(); ii++ ) { cmp = m_newModulesList[ii];
if( (ii == 0) || ( ref->m_Footprint != cmp->m_Footprint) ) { // New footprint : must be loaded from a library
Module = m_pcbframe->GetModuleLibrary( wxEmptyString, cmp->m_Footprint, false ); ref = cmp;
if( Module == NULL ) { success = false; if( m_messageWindow ) { wxString msg; msg.Printf( _( "Component [%s]: footprint <%s> not found" ), GetChars( cmp->m_Reference ), GetChars( cmp->m_Footprint ) );
msg += wxT("\n"); m_messageWindow->AppendText( msg ); } continue; }
Module->SetPosition( ModuleBestPosition );
/* Update schematic links : reference "Time Stamp" and schematic
* hierarchical path */ Module->m_Reference->m_Text = cmp->m_Reference; Module->SetTimeStamp( GetNewTimeStamp() ); Module->SetPath( cmp->m_TimeStamp ); } else { // Footprint already loaded from a library, duplicate it (faster)
if( Module == NULL ) continue; // Module does not exist in library.
MODULE* newmodule = new MODULE( *Module ); newmodule->SetParent( pcb );
pcb->Add( newmodule, ADD_APPEND );
Module = newmodule; Module->m_Reference->m_Text = cmp->m_Reference; Module->SetTimeStamp( GetNewTimeStamp() ); Module->SetPath( cmp->m_TimeStamp ); } }#endif
return success;}
|