You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

560 lines
17 KiB

  1. /**
  2. * @file pcbnew/netlist_reader_common.cpp
  3. */
  4. /*
  5. * This program source code file is part of KiCad, a free EDA CAD application.
  6. *
  7. * Copyright (C) 1992-2011 Jean-Pierre Charras.
  8. * Copyright (C) 1992-2011 KiCad Developers, see change_log.txt for contributors.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include <fctsys.h>
  28. #include <wxPcbStruct.h>
  29. #include <richio.h>
  30. #include <macros.h>
  31. #include <class_board.h>
  32. #include <class_module.h>
  33. #include <pcbnew.h>
  34. #include <netlist_reader.h>
  35. #include <algorithm>
  36. /*
  37. * Function ReadNetList
  38. * The main function to detect the netlist format,and run the right netlist reader
  39. * aFile = the already opened file (will be closed by the netlist reader)
  40. */
  41. bool NETLIST_READER::ReadNetList( FILE* aFile )
  42. {
  43. // Try to determine the netlist type:
  44. // Beginning of the first line of known formats, without spaces
  45. #define HEADERS_COUNT 3
  46. #define HEADER_ORCADPCB "({EESchemaNetlist"
  47. #define HEADER_PCBNEW "#EESchemaNetlist"
  48. #define HEADER_KICAD_NETFMT "(export"
  49. const std::string headers[HEADERS_COUNT] =
  50. {
  51. HEADER_ORCADPCB, HEADER_PCBNEW, HEADER_KICAD_NETFMT
  52. };
  53. int format = -1;
  54. for ( int jj = 0; jj < HEADERS_COUNT; jj++ )
  55. {
  56. int imax = headers[jj].size();
  57. int ii = 0;
  58. for( ; ii < imax; ii++ )
  59. {
  60. int data;
  61. // Read header, and skip blanks to avoid errors if an header changes
  62. do
  63. {
  64. data = fgetc( aFile );
  65. } while ( ( data == ' ' ) &&( EOF != data ) ) ;
  66. if( (int)headers[jj][ii] == data )
  67. continue;
  68. break;
  69. }
  70. if( ii == imax ) // header found
  71. {
  72. format = jj;
  73. break;
  74. }
  75. rewind( aFile );
  76. }
  77. rewind( aFile );
  78. bool success = false;
  79. switch( format )
  80. {
  81. case 0:
  82. m_typeNetlist = NETLIST_TYPE_ORCADPCB2;
  83. success = ReadOldFmtdNetList( aFile );
  84. break;
  85. case 1:
  86. m_typeNetlist = NETLIST_TYPE_PCBNEW;
  87. success = ReadOldFmtdNetList( aFile );
  88. break;
  89. case 2:
  90. m_typeNetlist = NETLIST_TYPE_KICAD;
  91. success = ReadKicadNetList( aFile );
  92. break;
  93. default: // Unrecognized format:
  94. break;
  95. }
  96. return success;
  97. }
  98. /**
  99. * Function GetComponentInfoList
  100. * @return a reference to the libpart info corresponding to a given part
  101. * @param aPartname = the name of the libpart
  102. */
  103. LIPBART_INFO* NETLIST_READER::GetLibpart(const wxString & aPartname)
  104. {
  105. for( unsigned ii = 0; ii < m_libpartList.size(); ii++ )
  106. {
  107. if( m_libpartList[ii]->m_Libpart == aPartname )
  108. return m_libpartList[ii];
  109. }
  110. return NULL;
  111. }
  112. bool NETLIST_READER::InitializeModules()
  113. {
  114. if( m_UseCmpFile ) // Try to get footprint name from .cmp file
  115. {
  116. readModuleComponentLinkfile();
  117. }
  118. if( m_pcbframe == NULL )
  119. return true;
  120. for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ )
  121. {
  122. COMPONENT_INFO* currcmp_info = m_componentsInNetlist[ii];
  123. // Test if module is already loaded.
  124. wxString * idMod = m_UseTimeStamp?
  125. &currcmp_info->m_TimeStamp : &currcmp_info->m_Reference;
  126. MODULE* module = FindModule( *idMod );
  127. if( module == NULL ) // not existing, load it
  128. {
  129. m_newModulesList.push_back( currcmp_info );
  130. }
  131. }
  132. bool success = loadNewModules();
  133. // Update modules fields
  134. for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ )
  135. {
  136. COMPONENT_INFO* currcmp_info = m_componentsInNetlist[ii];
  137. // Test if module is already loaded.
  138. wxString * idMod = m_UseTimeStamp?
  139. &currcmp_info->m_TimeStamp : &currcmp_info->m_Reference;
  140. MODULE* module = FindModule( *idMod );
  141. if( module )
  142. {
  143. // Update current module ( reference, value and "Time Stamp")
  144. module->m_Reference->m_Text = currcmp_info->m_Reference;
  145. module->m_Value->m_Text = currcmp_info->m_Value;
  146. module->SetPath( currcmp_info->m_TimeStamp );
  147. }
  148. else // not existing
  149. {
  150. }
  151. }
  152. // clear pads netnames
  153. for( MODULE* module = m_pcbframe->GetBoard()->m_Modules; module; module = module->Next() )
  154. {
  155. for( D_PAD* pad = module->m_Pads; pad; pad = pad->Next() )
  156. pad->SetNetname( wxEmptyString );
  157. }
  158. return success;
  159. }
  160. void NETLIST_READER::TestFootprintsMatchingAndExchange()
  161. {
  162. #ifdef PCBNEW
  163. // If a module is "exchanged", the new module is added to the end of
  164. // module list.
  165. // Calculates the module count
  166. int moduleCount = m_pcbframe->GetBoard()->m_Modules.GetCount();
  167. MODULE* nextmodule;
  168. MODULE *module = m_pcbframe->GetBoard()->m_Modules;
  169. for( ; module && moduleCount; module = nextmodule, moduleCount-- )
  170. {
  171. // Module can be deleted if exchanged, so store the next module.
  172. nextmodule = module->Next();
  173. // Search for the corresponding module info
  174. COMPONENT_INFO * cmp_info = NULL;
  175. for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ )
  176. {
  177. COMPONENT_INFO * candidate = m_componentsInNetlist[ii];
  178. // Test if cmp_info matches the current module:
  179. if( candidate->m_Reference.CmpNoCase( module->GetReference() ) == 0 )
  180. {
  181. cmp_info = candidate;
  182. break;
  183. }
  184. }
  185. if( cmp_info == NULL ) // not found in netlist
  186. continue;
  187. if( module->GetLibRef().CmpNoCase( cmp_info->m_Footprint ) != 0 )
  188. {
  189. if( m_ChangeFootprints ) // footprint exchange allowed.
  190. {
  191. MODULE* newModule = m_pcbframe->GetModuleLibrary( wxEmptyString,
  192. cmp_info->m_Footprint,
  193. false );
  194. if( newModule )
  195. {
  196. // Change old module to the new module (and delete the old one)
  197. m_pcbframe->Exchange_Module( module, newModule, NULL );
  198. }
  199. else if( m_messageWindow )
  200. {
  201. wxString msg;
  202. msg.Printf( _( "Component \"%s\": module [%s] not found\n" ),
  203. GetChars( cmp_info->m_Reference ),
  204. GetChars( cmp_info->m_Footprint ) );
  205. m_messageWindow->AppendText( msg );
  206. }
  207. }
  208. else if( m_messageWindow )
  209. {
  210. wxString msg;
  211. msg.Printf( _( "Component \"%s\": Mismatch! module is [%s] and netlist said [%s]\n" ),
  212. GetChars( cmp_info->m_Reference ),
  213. GetChars( module->GetLibRef() ),
  214. GetChars( cmp_info->m_Footprint ) );
  215. m_messageWindow->AppendText( msg );
  216. }
  217. }
  218. }
  219. #endif
  220. }
  221. /**
  222. * Function SetPadNetName
  223. * Update a pad netname
  224. * @param aModule = module reference
  225. * @param aPadname = pad name (pad num)
  226. * @param aNetname = new net name of the pad
  227. * @return a pointer to the pad or NULL if the pad is not found
  228. */
  229. D_PAD* NETLIST_READER::SetPadNetName( const wxString & aModule, const wxString & aPadname,
  230. const wxString & aNetname )
  231. {
  232. if( m_pcbframe == NULL )
  233. return NULL;
  234. MODULE* module = m_pcbframe->GetBoard()->FindModuleByReference( aModule );
  235. if( module )
  236. {
  237. D_PAD * pad = module->FindPadByName( aPadname );
  238. if( pad )
  239. {
  240. pad->SetNetname( aNetname );
  241. return pad;
  242. }
  243. if( m_messageWindow )
  244. {
  245. wxString msg;
  246. msg.Printf( _( "Module [%s]: Pad [%s] not found" ),
  247. GetChars( aModule ), GetChars( aPadname ) );
  248. m_messageWindow->AppendText( msg + wxT( "\n" ) );
  249. }
  250. }
  251. return NULL;
  252. }
  253. /* function RemoveExtraFootprints
  254. * Remove (delete) not locked footprints found on board, but not in netlist
  255. */
  256. void NETLIST_READER::RemoveExtraFootprints()
  257. {
  258. MODULE* nextModule;
  259. MODULE* module = m_pcbframe->GetBoard()->m_Modules;
  260. for( ; module != NULL; module = nextModule )
  261. {
  262. unsigned ii;
  263. nextModule = module->Next();
  264. if( module->m_ModuleStatus & MODULE_is_LOCKED )
  265. continue;
  266. for( ii = 0; ii < m_componentsInNetlist.size(); ii++ )
  267. {
  268. COMPONENT_INFO* cmp_info = m_componentsInNetlist[ii];
  269. if( module->m_Reference->m_Text.CmpNoCase( cmp_info->m_Reference ) == 0 )
  270. break; // Module is found in net list.
  271. }
  272. if( ii == m_componentsInNetlist.size() ) // Module not found in netlist.
  273. module->DeleteStructure();
  274. }
  275. }
  276. /* Search for a module id the modules existing in the current BOARD.
  277. * aId is a key to identify the module to find:
  278. * The reference or the full time stamp, according to m_UseTimeStamp
  279. * Returns the module is found, NULL otherwise.
  280. */
  281. MODULE* NETLIST_READER::FindModule( const wxString& aId )
  282. {
  283. MODULE* module = m_pcbframe->GetBoard()->m_Modules;
  284. for( ; module != NULL; module = module->Next() )
  285. {
  286. if( m_UseTimeStamp ) // identification by time stamp
  287. {
  288. if( aId.CmpNoCase( module->m_Path ) == 0 )
  289. return module;
  290. }
  291. else // identification by Reference
  292. {
  293. if( aId.CmpNoCase( module->m_Reference->m_Text ) == 0 )
  294. return module;
  295. }
  296. }
  297. return NULL;
  298. }
  299. /*
  300. * function readModuleComponentLinkfile
  301. * read the *.cmp file ( filename in m_cmplistFullName )
  302. * giving the equivalence Footprint_names / components
  303. * to find the footprint name corresponding to aCmpIdent
  304. * return true if the file can be read
  305. *
  306. * Sample file:
  307. *
  308. * Cmp-Mod V01 Genere by Pcbnew 29/10/2003-13: 11:6 *
  309. * BeginCmp
  310. * TimeStamp = /32307DE2/AA450F67;
  311. * Reference = C1;
  312. * ValeurCmp = 47uF;
  313. * IdModule = CP6;
  314. * EndCmp
  315. *
  316. */
  317. bool NETLIST_READER::readModuleComponentLinkfile()
  318. {
  319. wxString refcurrcmp; // Stores value read from line like Reference = BUS1;
  320. wxString timestamp; // Stores value read from line like TimeStamp = /32307DE2/AA450F67;
  321. wxString footprint; // Stores value read from line like IdModule = CP6;
  322. FILE* cmpFile = wxFopen( m_cmplistFullName, wxT( "rt" ) );
  323. if( cmpFile == NULL )
  324. {
  325. wxString msg;
  326. msg.Printf( _( "File <%s> not found, use Netlist for footprints selection" ),
  327. GetChars( m_cmplistFullName ) );
  328. if( m_messageWindow )
  329. m_messageWindow->AppendText( msg );
  330. return false;
  331. }
  332. // netlineReader dtor will close cmpFile
  333. FILE_LINE_READER netlineReader( cmpFile, m_cmplistFullName );
  334. wxString buffer;
  335. wxString value;
  336. while( netlineReader.ReadLine() )
  337. {
  338. buffer = FROM_UTF8( netlineReader.Line() );
  339. if( ! buffer.StartsWith( wxT("BeginCmp") ) )
  340. continue;
  341. // Begin component description.
  342. refcurrcmp.Empty();
  343. footprint.Empty();
  344. timestamp.Empty();
  345. while( netlineReader.ReadLine() )
  346. {
  347. buffer = FROM_UTF8( netlineReader.Line() );
  348. if( buffer.StartsWith( wxT("EndCmp") ) )
  349. break;
  350. // store string value, stored between '=' and ';' delimiters.
  351. value = buffer.AfterFirst( '=' );
  352. value = value.BeforeLast( ';');
  353. value.Trim(true);
  354. value.Trim(false);
  355. if( buffer.StartsWith( wxT("Reference") ) )
  356. {
  357. refcurrcmp = value;
  358. continue;
  359. }
  360. if( buffer.StartsWith( wxT("IdModule =" ) ) )
  361. {
  362. footprint = value;
  363. continue;
  364. }
  365. if( buffer.StartsWith( wxT("TimeStamp =" ) ) )
  366. {
  367. timestamp = value;
  368. continue;
  369. }
  370. }
  371. // Find the corresponding item in module info list:
  372. for( unsigned ii = 0; ii < m_componentsInNetlist.size(); ii++ )
  373. {
  374. COMPONENT_INFO * cmp_info = m_componentsInNetlist[ii];
  375. if( m_UseTimeStamp ) // Use schematic timestamp to locate the footprint
  376. {
  377. if( cmp_info->m_TimeStamp.CmpNoCase( timestamp ) == 0 &&
  378. !timestamp.IsEmpty() )
  379. { // Found
  380. if( !footprint.IsEmpty() )
  381. cmp_info->m_Footprint = footprint;
  382. break;
  383. }
  384. }
  385. else // Use schematic reference to locate the footprint
  386. {
  387. if( cmp_info->m_Reference.CmpNoCase( refcurrcmp ) == 0 ) // Found!
  388. {
  389. if( !footprint.IsEmpty() )
  390. cmp_info->m_Footprint = footprint;
  391. break;
  392. }
  393. }
  394. }
  395. }
  396. return true;
  397. }
  398. /* Function to sort the footprint list, used by loadNewModules.
  399. * the given list is sorted by name
  400. */
  401. #ifdef PCBNEW
  402. static bool SortByLibName( COMPONENT_INFO* ref, COMPONENT_INFO* cmp )
  403. {
  404. int ii = ref->m_Footprint.CmpNoCase( cmp->m_Footprint );
  405. return ii > 0;
  406. }
  407. #endif
  408. /* Load new modules from library.
  409. * If a new module is already loaded it is duplicated, which avoid multiple
  410. * unnecessary disk or net access to read libraries.
  411. * return false if a footprint is not found, true if OK
  412. */
  413. bool NETLIST_READER::loadNewModules()
  414. {
  415. bool success = true;
  416. #ifdef PCBNEW
  417. COMPONENT_INFO* ref, * cmp;
  418. MODULE* Module = NULL;
  419. wxPoint ModuleBestPosition;
  420. BOARD* pcb = m_pcbframe->GetBoard();
  421. if( m_newModulesList.size() == 0 )
  422. return true;
  423. sort( m_newModulesList.begin(), m_newModulesList.end(), SortByLibName );
  424. // Calculate the footprint "best" position:
  425. EDA_RECT bbbox = pcb->ComputeBoundingBox( true );
  426. if( bbbox.GetWidth() || bbbox.GetHeight() )
  427. {
  428. ModuleBestPosition = bbbox.GetEnd();
  429. ModuleBestPosition.y += 5000;
  430. }
  431. ref = cmp = m_newModulesList[0];
  432. for( unsigned ii = 0; ii < m_newModulesList.size(); ii++ )
  433. {
  434. cmp = m_newModulesList[ii];
  435. if( (ii == 0) || ( ref->m_Footprint != cmp->m_Footprint) )
  436. {
  437. // New footprint : must be loaded from a library
  438. Module = m_pcbframe->GetModuleLibrary( wxEmptyString, cmp->m_Footprint, false );
  439. ref = cmp;
  440. if( Module == NULL )
  441. {
  442. success = false;
  443. if( m_messageWindow )
  444. {
  445. wxString msg;
  446. msg.Printf( _( "Component [%s]: footprint <%s> not found" ),
  447. GetChars( cmp->m_Reference ),
  448. GetChars( cmp->m_Footprint ) );
  449. msg += wxT("\n");
  450. m_messageWindow->AppendText( msg );
  451. }
  452. continue;
  453. }
  454. Module->SetPosition( ModuleBestPosition );
  455. /* Update schematic links : reference "Time Stamp" and schematic
  456. * hierarchical path */
  457. Module->m_Reference->m_Text = cmp->m_Reference;
  458. Module->SetTimeStamp( GetNewTimeStamp() );
  459. Module->SetPath( cmp->m_TimeStamp );
  460. }
  461. else
  462. {
  463. // Footprint already loaded from a library, duplicate it (faster)
  464. if( Module == NULL )
  465. continue; // Module does not exist in library.
  466. MODULE* newmodule = new MODULE( *Module );
  467. newmodule->SetParent( pcb );
  468. pcb->Add( newmodule, ADD_APPEND );
  469. Module = newmodule;
  470. Module->m_Reference->m_Text = cmp->m_Reference;
  471. Module->SetTimeStamp( GetNewTimeStamp() );
  472. Module->SetPath( cmp->m_TimeStamp );
  473. }
  474. }
  475. #endif
  476. return success;
  477. }