KiCad PCB EDA Suite
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  * Electrical type of pins:
53  * PIN_INPUT = usual pin input: must be connected
54  * PIN_OUTPUT = usual output
55  * PIN_BIDI = input or output (like port for a microprocessor)
56  * PIN_TRISTATE = tris state bus pin
57  * PIN_PASSIVE = pin for passive components: must be connected, and can be
58  * connected to any pin
59  * PIN_UNSPECIFIED = unknown electrical properties: creates always a warning
60  * when connected
61  * PIN_POWER_IN = power input (GND, VCC for ICs). Must be connected to a power
62  * output.
63  * PIN_POWER_OUT = output of a regulator: intended to be connected to power
64  * input pins
65  * PIN_OPENCOLLECTOR = pin type open collector
66  * PIN_OPENEMITTER = pin type open emitter
67  * PIN_NC = not connected (must be left open)
68  *
69  * Minimal requirements:
70  * All pins *must* be connected (except PIN_NC).
71  * When a pin is not connected in schematic, the user must place a "non
72  * connected" symbol to this pin.
73  * This ensures a forgotten connection will be detected.
74  */
75 
76 /* Messages for conflicts :
77  * PIN_INPUT, PIN_OUTPUT, PIN_BIDI, PIN_TRISTATE, PIN_PASSIVE,
78  * PIN_UNSPECIFIED, PIN_POWER_IN, PIN_POWER_OUT, PIN_OPENCOLLECTOR,
79  * PIN_OPENEMITTER, PIN_NC
80  * These messages are used to show the ERC matrix in ERC dialog
81  */
82 
83 // Messages for matrix rows:
84 const wxString CommentERC_H[] =
85 {
86  _( "Input Pin" ),
87  _( "Output Pin" ),
88  _( "Bidirectional Pin" ),
89  _( "Tri-State Pin" ),
90  _( "Passive Pin" ),
91  _( "Unspecified Pin" ),
92  _( "Power Input Pin" ),
93  _( "Power Output Pin" ),
94  _( "Open Collector" ),
95  _( "Open Emitter" ),
96  _( "No Connection" )
97 };
98 
99 // Messages for matrix columns
100 const wxString CommentERC_V[] =
101 {
102  _( "Input Pin" ),
103  _( "Output Pin" ),
104  _( "Bidirectional Pin" ),
105  _( "Tri-State Pin" ),
106  _( "Passive Pin" ),
107  _( "Unspecified Pin" ),
108  _( "Power Input Pin" ),
109  _( "Power Output Pin" ),
110  _( "Open Collector" ),
111  _( "Open Emitter" ),
112  _( "No Connection" )
113 };
114 
115 
116 /* Look up table which gives the diag for a pair of connected pins
117  * Can be modified by ERC options.
118  * at start up: must be loaded by DefaultDiagErc
119  * Can be modified in dialog ERC
120  */
122 
131 {
132 /* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */
133 /* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
134 /* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR },
135 /* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR },
136 /* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR },
137 /*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
138 /*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR },
139 /*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR },
140 /*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR },
141 /* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
142 /* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
143 /* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }
144 };
145 
146 
158 {
159 /* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */
160 /* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
161 /*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
162 /* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
163 /* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
164 /*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
165 /*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
166 /*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI },
167 /*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
168 /* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
169 /* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
170 /* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI }
171 };
172 
173 
174 int TestDuplicateSheetNames( bool aCreateMarker )
175 {
176  SCH_SCREEN* screen;
177  SCH_ITEM* item;
178  SCH_ITEM* test_item;
179  int err_count = 0;
180  SCH_SCREENS screenList; // Created the list of screen
181 
182  for( screen = screenList.GetFirst(); screen != NULL; screen = screenList.GetNext() )
183  {
184  for( item = screen->GetDrawItems(); item != NULL; item = item->Next() )
185  {
186  // search for a sheet;
187  if( item->Type() != SCH_SHEET_T )
188  continue;
189 
190  for( test_item = item->Next(); test_item != NULL; test_item = test_item->Next() )
191  {
192  if( test_item->Type() != SCH_SHEET_T )
193  continue;
194 
195  // We have found a second sheet: compare names
196  // we are using case insensitive comparison to avoid mistakes between
197  // similar names like Mysheet and mysheet
198  if( ( (SCH_SHEET*) item )->GetName().CmpNoCase(
199  ( ( SCH_SHEET* ) test_item )->GetName() ) == 0 )
200  {
201  if( aCreateMarker )
202  {
203  /* Create a new marker type ERC error*/
204  SCH_MARKER* marker = new SCH_MARKER();
205  marker->SetTimeStamp( GetNewTimeStamp() );
207  ( (SCH_SHEET*) test_item )->GetPosition(),
208  _( "Duplicate sheet name" ),
209  ( (SCH_SHEET*) test_item )->GetPosition() );
212  screen->Append( marker );
213  }
214 
215  err_count++;
216  }
217  }
218  }
219  }
220 
221  return err_count;
222 }
223 
224 
225 int TestConflictingBusAliases( bool aCreateMarker )
226 {
227  wxString msg;
228  wxPoint dummyPos( 0, 0 );
229  int err_count = 0;
230  SCH_SCREENS screens;
231  std::vector< std::shared_ptr<BUS_ALIAS> > aliases;
232 
233  for( auto screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
234  {
235  std::unordered_set< std::shared_ptr<BUS_ALIAS> > screen_aliases = screen->GetBusAliases();
236 
237  for( const std::shared_ptr<BUS_ALIAS>& alias : screen_aliases )
238  {
239  for( const std::shared_ptr<BUS_ALIAS>& test : aliases )
240  {
241  if( alias->GetName() == test->GetName() && alias->Members() != test->Members() )
242  {
243  if( aCreateMarker )
244  {
245  msg = wxString::Format( _( "Bus alias %s has conflicting definitions on"
246  " multiple sheets: %s and %s" ),
247  alias->GetName(),
248  alias->GetParent()->GetFileName(),
249  test->GetParent()->GetFileName() );
250 
251  SCH_MARKER* marker = new SCH_MARKER();
252  marker->SetData( ERCE_BUS_ALIAS_CONFLICT, dummyPos, msg, dummyPos );
253  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
254  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
255 
256  test->GetParent()->Append( marker );
257  }
258 
259  ++err_count;
260  }
261  }
262  }
263 
264  aliases.insert( aliases.end(), screen_aliases.begin(), screen_aliases.end() );
265  }
266 
267  return err_count;
268 }
269 
270 
272 {
273  int errors = 0;
274  std::map<wxString, LIB_ID> footprints;
276  aSheetList.GetMultiUnitComponents( refMap, true );
277 
278  for( auto& component : refMap )
279  {
280  auto& refList = component.second;
281 
282  if( refList.GetCount() == 0 )
283  {
284  wxFAIL; // it should not happen
285  continue;
286  }
287 
288  // Reference footprint
289  wxString fp;
290  wxString unitName;
291 
292  for( unsigned i = 0; i < component.second.GetCount(); ++i )
293  {
294  SCH_COMPONENT* cmp = refList.GetItem( i ).GetComp();
295  SCH_SHEET_PATH sheetPath = refList.GetItem( i ).GetSheetPath();
296  fp = cmp->GetField( FOOTPRINT )->GetText();
297 
298  if( !fp.IsEmpty() )
299  {
300  unitName = cmp->GetRef( &sheetPath )
301  + LIB_PART::SubReference( cmp->GetUnit(), false );
302  break;
303  }
304  }
305 
306  for( unsigned i = 0; i < component.second.GetCount(); ++i )
307  {
308  SCH_REFERENCE& ref = refList.GetItem( i );
309  SCH_COMPONENT* unit = ref.GetComp();
310  SCH_SHEET_PATH sheetPath = refList.GetItem( i ).GetSheetPath();
311  const wxString curFp = unit->GetField( FOOTPRINT )->GetText();
312 
313  if( !curFp.IsEmpty() && fp != curFp )
314  {
315  wxString curUnitName = unit->GetRef( &sheetPath )
316  + LIB_PART::SubReference( unit->GetUnit(), false );
317  wxString msg = wxString::Format( _( "Unit %s has '%s' assigned, "
318  "whereas unit %s has '%s' assigned" ),
319  unitName,
320  fp,
321  curUnitName,
322  curFp );
323  wxPoint pos = unit->GetPosition();
324 
325  SCH_MARKER* marker = new SCH_MARKER();
326  marker->SetTimeStamp( GetNewTimeStamp() );
327  marker->SetData( ERCE_DIFFERENT_UNIT_FP, pos, msg, pos );
330  ref.GetSheetPath().LastScreen()->Append( marker );
331 
332  ++errors;
333  }
334  }
335  }
336 
337  return errors;
338 }
339 
340 
341 void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, int aMinConn, int aDiag )
342 {
343  SCH_MARKER* marker = NULL;
344  SCH_SCREEN* screen;
345  ELECTRICAL_PINTYPE ii, jj;
346 
347  if( aDiag == OK || aMinConn < 1 )
348  return;
349 
350  /* Create new marker for ERC error. */
351  marker = new SCH_MARKER();
352  marker->SetTimeStamp( GetNewTimeStamp() );
353 
356  screen = aNetItemRef->m_SheetPath.LastScreen();
357  screen->Append( marker );
358 
359  wxString msg;
360 
361  ii = aNetItemRef->m_ElectricalPinType;
362 
363  wxString cmp_ref( "?" );
364 
365  if( aNetItemRef->m_Type == NET_PIN && aNetItemRef->m_Link )
366  cmp_ref = aNetItemRef->GetComponentParent()->GetRef( &aNetItemRef->m_SheetPath );
367 
368  if( aNetItemTst == NULL )
369  {
370  if( aMinConn == NOD ) /* Nothing driving the net. */
371  {
372  if( aNetItemRef->m_Type == NET_PIN && aNetItemRef->m_Link )
373  cmp_ref = aNetItemRef->GetComponentParent()->GetRef(
374  &aNetItemRef->m_SheetPath );
375 
376  msg.Printf( _( "Pin %s (%s) of component %s is not driven (Net %d)." ),
377  aNetItemRef->m_PinNum,
378  GetChars( GetText( ii ) ),
379  GetChars( cmp_ref ),
380  aNetItemRef->GetNet() );
381  marker->SetData( ERCE_PIN_NOT_DRIVEN, aNetItemRef->m_Start, msg, aNetItemRef->m_Start );
382  return;
383  }
384  }
385 
386  if( aNetItemTst ) /* Error between 2 pins */
387  {
388  jj = aNetItemTst->m_ElectricalPinType;
390 
391  if( aDiag == ERR )
392  {
395  }
396 
397  wxString alt_cmp( "?" );
398 
399  if( aNetItemTst->m_Type == NET_PIN && aNetItemTst->m_Link )
400  alt_cmp = aNetItemTst->GetComponentParent()->GetRef( &aNetItemTst->m_SheetPath );
401 
402  msg.Printf( _( "Pin %s (%s) of component %s is connected to " ),
403  aNetItemRef->m_PinNum,
404  GetChars( GetText( ii ) ),
405  GetChars( cmp_ref ) );
406  marker->SetData( errortype, aNetItemRef->m_Start, msg, aNetItemRef->m_Start );
407  msg.Printf( _( "pin %s (%s) of component %s (net %d)." ),
408  aNetItemTst->m_PinNum,
409  GetChars( GetText( jj ) ),
410  GetChars( alt_cmp ),
411  aNetItemRef->GetNet() );
412  marker->SetAuxiliaryData( msg, aNetItemTst->m_Start );
413  }
414 }
415 
416 
417 void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aNetStart,
418  int* aMinConnexion )
419 {
420  unsigned netItemTst = aNetStart;
422  int erc = OK;
423 
424  /* Analysis of the table of connections. */
425  ELECTRICAL_PINTYPE ref_elect_type = aList->GetItem( aNetItemRef )->m_ElectricalPinType;
426  int local_minconn = NOC;
427 
428  if( ref_elect_type == PIN_NC )
429  local_minconn = NPI;
430 
431  /* Test pins connected to NetItemRef */
432  for( ; ; netItemTst++ )
433  {
434  if( aNetItemRef == netItemTst )
435  continue;
436 
437  // We examine only a given net. We stop the search if the net changes
438  if( ( netItemTst >= aList->size() ) // End of list
439  || ( aList->GetItemNet( aNetItemRef ) !=
440  aList->GetItemNet( netItemTst ) ) ) // End of net
441  {
442  /* End net code found: minimum connection test. */
443  if( ( *aMinConnexion < NET_NC ) && ( local_minconn < NET_NC ) )
444  {
445  /* Not connected or not driven pin. */
446  bool seterr = true;
447 
448  if( local_minconn == NOC &&
449  aList->GetItemType( aNetItemRef ) == NET_PIN )
450  {
451  /* This pin is not connected: for multiple part per
452  * package, and duplicated pin,
453  * search for another instance of this pin
454  * this will be flagged only if all instances of this pin
455  * are not connected
456  * TODO test also if instances connected are connected to
457  * the same net
458  */
459  for( unsigned duplicate = 0; duplicate < aList->size(); duplicate++ )
460  {
461  if( aList->GetItemType( duplicate ) != NET_PIN )
462  continue;
463 
464  if( duplicate == aNetItemRef )
465  continue;
466 
467  if( aList->GetItem( aNetItemRef )->m_PinNum !=
468  aList->GetItem( duplicate )->m_PinNum )
469  continue;
470 
471  if( ( (SCH_COMPONENT*) aList->GetItem( aNetItemRef )->
472  m_Link )->GetRef( &aList->GetItem( aNetItemRef )-> m_SheetPath ) !=
473  ( (SCH_COMPONENT*) aList->GetItem( duplicate )->m_Link )
474  ->GetRef( &aList->GetItem( duplicate )->m_SheetPath ) )
475  continue;
476 
477  // Same component and same pin. Do dot create error for this pin
478  // if the other pin is connected (i.e. if duplicate net has another
479  // item)
480  if( (duplicate > 0)
481  && ( aList->GetItemNet( duplicate ) ==
482  aList->GetItemNet( duplicate - 1 ) ) )
483  seterr = false;
484 
485  if( (duplicate < aList->size() - 1)
486  && ( aList->GetItemNet( duplicate ) ==
487  aList->GetItemNet( duplicate + 1 ) ) )
488  seterr = false;
489  }
490  }
491 
492  if( seterr )
493  Diagnose( aList->GetItem( aNetItemRef ), NULL, local_minconn, WAR );
494 
495  *aMinConnexion = DRV; // inhibiting other messages of this
496  // type for the net.
497  }
498  return;
499  }
500 
501  switch( aList->GetItemType( netItemTst ) )
502  {
504  case NET_SEGMENT:
505  case NET_BUS:
506  case NET_JUNCTION:
507  case NET_LABEL:
508  case NET_HIERLABEL:
509  case NET_BUSLABELMEMBER:
512  case NET_SHEETLABEL:
513  case NET_GLOBLABEL:
515  case NET_PINLABEL:
516  break;
517 
518  case NET_NOCONNECT:
519  local_minconn = std::max( NET_NC, local_minconn );
520  break;
521 
522  case NET_PIN:
523  jj = aList->GetItem( netItemTst )->m_ElectricalPinType;
524  local_minconn = std::max( MinimalReq[ref_elect_type][jj], local_minconn );
525 
526  if( netItemTst <= aNetItemRef )
527  break;
528 
529  if( erc == OK )
530  {
531  erc = DiagErc[ref_elect_type][jj];
532 
533  if( erc != OK )
534  {
535  if( aList->GetConnectionType( netItemTst ) == UNCONNECTED )
536  {
537  Diagnose( aList->GetItem( aNetItemRef ),
538  aList->GetItem( netItemTst ),
539  0, erc );
540  aList->SetConnectionType( netItemTst, NOCONNECT_SYMBOL_PRESENT );
541  }
542  }
543  }
544 
545  break;
546  }
547  }
548 }
549 
550 int NETLIST_OBJECT_LIST::CountPinsInNet( unsigned aNetStart )
551 {
552  int count = 0;
553  int curr_net = GetItemNet( aNetStart );
554 
555  /* Test pins connected to NetItemRef */
556  for( unsigned item = aNetStart; item < size(); item++ )
557  {
558  // We examine only a given net. We stop the search if the net changes
559  if( curr_net != GetItemNet( item ) ) // End of net
560  break;
561 
562  if( GetItemType( item ) == NET_PIN )
563  count++;
564  }
565 
566  return count;
567 }
568 
569 bool WriteDiagnosticERC( EDA_UNITS_T aUnits, const wxString& aFullFileName )
570 {
571  wxFFile file( aFullFileName, wxT( "wt" ) );
572 
573  if( !file.IsOpened() )
574  return false;
575 
576  wxString msg = wxString::Format( _( "ERC report (%s, Encoding UTF8)\n" ), DateAndTime() );
577  int err_count = 0;
578  int warn_count = 0;
579  int total_count = 0;
580  SCH_SHEET_LIST sheetList( g_RootSheet );
581 
582  for( unsigned i = 0; i < sheetList.size(); i++ )
583  {
584  msg << wxString::Format( _( "\n***** Sheet %s\n" ),
585  GetChars( sheetList[i].PathHumanReadable() ) );
586 
587  for( SCH_ITEM* item = sheetList[i].LastDrawList(); item != NULL; item = item->Next() )
588  {
589  if( item->Type() != SCH_MARKER_T )
590  continue;
591 
592  SCH_MARKER* marker = (SCH_MARKER*) item;
593 
594  if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
595  continue;
596 
597  total_count++;
598 
600  err_count++;
601 
603  warn_count++;
604 
605  msg << marker->GetReporter().ShowReport( aUnits );
606  }
607  }
608 
609  msg << wxString::Format( _( "\n ** ERC messages: %d Errors %d Warnings %d\n" ),
610  total_count, err_count, warn_count );
611 
612  // Currently: write report using UTF8 (as usual in Kicad).
613  // TODO: see if we can use the current encoding page (mainly for Windows users),
614  // Or other format (HTML?)
615  file.Write( msg );
616 
617  // wxFFile dtor will close the file.
618 
619  return true;
620 }
621 
622 
623 void NETLIST_OBJECT_LIST::TestforNonOrphanLabel( unsigned aNetItemRef, unsigned aStartNet )
624 {
625  unsigned netItemTst = aStartNet;
626  int erc = 1;
627 
628  // Review the list of labels connected to NetItemRef:
629  for( ; ; netItemTst++ )
630  {
631  if( netItemTst == aNetItemRef )
632  continue;
633 
634  /* Is always in the same net? */
635  if( ( netItemTst == size() )
636  || ( GetItemNet( aNetItemRef ) != GetItemNet( netItemTst ) ) )
637  {
638  /* End Netcode found. */
639  if( erc )
640  {
641  /* Glabel or SheetLabel orphaned. */
642  Diagnose( GetItem( aNetItemRef ), NULL, -1, WAR );
643  }
644 
645  return;
646  }
647 
648  if( GetItem( aNetItemRef )->IsLabelConnected( GetItem( netItemTst ) ) )
649  erc = 0;
650 
651  //same thing, different order.
652  if( GetItem( netItemTst )->IsLabelConnected( GetItem( aNetItemRef ) ) )
653  erc = 0;
654  }
655 }
656 
657 
658 // this code try to detect similar labels, i.e. labels which are identical
659 // when they are compared using case insensitive coparisons.
660 
661 
662 // A helper struct to compare NETLIST_OBJECT items by sheetpath and label texts
663 // for a std::set<NETLIST_OBJECT*> container
664 // the full text is "sheetpath+label" for local labels and "label" for global labels
666 {
667  bool operator() ( const NETLIST_OBJECT* lab1, const NETLIST_OBJECT* lab2 )
668  {
669  wxString str1 = lab1->m_SheetPath.Path() + lab1->m_Label;
670  wxString str2 = lab2->m_SheetPath.Path() + lab2->m_Label;
671 
672  return str1.Cmp( str2 ) < 0;
673  }
674 };
675 
677 {
678  bool operator() ( const NETLIST_OBJECT* lab1, const NETLIST_OBJECT* lab2 )
679  {
680  return lab1->m_Label.Cmp( lab2->m_Label ) < 0;
681  }
682 };
683 
685 {
686  bool operator() ( const NETLIST_OBJECT* lab1, const NETLIST_OBJECT* lab2 )
687  {
688  return lab1->m_SheetPath.Path().Cmp( lab2->m_SheetPath.Path() ) < 0;
689  }
690 };
691 
692 // Helper functions to build the warning messages about Similar Labels:
693 static int countIndenticalLabels( std::vector<NETLIST_OBJECT*>& aList, NETLIST_OBJECT* aRef );
694 static void SimilarLabelsDiagnose( NETLIST_OBJECT* aItemA, NETLIST_OBJECT* aItemB );
695 
696 
698 {
699  // Similar labels which are different when using case sensitive comparisons
700  // but are equal when using case insensitive comparisons
701 
702  // list of all labels (used the better item to build diag messages)
703  std::vector<NETLIST_OBJECT*> fullLabelList;
704  // list of all labels , each label appears only once (used to to detect similar labels)
705  std::set<NETLIST_OBJECT*, compare_labels> uniqueLabelList;
706  wxString msg;
707 
708  // Build a list of differents labels. If inside a given sheet there are
709  // more than one given label, only one label is stored.
710  // not also the sheet labels are not taken in account for 2 reasons:
711  // * they are in the root sheet but they are seen only from the child sheet
712  // * any mismatch between child sheet hierarchical labels and the sheet label
713  // already detected by ERC
714  for( unsigned netItem = 0; netItem < size(); ++netItem )
715  {
716  switch( GetItemType( netItem ) )
717  {
718  case NET_LABEL:
719  case NET_BUSLABELMEMBER:
720  case NET_PINLABEL:
722  case NET_HIERLABEL:
724  case NET_GLOBLABEL:
725  // add this label in lists
726  uniqueLabelList.insert( GetItem( netItem ) );
727  fullLabelList.push_back( GetItem( netItem ) );
728  break;
729 
730  case NET_SHEETLABEL:
732  default:
733  break;
734  }
735  }
736 
737  // build global labels and compare
738  std::set<NETLIST_OBJECT*, compare_label_names> loc_labelList;
739 
740  for( auto it = uniqueLabelList.begin(); it != uniqueLabelList.end(); ++it )
741  {
742  if( (*it)->IsLabelGlobal() )
743  loc_labelList.insert( *it );
744  }
745 
746  // compare global labels (same label names appears only once in list)
747  for( auto it = loc_labelList.begin(); it != loc_labelList.end(); ++it )
748  {
749  auto it_aux = it;
750 
751  for( ++it_aux; it_aux != loc_labelList.end(); ++it_aux )
752  {
753  if( (*it)->m_Label.CmpNoCase( (*it_aux)->m_Label ) == 0 )
754  {
755  // Create new marker for ERC.
756  int cntA = countIndenticalLabels( fullLabelList, *it );
757  int cntB = countIndenticalLabels( fullLabelList, *it_aux );
758 
759  if( cntA <= cntB )
760  SimilarLabelsDiagnose( (*it), (*it_aux) );
761  else
762  SimilarLabelsDiagnose( (*it_aux), (*it) );
763  }
764  }
765  }
766 
767  // Build paths list
768  std::set<NETLIST_OBJECT*, compare_paths> pathsList;
769 
770  for( auto it = uniqueLabelList.begin(); it != uniqueLabelList.end(); ++it )
771  pathsList.insert( *it );
772 
773  // Examine each label inside a sheet path:
774  for( auto it = pathsList.begin(); it != pathsList.end(); ++it )
775  {
776  loc_labelList.clear();
777 
778  auto it_uniq = uniqueLabelList.begin();
779 
780  for( ; it_uniq != uniqueLabelList.end(); ++it_uniq )
781  {
782  if( ( *it )->m_SheetPath.Path() == ( *it_uniq )->m_SheetPath.Path() )
783  loc_labelList.insert( *it_uniq );
784  }
785 
786  // at this point, loc_labelList contains labels of the current sheet path.
787  // Detect similar labels (same label names appears only once in list)
788 
789  for( auto ref_it = loc_labelList.begin(); ref_it != loc_labelList.end(); ++ref_it )
790  {
791  NETLIST_OBJECT* ref_item = *ref_it;
792  auto it_aux = ref_it;
793 
794  for( ++it_aux; it_aux != loc_labelList.end(); ++it_aux )
795  {
796  // global label versus global label was already examined.
797  // here, at least one label must be local
798  if( ref_item->IsLabelGlobal() && ( *it_aux )->IsLabelGlobal() )
799  continue;
800 
801  if( ref_item->m_Label.CmpNoCase( ( *it_aux )->m_Label ) == 0 )
802  {
803  // Create new marker for ERC.
804  int cntA = countIndenticalLabels( fullLabelList, ref_item );
805  int cntB = countIndenticalLabels( fullLabelList, *it_aux );
806 
807  if( cntA <= cntB )
808  SimilarLabelsDiagnose( ref_item, ( *it_aux ) );
809  else
810  SimilarLabelsDiagnose( ( *it_aux ), ref_item );
811  }
812  }
813  }
814  }
815 }
816 
817 // Helper function: count the number of labels identical to aLabel
818 // for global label: global labels in the full project
819 // for local label: all labels in the current sheet
820 static int countIndenticalLabels( std::vector<NETLIST_OBJECT*>& aList, NETLIST_OBJECT* aRef )
821 {
822  int count = 0;
823 
824  if( aRef->IsLabelGlobal() )
825  {
826  for( auto i : aList)
827  {
828  if( i->IsLabelGlobal() && i->m_Label == aRef->m_Label )
829  count++;
830  }
831  }
832  else
833  {
834  for( auto i : aList)
835  {
836  if( i->m_Label == aRef->m_Label && i->m_SheetPath.Path() == aRef->m_SheetPath.Path() )
837  count++;
838  }
839  }
840 
841  return count;
842 }
843 
844 // Helper function: creates a marker for similar labels ERC warning
845 static void SimilarLabelsDiagnose( NETLIST_OBJECT* aItemA, NETLIST_OBJECT* aItemB )
846 {
847  // Create new marker for ERC.
848  SCH_MARKER* marker = new SCH_MARKER();
849 
850  marker->SetTimeStamp( GetNewTimeStamp() );
853  SCH_SCREEN* screen = aItemA->m_SheetPath.LastScreen();
854  screen->Append( marker );
855 
856  wxString fmt = aItemA->IsLabelGlobal() ? _( "Global label '%s' (sheet '%s') looks like:" ) :
857  _( "Local label '%s' (sheet '%s') looks like:" );
858  wxString msg;
859 
860  msg.Printf( fmt, aItemA->m_Label, aItemA->m_SheetPath.PathHumanReadable() );
861  marker->SetData( aItemA->IsLabelGlobal() && aItemB->IsLabelGlobal() ?
863  aItemA->m_Start, msg, aItemA->m_Start );
864 
865  fmt = aItemB->IsLabelGlobal() ? _( "Global label \"%s\" (sheet \"%s\")" ) :
866  _( "Local label \"%s\" (sheet \"%s\")" );
867  msg.Printf( fmt, aItemB->m_Label, aItemB->m_SheetPath.PathHumanReadable() );
868  marker->SetAuxiliaryData( msg, aItemB->m_Start );
869 }
Class SCH_SHEET_LIST.
static int countIndenticalLabels(std::vector< NETLIST_OBJECT * > &aList, NETLIST_OBJECT *aRef)
Definition: erc.cpp:820
SCH_COMPONENT * GetComponentParent() const
For Pins (NET_PINS):
SCH_SCREEN * GetNext()
Definition: erc.h:43
bool operator()(const NETLIST_OBJECT *lab1, const NETLIST_OBJECT *lab2)
Definition: erc.cpp:678
const DRC_ITEM & GetReporter() const
Function GetReporter returns the DRC_ITEM held within this MARKER so that its interface may be used.
Definition: marker_base.h:243
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...
Definition: erc.cpp:417
const SCH_SHEET_PATH & GetSheetPath() const
SCH_ITEM * Next() const
Definition: sch_item.h:153
MARKER_SEVERITY GetErrorLevel() const
Definition: marker_base.h:175
int TestConflictingBusAliases(bool aCreateMarker)
Checks that there are not conflicting bus alias definitions in the schematic.
Definition: erc.cpp:225
int GetNet() const
int DiagErc[PINTYPE_COUNT][PINTYPE_COUNT]
Definition: erc.cpp:121
SCH_COMPONENT * GetComp() const
const wxString CommentERC_H[]
Definition: erc.cpp:84
void SetData(EDA_UNITS_T 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.
int CountPinsInNet(unsigned aNetStart)
Counts number of pins connected on the same net.
Definition: erc.cpp:550
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...
Definition: erc.cpp:341
SCH_SHEET_PATH m_SheetPath
ELECTRICAL_PINTYPE m_ElectricalPinType
NETLIST_ITEM_T m_Type
int GetItemNet(unsigned aIdx) const
Acces to an item net code.
bool WriteDiagnosticERC(EDA_UNITS_T aUnits, const wxString &aFullFileName)
Function WriteDiagnosticERC save the ERC errors to aFullFileName.
Definition: erc.cpp:569
Field Name Module PCB, i.e. "16DIP300".
void SetConnectionType(unsigned aIdx, NET_CONNECTION_T aFlg=UNCONNECTED)
Set the item connection type: UNCONNECTED Pin or Label not connected (error) NOCONNECT_SYMBOL_PRESENT...
bool IsLabelGlobal() const
Function IsLabelGlobal.
Class NETLIST_OBJECT_LIST is a container holding and owning NETLIST_OBJECTs, which are connected item...
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
#define DRV
Definition: erc.h:79
Definition: erc.h:42
timestamp_t GetNewTimeStamp()
Definition: common.cpp:217
Definition: erc.h:44
bool operator()(const NETLIST_OBJECT *lab1, const NETLIST_OBJECT *lab2)
Definition: erc.cpp:686
int GetUnit() const
int TestDuplicateSheetNames(bool aCreateMarker)
Function TestDuplicateSheetNames( ) inside a given sheet, one cannot have sheets with duplicate names...
Definition: erc.cpp:174
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:47
void TestforSimilarLabels()
Function TestforSimilarLabels detects labels which are different when using case sensitive comparison...
Definition: erc.cpp:697
wxString Path() const
Function Path the path uses the time stamps which do not changes even when editing sheet parameters a...
void TestforNonOrphanLabel(unsigned aNetItemRef, unsigned aStartNet)
Function TestforNonOrphanLabel Sheet labels are expected to be connected to a hierarchical label.
Definition: erc.cpp:623
wxString GetText(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:33
Class SCH_SHEET_PATH.
void SetMarkerType(enum TYPEMARKER aMarkerType)
accessors to set/get marker type (DRC, ERC, or other)
Definition: marker_base.h:182
const wxString GetRef(const SCH_SHEET_PATH *aSheet)
Return the reference for the given sheet path.
#define _(s)
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:204
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 ...
bool operator()(const NETLIST_OBJECT *lab1, const NETLIST_OBJECT *lab2)
Definition: erc.cpp:667
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
NET_CONNECTION_T GetConnectionType(unsigned aIdx)
static int MinimalReq[PINTYPE_COUNT][PINTYPE_COUNT]
Look up table which gives the minimal drive for a pair of connected pins on a net.
Definition: erc.cpp:157
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.h:149
enum TYPEMARKER GetMarkerType() const
Definition: marker_base.h:187
#define max(a, b)
Definition: auxiliary.h:86
void SetErrorLevel(MARKER_SEVERITY aErrorLevel)
accessors to set/get error levels (warning, error, fatal error..)
Definition: marker_base.h:170
#define NPI
Definition: erc.h:78
size_t i
Definition: json11.cpp:597
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:73
wxPoint GetPosition() const override
Function GetPosition.
int DefaultDiagErc[PINTYPE_COUNT][PINTYPE_COUNT]
Default Look up table which gives the ERC error level for a pair of connected pins Same as DiagErc,...
Definition: erc.cpp:130
const wxString CommentERC_V[]
Definition: erc.cpp:100
errortype
Definition: erc.h:40
wxString ShowReport(EDA_UNITS_T aUnits) const
Function ShowReport translates this object into a text string suitable for saving to disk in a report...
Definition: drc_item.cpp:229
SCH_SCREEN * GetFirst()
#define NET_NC
Definition: erc.h:80
wxString PathHumanReadable() const
Function PathHumanReadable returns the sheet path in a human readable form, i.e.
Definition of the NETLIST_OBJECT class.
SCH_ITEM * m_Link
NETLIST_ITEM_T GetItemType(unsigned aIdx) const
Acces to an item type.
int TestMultiunitFootprints(SCH_SHEET_LIST &aSheetList)
Test if all units of each multiunit component have the same footprint assigned.
Definition: erc.cpp:271
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Definition: sch_item.h:114
virtual const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:124
EDA_UNITS_T
Definition: common.h:154
Class 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:227
wxString DateAndTime()
Definition: string.cpp:333
static void SimilarLabelsDiagnose(NETLIST_OBJECT *aItemA, NETLIST_OBJECT *aItemB)
Definition: erc.cpp:845
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:486
#define NOD
Definition: erc.h:81
SCH_SCREEN * LastScreen() const
Function LastScreen.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:215
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:147