KiCad PCB EDA Suite
eeschema/erc.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2011-2016 Wayne Stambaugh <stambaughw@verizon.net>
6  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
31 #include <fctsys.h>
32 #include <sch_draw_panel.h>
33 #include <kicad_string.h>
34 #include <sch_edit_frame.h>
35 #include <netlist_object.h>
36 #include <lib_pin.h>
37 #include <erc.h>
38 #include <sch_marker.h>
39 #include <sch_sheet.h>
40 #include <sch_reference_list.h>
41 #include <wx/ffile.h>
42 
43 
44 /* ERC tests :
45  * 1 - conflicts between connected pins ( example: 2 connected outputs )
46  * 2 - minimal connections requirements ( 1 input *must* be connected to an
47  * output, or a passive pin )
48  */
49 
50 
51 /*
52  * Minimal ERC requirements:
53  * All pins *must* be connected (except ELECTRICAL_PINTYPE::PT_NC).
54  * When a pin is not connected in schematic, the user must place a "non
55  * connected" symbol to this pin.
56  * This ensures a forgotten connection will be detected.
57  */
58 
59 /* Messages for conflicts :
60  * ELECTRICAL_PINTYPE::PT_INPUT, ELECTRICAL_PINTYPE::PT_OUTPUT, ELECTRICAL_PINTYPE:PT_:BIDI, ELECTRICAL_PINTYPE::PT_TRISTATE, ELECTRICAL_PINTYPE::PT_PASSIVE,
61  * ELECTRICAL_PINTYPE::PT_UNSPECIFIED, ELECTRICAL_PINTYPE::PT_POWER_IN, ELECTRICAL_PINTYPE::PT_POWER_OUT, ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR,
62  * ELECTRICAL_PINTYPE::PT_OPENEMITTER, ELECTRICAL_PINTYPE::PT_NC
63  * These messages are used to show the ERC matrix in ERC dialog
64  */
65 
66 // Messages for matrix rows:
67 const wxString CommentERC_H[] =
68 {
69  _( "Input Pin" ),
70  _( "Output Pin" ),
71  _( "Bidirectional Pin" ),
72  _( "Tri-State Pin" ),
73  _( "Passive Pin" ),
74  _( "Unspecified Pin" ),
75  _( "Power Input Pin" ),
76  _( "Power Output Pin" ),
77  _( "Open Collector" ),
78  _( "Open Emitter" ),
79  _( "No Connection" )
80 };
81 
82 // Messages for matrix columns
83 const wxString CommentERC_V[] =
84 {
85  _( "Input Pin" ),
86  _( "Output Pin" ),
87  _( "Bidirectional Pin" ),
88  _( "Tri-State Pin" ),
89  _( "Passive Pin" ),
90  _( "Unspecified Pin" ),
91  _( "Power Input Pin" ),
92  _( "Power Output Pin" ),
93  _( "Open Collector" ),
94  _( "Open Emitter" ),
95  _( "No Connection" )
96 };
97 
98 
99 /* Look up table which gives the diag for a pair of connected pins
100  * Can be modified by ERC options.
101  * at start up: must be loaded by DefaultDiagErc
102  * Can be modified in dialog ERC
103  */
105 
114 {
115 /* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */
116 /* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
117 /* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR },
118 /* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR },
119 /* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR },
120 /*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
121 /*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR },
122 /*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR },
123 /*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR },
124 /* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
125 /* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
126 /* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }
127 };
128 
129 
141 {
142 /* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */
143 /* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
144 /*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
145 /* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
146 /* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
147 /*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
148 /*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
149 /*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI },
150 /*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
151 /* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
152 /* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
153 /* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI }
154 };
155 
156 
157 int TestDuplicateSheetNames( bool aCreateMarker )
158 {
159  SCH_SCREEN* screen;
160  int err_count = 0;
161  SCH_SCREENS screenList; // Created the list of screen
162 
163  for( screen = screenList.GetFirst(); screen != NULL; screen = screenList.GetNext() )
164  {
165  std::vector<SCH_SHEET*> list;
166 
167  for( auto item : screen->Items().OfType( SCH_SHEET_T ) )
168  list.push_back( static_cast<SCH_SHEET*>( item ) );
169 
170  for( size_t i = 0; i < list.size(); i++ )
171  {
172  auto item = list[i];
173 
174  for( size_t j = i + 1; j < list.size(); j++ )
175  {
176  auto test_item = list[j];
177 
178  // We have found a second sheet: compare names
179  // we are using case insensitive comparison to avoid mistakes between
180  // similar names like Mysheet and mysheet
181  if( ( (SCH_SHEET*) item )->GetName().CmpNoCase(
182  ( ( SCH_SHEET* ) test_item )->GetName() ) == 0 )
183  {
184  if( aCreateMarker )
185  {
186  /* Create a new marker type ERC error*/
187  SCH_MARKER* marker = new SCH_MARKER();
188  marker->SetTimeStamp( GetNewTimeStamp() );
190  ( (SCH_SHEET*) test_item )->GetPosition(),
191  _( "Duplicate sheet name" ),
192  ( (SCH_SHEET*) test_item )->GetPosition() );
195  screen->Append( marker );
196  }
197 
198  err_count++;
199  }
200  }
201  }
202  }
203 
204  return err_count;
205 }
206 
207 
208 int TestConflictingBusAliases( bool aCreateMarker )
209 {
210  wxString msg;
211  wxPoint dummyPos( 0, 0 );
212  int err_count = 0;
213  SCH_SCREENS screens;
214  std::vector< std::shared_ptr<BUS_ALIAS> > aliases;
215 
216  for( auto screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
217  {
218  std::unordered_set< std::shared_ptr<BUS_ALIAS> > screen_aliases = screen->GetBusAliases();
219 
220  for( const std::shared_ptr<BUS_ALIAS>& alias : screen_aliases )
221  {
222  for( const std::shared_ptr<BUS_ALIAS>& test : aliases )
223  {
224  if( alias->GetName() == test->GetName() && alias->Members() != test->Members() )
225  {
226  if( aCreateMarker )
227  {
228  msg = wxString::Format( _( "Bus alias %s has conflicting definitions on"
229  " multiple sheets: %s and %s" ),
230  alias->GetName(),
231  alias->GetParent()->GetFileName(),
232  test->GetParent()->GetFileName() );
233 
234  SCH_MARKER* marker = new SCH_MARKER();
235  marker->SetData( ERCE_BUS_ALIAS_CONFLICT, dummyPos, msg, dummyPos );
236  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
237  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
238 
239  test->GetParent()->Append( marker );
240  }
241 
242  ++err_count;
243  }
244  }
245  }
246 
247  aliases.insert( aliases.end(), screen_aliases.begin(), screen_aliases.end() );
248  }
249 
250  return err_count;
251 }
252 
253 
255 {
256  int errors = 0;
257  std::map<wxString, LIB_ID> footprints;
259  aSheetList.GetMultiUnitComponents( refMap, true );
260 
261  for( auto& component : refMap )
262  {
263  auto& refList = component.second;
264 
265  if( refList.GetCount() == 0 )
266  {
267  wxFAIL; // it should not happen
268  continue;
269  }
270 
271  // Reference footprint
272  wxString fp;
273  wxString unitName;
274 
275  for( unsigned i = 0; i < component.second.GetCount(); ++i )
276  {
277  SCH_COMPONENT* cmp = refList.GetItem( i ).GetComp();
278  SCH_SHEET_PATH sheetPath = refList.GetItem( i ).GetSheetPath();
279  fp = cmp->GetField( FOOTPRINT )->GetText();
280 
281  if( !fp.IsEmpty() )
282  {
283  unitName = cmp->GetRef( &sheetPath )
284  + LIB_PART::SubReference( cmp->GetUnit(), false );
285  break;
286  }
287  }
288 
289  for( unsigned i = 0; i < component.second.GetCount(); ++i )
290  {
291  SCH_REFERENCE& ref = refList.GetItem( i );
292  SCH_COMPONENT* unit = ref.GetComp();
293  SCH_SHEET_PATH sheetPath = refList.GetItem( i ).GetSheetPath();
294  const wxString curFp = unit->GetField( FOOTPRINT )->GetText();
295 
296  if( !curFp.IsEmpty() && fp != curFp )
297  {
298  wxString curUnitName = unit->GetRef( &sheetPath )
299  + LIB_PART::SubReference( unit->GetUnit(), false );
300  wxString msg = wxString::Format( _( "Unit %s has '%s' assigned, "
301  "whereas unit %s has '%s' assigned" ),
302  unitName,
303  fp,
304  curUnitName,
305  curFp );
306  wxPoint pos = unit->GetPosition();
307 
308  SCH_MARKER* marker = new SCH_MARKER();
309  marker->SetTimeStamp( GetNewTimeStamp() );
310  marker->SetData( ERCE_DIFFERENT_UNIT_FP, pos, msg, pos );
313  ref.GetSheetPath().LastScreen()->Append( marker );
314 
315  ++errors;
316  }
317  }
318  }
319 
320  return errors;
321 }
322 
323 
324 void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, int aMinConn, int aDiag )
325 {
326  SCH_MARKER* marker = NULL;
327  SCH_SCREEN* screen;
328  ELECTRICAL_PINTYPE ii, jj;
329 
330  if( aDiag == OK || aMinConn < 1 )
331  return;
332 
333  /* Create new marker for ERC error. */
334  marker = new SCH_MARKER();
335  marker->SetTimeStamp( GetNewTimeStamp() );
336 
339  screen = aNetItemRef->m_SheetPath.LastScreen();
340  screen->Append( marker );
341 
342  wxString msg;
343 
344  ii = aNetItemRef->m_ElectricalPinType;
345 
346  wxString cmp_ref( "?" );
347 
348  if( aNetItemRef->m_Type == NETLIST_ITEM::PIN && aNetItemRef->m_Link )
349  cmp_ref = aNetItemRef->GetComponentParent()->GetRef( &aNetItemRef->m_SheetPath );
350 
351  if( aNetItemTst == NULL )
352  {
353  if( aMinConn == NOD ) /* Nothing driving the net. */
354  {
355  if( aNetItemRef->m_Type == NETLIST_ITEM::PIN && aNetItemRef->m_Link )
356  cmp_ref = aNetItemRef->GetComponentParent()->GetRef(
357  &aNetItemRef->m_SheetPath );
358 
359  msg.Printf( _( "Pin %s (%s) of component %s is not driven (Net %d)." ),
360  aNetItemRef->m_PinNum,
361  GetChars( GetText( ii ) ),
362  GetChars( cmp_ref ),
363  aNetItemRef->GetNet() );
364  marker->SetData( ERCE_PIN_NOT_DRIVEN, aNetItemRef->m_Start, msg, aNetItemRef->m_Start );
365  return;
366  }
367  }
368 
369  if( aNetItemTst ) /* Error between 2 pins */
370  {
371  jj = aNetItemTst->m_ElectricalPinType;
373 
374  if( aDiag == ERR )
375  {
378  }
379 
380  wxString alt_cmp( "?" );
381 
382  if( aNetItemTst->m_Type == NETLIST_ITEM::PIN && aNetItemTst->m_Link )
383  alt_cmp = aNetItemTst->GetComponentParent()->GetRef( &aNetItemTst->m_SheetPath );
384 
385  msg.Printf( _( "Pin %s (%s) of component %s is connected to " ),
386  aNetItemRef->m_PinNum,
387  GetChars( GetText( ii ) ),
388  GetChars( cmp_ref ) );
389  marker->SetData( errortype, aNetItemRef->m_Start, msg, aNetItemRef->m_Start );
390  msg.Printf( _( "pin %s (%s) of component %s (net %d)." ),
391  aNetItemTst->m_PinNum,
392  GetChars( GetText( jj ) ),
393  GetChars( alt_cmp ),
394  aNetItemRef->GetNet() );
395  marker->SetAuxiliaryData( msg, aNetItemTst->m_Start );
396  }
397 }
398 
399 
400 void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aNetStart,
401  int* aMinConnexion )
402 {
403  unsigned netItemTst = aNetStart;
405  int erc = OK;
406 
407  /* Analysis of the table of connections. */
408  ELECTRICAL_PINTYPE ref_elect_type = aList->GetItem( aNetItemRef )->m_ElectricalPinType;
409  int local_minconn = NOC;
410 
411  if( ref_elect_type == ELECTRICAL_PINTYPE::PT_NC )
412  local_minconn = NPI;
413 
414  /* Test pins connected to NetItemRef */
415  for( ; ; netItemTst++ )
416  {
417  if( aNetItemRef == netItemTst )
418  continue;
419 
420  // We examine only a given net. We stop the search if the net changes
421  if( ( netItemTst >= aList->size() ) // End of list
422  || ( aList->GetItemNet( aNetItemRef ) !=
423  aList->GetItemNet( netItemTst ) ) ) // End of net
424  {
425  /* End net code found: minimum connection test. */
426  if( ( *aMinConnexion < NET_NC ) && ( local_minconn < NET_NC ) )
427  {
428  /* Not connected or not driven pin. */
429  bool seterr = true;
430 
431  if( local_minconn == NOC && aList->GetItemType( aNetItemRef ) == NETLIST_ITEM::PIN )
432  {
433  /* This pin is not connected: for multiple part per
434  * package, and duplicated pin,
435  * search for another instance of this pin
436  * this will be flagged only if all instances of this pin
437  * are not connected
438  * TODO test also if instances connected are connected to
439  * the same net
440  */
441  for( unsigned duplicate = 0; duplicate < aList->size(); duplicate++ )
442  {
443  if( aList->GetItemType( duplicate ) != NETLIST_ITEM::PIN )
444  continue;
445 
446  if( duplicate == aNetItemRef )
447  continue;
448 
449  if( aList->GetItem( aNetItemRef )->m_PinNum !=
450  aList->GetItem( duplicate )->m_PinNum )
451  continue;
452 
453  if( ( (SCH_COMPONENT*) aList->GetItem( aNetItemRef )->
454  m_Link )->GetRef( &aList->GetItem( aNetItemRef )-> m_SheetPath ) !=
455  ( (SCH_COMPONENT*) aList->GetItem( duplicate )->m_Link )
456  ->GetRef( &aList->GetItem( duplicate )->m_SheetPath ) )
457  continue;
458 
459  // Same component and same pin. Do dot create error for this pin
460  // if the other pin is connected (i.e. if duplicate net has another
461  // item)
462  if( (duplicate > 0)
463  && ( aList->GetItemNet( duplicate ) ==
464  aList->GetItemNet( duplicate - 1 ) ) )
465  seterr = false;
466 
467  if( (duplicate < aList->size() - 1)
468  && ( aList->GetItemNet( duplicate ) ==
469  aList->GetItemNet( duplicate + 1 ) ) )
470  seterr = false;
471  }
472  }
473 
474  if( seterr )
475  Diagnose( aList->GetItem( aNetItemRef ), NULL, local_minconn, WAR );
476 
477  *aMinConnexion = DRV; // inhibiting other messages of this
478  // type for the net.
479  }
480  return;
481  }
482 
483  switch( aList->GetItemType( netItemTst ) )
484  {
487  case NETLIST_ITEM::BUS:
489  case NETLIST_ITEM::LABEL:
498  break;
499 
501  local_minconn = std::max( NET_NC, local_minconn );
502  break;
503 
504  case NETLIST_ITEM::PIN:
505  jj = aList->GetItem( netItemTst )->m_ElectricalPinType;
506  local_minconn = std::max(
507  MinimalReq[static_cast<int>( ref_elect_type )][static_cast<int>( jj )],
508  local_minconn );
509 
510  if( netItemTst <= aNetItemRef )
511  break;
512 
513  if( erc == OK )
514  {
515  erc = DiagErc[static_cast<int>( ref_elect_type )][static_cast<int>( jj )];
516 
517  if( erc != OK )
518  {
519  if( aList->GetConnectionType( netItemTst ) == NET_CONNECTION::UNCONNECTED )
520  {
521  Diagnose( aList->GetItem( aNetItemRef ), aList->GetItem( netItemTst ), 0,
522  erc );
523  aList->SetConnectionType(
525  }
526  }
527  }
528 
529  break;
530  }
531  }
532 }
533 
534 int NETLIST_OBJECT_LIST::CountPinsInNet( unsigned aNetStart )
535 {
536  int count = 0;
537  int curr_net = GetItemNet( aNetStart );
538 
539  /* Test pins connected to NetItemRef */
540  for( unsigned item = aNetStart; item < size(); item++ )
541  {
542  // We examine only a given net. We stop the search if the net changes
543  if( curr_net != GetItemNet( item ) ) // End of net
544  break;
545 
546  if( GetItemType( item ) == NETLIST_ITEM::PIN )
547  count++;
548  }
549 
550  return count;
551 }
552 
553 bool WriteDiagnosticERC( EDA_UNITS aUnits, const wxString& aFullFileName )
554 {
555  wxFFile file( aFullFileName, wxT( "wt" ) );
556 
557  if( !file.IsOpened() )
558  return false;
559 
560  wxString msg = wxString::Format( _( "ERC report (%s, Encoding UTF8)\n" ), DateAndTime() );
561  int err_count = 0;
562  int warn_count = 0;
563  int total_count = 0;
564  SCH_SHEET_LIST sheetList( g_RootSheet );
565 
566  for( unsigned i = 0; i < sheetList.size(); i++ )
567  {
568  msg << wxString::Format( _( "\n***** Sheet %s\n" ),
569  GetChars( sheetList[i].PathHumanReadable() ) );
570 
571  for( auto aItem : sheetList[i].LastScreen()->Items().OfType( SCH_MARKER_T ) )
572  {
573  auto marker = static_cast<const SCH_MARKER*>( aItem );
574 
575  if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
576  continue;
577 
578  total_count++;
579 
580  if( marker->GetErrorLevel() == MARKER_BASE::MARKER_SEVERITY_ERROR )
581  err_count++;
582 
583  if( marker->GetErrorLevel() == MARKER_BASE::MARKER_SEVERITY_WARNING )
584  warn_count++;
585 
586  msg << marker->GetReporter().ShowReport( aUnits );
587  }
588  }
589 
590  msg << wxString::Format( _( "\n ** ERC messages: %d Errors %d Warnings %d\n" ),
591  total_count, err_count, warn_count );
592 
593  // Currently: write report using UTF8 (as usual in Kicad).
594  // TODO: see if we can use the current encoding page (mainly for Windows users),
595  // Or other format (HTML?)
596  file.Write( msg );
597 
598  // wxFFile dtor will close the file.
599 
600  return true;
601 }
602 
603 
604 void NETLIST_OBJECT_LIST::TestforNonOrphanLabel( unsigned aNetItemRef, unsigned aStartNet )
605 {
606  unsigned netItemTst = aStartNet;
607  int erc = 1;
608 
609  // Review the list of labels connected to NetItemRef:
610  for( ; ; netItemTst++ )
611  {
612  if( netItemTst == aNetItemRef )
613  continue;
614 
615  /* Is always in the same net? */
616  if( ( netItemTst == size() )
617  || ( GetItemNet( aNetItemRef ) != GetItemNet( netItemTst ) ) )
618  {
619  /* End Netcode found. */
620  if( erc )
621  {
622  /* Glabel or SheetLabel orphaned. */
623  Diagnose( GetItem( aNetItemRef ), NULL, -1, WAR );
624  }
625 
626  return;
627  }
628 
629  if( GetItem( aNetItemRef )->IsLabelConnected( GetItem( netItemTst ) ) )
630  erc = 0;
631 
632  //same thing, different order.
633  if( GetItem( netItemTst )->IsLabelConnected( GetItem( aNetItemRef ) ) )
634  erc = 0;
635  }
636 }
637 
638 
639 // this code try to detect similar labels, i.e. labels which are identical
640 // when they are compared using case insensitive coparisons.
641 
642 
643 // A helper struct to compare NETLIST_OBJECT items by sheetpath and label texts
644 // for a std::set<NETLIST_OBJECT*> container
645 // the full text is "sheetpath+label" for local labels and "label" for global labels
647 {
648  bool operator() ( const NETLIST_OBJECT* lab1, const NETLIST_OBJECT* lab2 ) const
649  {
650  wxString str1 = lab1->m_SheetPath.Path() + lab1->m_Label;
651  wxString str2 = lab2->m_SheetPath.Path() + lab2->m_Label;
652 
653  return str1.Cmp( str2 ) < 0;
654  }
655 };
656 
658 {
659  bool operator() ( const NETLIST_OBJECT* lab1, const NETLIST_OBJECT* lab2 ) const
660  {
661  return lab1->m_Label.Cmp( lab2->m_Label ) < 0;
662  }
663 };
664 
666 {
667  bool operator() ( const NETLIST_OBJECT* lab1, const NETLIST_OBJECT* lab2 ) const
668  {
669  return lab1->m_SheetPath.Path().Cmp( lab2->m_SheetPath.Path() ) < 0;
670  }
671 };
672 
673 // Helper functions to build the warning messages about Similar Labels:
674 static int countIndenticalLabels( std::vector<NETLIST_OBJECT*>& aList, NETLIST_OBJECT* aRef );
675 static void SimilarLabelsDiagnose( NETLIST_OBJECT* aItemA, NETLIST_OBJECT* aItemB );
676 
677 
679 {
680  // Similar labels which are different when using case sensitive comparisons
681  // but are equal when using case insensitive comparisons
682 
683  // list of all labels (used the better item to build diag messages)
684  std::vector<NETLIST_OBJECT*> fullLabelList;
685  // list of all labels , each label appears only once (used to to detect similar labels)
686  std::set<NETLIST_OBJECT*, compare_labels> uniqueLabelList;
687  wxString msg;
688 
689  // Build a list of differents labels. If inside a given sheet there are
690  // more than one given label, only one label is stored.
691  // not also the sheet labels are not taken in account for 2 reasons:
692  // * they are in the root sheet but they are seen only from the child sheet
693  // * any mismatch between child sheet hierarchical labels and the sheet label
694  // already detected by ERC
695  for( unsigned netItem = 0; netItem < size(); ++netItem )
696  {
697  switch( GetItemType( netItem ) )
698  {
699  case NETLIST_ITEM::LABEL:
706  // add this label in lists
707  uniqueLabelList.insert( GetItem( netItem ) );
708  fullLabelList.push_back( GetItem( netItem ) );
709  break;
710 
713  default:
714  break;
715  }
716  }
717 
718  // build global labels and compare
719  std::set<NETLIST_OBJECT*, compare_label_names> loc_labelList;
720 
721  for( auto it = uniqueLabelList.begin(); it != uniqueLabelList.end(); ++it )
722  {
723  if( (*it)->IsLabelGlobal() )
724  loc_labelList.insert( *it );
725  }
726 
727  // compare global labels (same label names appears only once in list)
728  for( auto it = loc_labelList.begin(); it != loc_labelList.end(); ++it )
729  {
730  auto it_aux = it;
731 
732  for( ++it_aux; it_aux != loc_labelList.end(); ++it_aux )
733  {
734  if( (*it)->m_Label.CmpNoCase( (*it_aux)->m_Label ) == 0 )
735  {
736  // Create new marker for ERC.
737  int cntA = countIndenticalLabels( fullLabelList, *it );
738  int cntB = countIndenticalLabels( fullLabelList, *it_aux );
739 
740  if( cntA <= cntB )
741  SimilarLabelsDiagnose( (*it), (*it_aux) );
742  else
743  SimilarLabelsDiagnose( (*it_aux), (*it) );
744  }
745  }
746  }
747 
748  // Build paths list
749  std::set<NETLIST_OBJECT*, compare_paths> pathsList;
750 
751  for( auto it = uniqueLabelList.begin(); it != uniqueLabelList.end(); ++it )
752  pathsList.insert( *it );
753 
754  // Examine each label inside a sheet path:
755  for( auto it = pathsList.begin(); it != pathsList.end(); ++it )
756  {
757  loc_labelList.clear();
758 
759  auto it_uniq = uniqueLabelList.begin();
760 
761  for( ; it_uniq != uniqueLabelList.end(); ++it_uniq )
762  {
763  if( ( *it )->m_SheetPath.Path() == ( *it_uniq )->m_SheetPath.Path() )
764  loc_labelList.insert( *it_uniq );
765  }
766 
767  // at this point, loc_labelList contains labels of the current sheet path.
768  // Detect similar labels (same label names appears only once in list)
769 
770  for( auto ref_it = loc_labelList.begin(); ref_it != loc_labelList.end(); ++ref_it )
771  {
772  NETLIST_OBJECT* ref_item = *ref_it;
773  auto it_aux = ref_it;
774 
775  for( ++it_aux; it_aux != loc_labelList.end(); ++it_aux )
776  {
777  // global label versus global label was already examined.
778  // here, at least one label must be local
779  if( ref_item->IsLabelGlobal() && ( *it_aux )->IsLabelGlobal() )
780  continue;
781 
782  if( ref_item->m_Label.CmpNoCase( ( *it_aux )->m_Label ) == 0 )
783  {
784  // Create new marker for ERC.
785  int cntA = countIndenticalLabels( fullLabelList, ref_item );
786  int cntB = countIndenticalLabels( fullLabelList, *it_aux );
787 
788  if( cntA <= cntB )
789  SimilarLabelsDiagnose( ref_item, ( *it_aux ) );
790  else
791  SimilarLabelsDiagnose( ( *it_aux ), ref_item );
792  }
793  }
794  }
795  }
796 }
797 
798 // Helper function: count the number of labels identical to aLabel
799 // for global label: global labels in the full project
800 // for local label: all labels in the current sheet
801 static int countIndenticalLabels( std::vector<NETLIST_OBJECT*>& aList, NETLIST_OBJECT* aRef )
802 {
803  int count = 0;
804 
805  if( aRef->IsLabelGlobal() )
806  {
807  for( auto i : aList)
808  {
809  if( i->IsLabelGlobal() && i->m_Label == aRef->m_Label )
810  count++;
811  }
812  }
813  else
814  {
815  for( auto i : aList)
816  {
817  if( i->m_Label == aRef->m_Label && i->m_SheetPath.Path() == aRef->m_SheetPath.Path() )
818  count++;
819  }
820  }
821 
822  return count;
823 }
824 
825 // Helper function: creates a marker for similar labels ERC warning
826 static void SimilarLabelsDiagnose( NETLIST_OBJECT* aItemA, NETLIST_OBJECT* aItemB )
827 {
828  // Create new marker for ERC.
829  SCH_MARKER* marker = new SCH_MARKER();
830 
831  marker->SetTimeStamp( GetNewTimeStamp() );
834  SCH_SCREEN* screen = aItemA->m_SheetPath.LastScreen();
835  screen->Append( marker );
836 
837  wxString fmt = aItemA->IsLabelGlobal() ? _( "Global label '%s' (sheet '%s') looks like:" ) :
838  _( "Local label '%s' (sheet '%s') looks like:" );
839  wxString msg;
840 
841  msg.Printf( fmt, aItemA->m_Label, aItemA->m_SheetPath.PathHumanReadable() );
842  marker->SetData( aItemA->IsLabelGlobal() && aItemB->IsLabelGlobal() ?
844  aItemA->m_Start, msg, aItemA->m_Start );
845 
846  fmt = aItemB->IsLabelGlobal() ? _( "Global label \"%s\" (sheet \"%s\")" ) :
847  _( "Local label \"%s\" (sheet \"%s\")" );
848  msg.Printf( fmt, aItemB->m_Label, aItemB->m_SheetPath.PathHumanReadable() );
849  marker->SetAuxiliaryData( msg, aItemB->m_Start );
850 }
EDA_UNITS
Definition: common.h:72
SCH_SHEET_LIST.
static int countIndenticalLabels(std::vector< NETLIST_OBJECT * > &aList, NETLIST_OBJECT *aRef)
SCH_COMPONENT * GetComponentParent() const
For Pins (NET_PINS):
SCH_SCREEN * GetNext()
Definition: sch_screen.cpp:981
Definition: erc.h:43
void Diagnose(NETLIST_OBJECT *aNetItemRef, NETLIST_OBJECT *aNetItemTst, int aMinConn, int aDiag)
Performs ERC testing and creates an ERC marker to show the ERC problem for aNetItemRef or between aNe...
const SCH_SHEET_PATH & GetSheetPath() const
const wxString CommentERC_V[]
const wxString CommentERC_H[]
int GetNet() const
SCH_COMPONENT * GetComp() const
EE_TYPE OfType(KICAD_T aType)
Definition: sch_rtree.h:219
int CountPinsInNet(unsigned aNetStart)
Counts number of pins connected on the same net.
SCH_SHEET_PATH m_SheetPath
ELECTRICAL_PINTYPE m_ElectricalPinType
int GetItemNet(unsigned aIdx) const
Acces to an item net code.
Field Name Module PCB, i.e. "16DIP300".
bool IsLabelGlobal() const
Function IsLabelGlobal.
NETLIST_OBJECT_LIST is a container holding and owning NETLIST_OBJECTs, which are connected items in a...
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
#define DRV
Definition: erc.h:79
Definition: erc.h:42
bool WriteDiagnosticERC(EDA_UNITS aUnits, const wxString &aFullFileName)
Function WriteDiagnosticERC save the ERC errors to aFullFileName.
bool operator()(const NETLIST_OBJECT *lab1, const NETLIST_OBJECT *lab2) const
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
Definition: erc.h:44
int GetUnit() const
bool operator()(const NETLIST_OBJECT *lab1, const NETLIST_OBJECT *lab2) const
void TestforSimilarLabels()
Function TestforSimilarLabels detects labels which are different when using case sensitive comparison...
#define NULL
wxString Path() const
Function Path the path uses the time stamps which do not changes even when editing sheet parameters a...
int DiagErc[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]
wxString GetText(GRAPHIC_PINSHAPE aShape)
Definition: pin_shape.cpp:58
int TestDuplicateSheetNames(bool aCreateMarker)
Function TestDuplicateSheetNames( ) inside a given sheet, one cannot have sheets with duplicate names...
void TestforNonOrphanLabel(unsigned aNetItemRef, unsigned aStartNet)
Function TestforNonOrphanLabel Sheet labels are expected to be connected to a hierarchical label.
SCH_SHEET_PATH.
void SetMarkerType(enum TYPEMARKER aMarkerType)
accessors to set/get marker type (DRC, ERC, or other)
Definition: marker_base.h:181
NETLIST_ITEM GetItemType(unsigned aIdx) const
Acces to an item type.
const wxString GetRef(const SCH_SHEET_PATH *aSheet)
Return the reference for the given sheet path.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Type SCH_MULTI_UNIT_REFERENCE_MAP is used to create a map of reference designators for multi-unit par...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:206
void GetMultiUnitComponents(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true)
Function GetMultiUnitComponents adds a SCH_REFERENCE_LIST object to aRefList for each same-reference ...
NETLIST_OBJECT * GetItem(unsigned aIdx) const
Acces to an item in list.
#define NOC
Definition: erc.h:82
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
SCH_SCREEN * LastScreen()
Function LastScreen.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
ELECTRICAL_PINTYPE
The component library pin object electrical types used in ERC tests.
Definition: pin_type.h:37
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:175
#define _(s)
Definition: 3d_actions.cpp:31
void SetErrorLevel(MARKER_SEVERITY aErrorLevel)
accessors to set/get error levels (warning, error, fatal error..)
Definition: marker_base.h:169
#define NPI
Definition: erc.h:78
EE_RTREE & Items()
Definition: sch_screen.h:127
static wxString SubReference(int aUnit, bool aAddSeparator=true)
SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:89
wxPoint GetPosition() const override
Function GetPosition.
int TestConflictingBusAliases(bool aCreateMarker)
Checks that there are not conflicting bus alias definitions in the schematic.
void SetConnectionType(unsigned aIdx, NET_CONNECTION aFlg=NET_CONNECTION::UNCONNECTED)
Set the item connection type: UNCONNECTED Pin or Label not connected (error) NOCONNECT_SYMBOL_PRESENT...
errortype
Definition: erc.h:40
void TestOthersItems(NETLIST_OBJECT_LIST *aList, unsigned aNetItemRef, unsigned aNetStart, int *aMinConnexion)
Perform ERC testing for electrical conflicts between NetItemRef and other items (mainly pin) on the s...
SCH_SCREEN * GetFirst()
Definition: sch_screen.cpp:970
NET_CONNECTION GetConnectionType(unsigned aIdx)
int DefaultDiagErc[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]
Default Look up table which gives the ERC error level for a pair of connected pins Same as DiagErc,...
SCH_SHEET * g_RootSheet
#define NET_NC
Definition: erc.h:80
#define ELECTRICAL_PINTYPES_TOTAL
Definition: pin_type.h:54
void SetData(EDA_UNITS aUnits, int aErrorCode, const wxPoint &aMarkerPos, EDA_ITEM *aItem, const wxPoint &aPos, EDA_ITEM *bItem=nullptr, const wxPoint &bPos=wxPoint())
Function SetData fills in all the reportable data associated with a MARKER.
wxString PathHumanReadable() const
Function PathHumanReadable returns the sheet path in a human readable form, i.e.
not connected (must be left open)
Definition of the NETLIST_OBJECT class.
NETLIST_ITEM m_Type
int TestMultiunitFootprints(SCH_SHEET_LIST &aSheetList)
Test if all units of each multiunit component have the same footprint assigned.
SCH_ITEM * m_Link
bool operator()(const NETLIST_OBJECT *lab1, const NETLIST_OBJECT *lab2) const
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
static int MinimalReq[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]
Look up table which gives the minimal drive for a pair of connected pins on a net.
SCH_REFERENCE is used as a helper to define a component's reference designator in a schematic.
void SetAuxiliaryData(const wxString &aAuxiliaryText, const wxPoint &aAuxiliaryPos)
Function SetAuxiliaryData initialize data for the second (auxiliary) item.
Definition: marker_base.h:225
wxString DateAndTime()
Definition: string.cpp:345
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:498
#define NOD
Definition: erc.h:81
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:212
static void SimilarLabelsDiagnose(NETLIST_OBJECT *aItemA, NETLIST_OBJECT *aItemB)