/** * @file pcbnew/netlist_reader_kicad.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 #include // netlist_lexer is common to Eeschema and Pcbnew #include using namespace NL_T; /** * Class PCB_PLOT_PARAMS_PARSER * is the parser class for PCB_PLOT_PARAMS. */ class NETLIST_READER_KICAD_PARSER : public NETLIST_LEXER { private: T token; NETLIST_READER * netlist_reader; public: NETLIST_READER_KICAD_PARSER( FILE_LINE_READER* aReader, NETLIST_READER *aNetlistReader ); /** * Function Parse * parse the full netlist */ void Parse( BOARD * aBrd ) throw( IO_ERROR, PARSE_ERROR ); /** * Function ParseComp * parse the comp description like * (comp (ref P1) * (value DB25FEMELLE) * (footprint DB25FC) * (libsource (lib conn) (part DB25)) * (sheetpath (names /) (tstamps /)) * (tstamp 3256759C)) */ COMPONENT_INFO* ParseComp() throw( IO_ERROR, PARSE_ERROR ); /** * Function ParseKicadLibpartList * Read the section "libparts" like: * (libparts * (libpart (lib device) (part C) * (description "Condensateur non polarise") * (footprints * (fp SM*) * (fp C?) * (fp C1-1)) * (fields * (field (name Reference) C) * (field (name Value) C)) * (pins * (pin (num 1) (name ~) (type passive)) * (pin (num 2) (name ~) (type passive)))) * * And add the strings giving the footprint filter (subsection footprints) * of the corresponding module info *

This section is used by CvPcb, and is not useful in Pcbnew, * therefore it it not always read

*/ void ParseKicadLibpartList() throw( IO_ERROR, PARSE_ERROR ); /** * Function ParseNet * Parses a section like * (net (code 20) (name /PC-A0) * (node (ref BUS1) (pin 62)) * (node (ref U3) (pin 3)) * (node (ref U9) (pin M6))) * * and set the corresponfings pads netnames */ void ParseNet( BOARD * aBrd ) throw( IO_ERROR, PARSE_ERROR ); /** * Function SkipCurrent * Skip the current token level, i.e * search for the RIGHT parenthesis which closes the current description */ void SkipCurrent() throw( IO_ERROR, PARSE_ERROR ); // Useful for debug only: const char* getTokenName( T aTok ) { return NETLIST_LEXER::TokenName( aTok ); } }; bool NETLIST_READER::ReadKicadNetList( FILE* aFile ) { BOARD * brd = m_pcbframe ? m_pcbframe->GetBoard() : NULL; // netlineReader dtor will close aFile FILE_LINE_READER netlineReader( aFile, m_netlistFullName ); NETLIST_READER_KICAD_PARSER netlist_parser( &netlineReader, this ); try { netlist_parser.Parse( brd ); } catch( IO_ERROR& ioe ) { ioe.errorText += '\n'; ioe.errorText += _("Netlist error."); wxMessageBox( ioe.errorText ); return false; } return true; } // NETLIST_READER_KICAD_PARSER NETLIST_READER_KICAD_PARSER::NETLIST_READER_KICAD_PARSER( FILE_LINE_READER* aReader, NETLIST_READER *aNetlistReader ) : NETLIST_LEXER( aReader ) { netlist_reader = aNetlistReader; } /** * Function SkipCurrent * Skip the current token level, i.e * search for the RIGHT parenthesis which closes the current description */ void NETLIST_READER_KICAD_PARSER::SkipCurrent() throw( IO_ERROR, PARSE_ERROR ) { int curr_level = 0; while( ( token = NextTok() ) != T_EOF ) { if( token == T_LEFT ) curr_level--; if( token == T_RIGHT ) { curr_level++; if( curr_level > 0 ) return; } } } void NETLIST_READER_KICAD_PARSER::Parse( BOARD * aBrd ) throw( IO_ERROR, PARSE_ERROR ) { int plevel = 0; // the count of ')' to read and end of file, // after parsing all sections while( ( token = NextTok() ) != T_EOF ) { if( token == T_LEFT ) token = NextTok(); switch( token ) { case T_export: // The netlist starts here. // nothing to do here, // just increment the count of ')' to read and end of file plevel++; break; case T_version: // The netlist starts here. // version id not yet used: read it but does not use it NextTok(); NeedRIGHT(); break; case T_components: // The section comp starts here. while( ( token = NextTok() ) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); if( token == T_comp ) // A comp section if found. Read it { COMPONENT_INFO* cmp_info = ParseComp(); netlist_reader->AddModuleInfo( cmp_info ); } } if( netlist_reader->BuildModuleListOnlyOpt() ) return; // at this point, the module list is read and built. // Load new footprints netlist_reader->InitializeModules(); netlist_reader->TestFootprintsMatchingAndExchange(); break; case T_nets: // The section nets starts here. while( ( token = NextTok() ) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); if( token == T_net ) { // A net section if found. Read it ParseNet( aBrd ); } } break; case T_libparts: // The section libparts starts here. if( netlist_reader->ReadLibpartSectionOpt() ) { while( ( token = NextTok() ) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); if( token == T_libpart ) { // A libpart section if found. Read it ParseKicadLibpartList(); } } } else SkipCurrent(); break; case T_libraries: // The section libraries starts here. // List of libraries in use. // Not used here, just skip it SkipCurrent(); break; case T_design: // The section design starts here. // Not used (mainly thet are comments), just skip it SkipCurrent(); break; case T_RIGHT: // The closing parenthesis of the file. // Not used (mainly thet are comments), just skip it plevel--; break; default: SkipCurrent(); break; } } if( plevel != 0 ) { wxLogDebug(wxT("NETLIST_READER_KICAD_PARSER::Parse(): bad parenthesis count (count = %d"), plevel ); } } void NETLIST_READER_KICAD_PARSER::ParseNet( BOARD * aBrd ) throw( IO_ERROR, PARSE_ERROR ) { /* Parses a section like * (net (code 20) (name /PC-A0) * (node (ref BUS1) (pin 62)) * (node (ref U3) (pin 3)) * (node (ref U9) (pin M6))) */ wxString code; wxString name; wxString cmpref; wxString pin; int nodecount = 0; std::vector padList; // The token net was read, so the next data is (code ) while( (token = NextTok()) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); switch( token ) { case T_code: NeedSYMBOLorNUMBER(); code = FROM_UTF8( CurText() ); NeedRIGHT(); break; case T_name: NeedSYMBOLorNUMBER(); name = FROM_UTF8( CurText() ); NeedRIGHT(); if( name.IsEmpty() ) // Give a dummy net name like N-000109 name = wxT("N-00000") + code; break; case T_node: while( (token = NextTok()) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); switch( token ) { case T_ref: NeedSYMBOLorNUMBER(); cmpref = FROM_UTF8( CurText() ); NeedRIGHT(); break; case T_pin: NeedSYMBOLorNUMBER(); pin = FROM_UTF8( CurText() ); NeedRIGHT(); break; default: SkipCurrent(); break; } } netlist_reader->SetPadsNetName( cmpref, pin, name, padList ); nodecount++; break; default: SkipCurrent(); break; } } // When there is only one item in net, clear pad netname // Remember one can have more than one pad in list, because a footprint // can have many pads with the same pad name if( nodecount < 2 ) for( unsigned ii = 0; ii < padList.size(); ii++ ) padList[ii]->SetNetname( wxEmptyString ); } COMPONENT_INFO* NETLIST_READER_KICAD_PARSER::ParseComp() throw( IO_ERROR, PARSE_ERROR ) { /* Parses a section like * (comp (ref P1) * (value DB25FEMELLE) * (footprint DB25FC) * (libsource (lib conn) (part DB25)) * (sheetpath (names /) (tstamps /)) * (tstamp 3256759C)) * * other fields (unused) are skipped * A component need a reference, value, foorprint name and a full time stamp * The full time stamp is the sheetpath time stamp + the component time stamp */ wxString ref; wxString value; wxString footprint; wxString libpart; wxString pathtimestamp, timestamp; // The token comp was read, so the next data is (ref P1) while( (token = NextTok()) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); switch( token ) { case T_ref: NeedSYMBOLorNUMBER(); ref = FROM_UTF8( CurText() ); NeedRIGHT(); break; case T_value: NeedSYMBOLorNUMBER(); value = FROM_UTF8( CurText() ); NeedRIGHT(); break; case T_footprint: NeedSYMBOLorNUMBER(); footprint = FROM_UTF8( CurText() ); NeedRIGHT(); break; case T_libsource: // Read libsource while( (token = NextTok()) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); if( token == T_part ) { NeedSYMBOLorNUMBER(); libpart = FROM_UTF8( CurText() ); NeedRIGHT(); } else SkipCurrent(); } break; case T_sheetpath: while( ( token = NextTok() ) != T_tstamps ); NeedSYMBOLorNUMBER(); pathtimestamp = FROM_UTF8( CurText() ); NeedRIGHT(); NeedRIGHT(); break; case T_tstamp: NeedSYMBOLorNUMBER(); timestamp = FROM_UTF8( CurText() ); NeedRIGHT(); break; default: // Skip not used data (i.e all other tokens) SkipCurrent(); break; } } pathtimestamp += timestamp; COMPONENT_INFO* cmp_info = new COMPONENT_INFO( footprint, ref, value, pathtimestamp ); cmp_info->m_Libpart = libpart; return cmp_info; } /* Read the section "libparts" like: * (libparts * (libpart (lib device) (part C) * (description "Condensateur non polarise") * (footprints * (fp SM*) * (fp C?) * (fp C1-1)) * (fields * (field (name Reference) C) * (field (name Value) C)) * (pins * (pin (num 1) (name ~) (type passive)) * (pin (num 2) (name ~) (type passive)))) * * And add the strings giving the footprint filter (subsection footprints) * of the corresponding module info */ void NETLIST_READER_KICAD_PARSER::ParseKicadLibpartList() throw( IO_ERROR, PARSE_ERROR ) { /* Parses a section like * (libpart (lib device) (part C) * (description "Condensateur non polarise") * (footprints * (fp SM*) * (fp C?) * (fp C1-1)) * (fields * (field (name Reference) C) * (field (name Value) C)) * (pins * (pin (num 1) (name ~) (type passive)) * (pin (num 2) (name ~) (type passive)))) * * Currently footprints section/fp are read and data stored * other fields (unused) are skipped */ wxString device; wxString filter; LIPBART_INFO* libpart_info = NULL; // The last token read was libpart, so read the next token while( (token = NextTok()) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); switch( token ) { case T_part: NeedSYMBOLorNUMBER(); device = FROM_UTF8( CurText() ); NeedRIGHT(); libpart_info = new LIPBART_INFO( device ); netlist_reader->AddLibpartInfo( libpart_info ); break; case T_footprints: // Ensure "(part C)" was already read if( libpart_info == NULL ) Expecting( T_part ); // Read all fp elements (footprint filter item) while( (token = NextTok()) != T_RIGHT ) { if( token == T_LEFT ) token = NextTok(); if( token != T_fp ) Expecting( T_fp ); NeedSYMBOLorNUMBER(); filter = FROM_UTF8( CurText() ); NeedRIGHT(); libpart_info->m_FootprintFilter.Add( filter ); } break; default: // Skip not used data (i.e all other tokens) SkipCurrent(); break; } } }