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