KiCad PCB EDA Suite
CONNECTION_GRAPH Class Reference

Calculates the connectivity of a schematic and generates netlists. More...

#include <connection_graph.h>

Public Member Functions

 CONNECTION_GRAPH (SCHEMATIC *aSchematic=nullptr)
 
 ~CONNECTION_GRAPH ()
 
void Reset ()
 
void SetSchematic (SCHEMATIC *aSchematic)
 
void Recalculate (const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
 Updates the connection graph for the given list of sheets. More...
 
std::shared_ptr< BUS_ALIASGetBusAlias (const wxString &aName)
 Returns a bus alias pointer for the given name if it exists (from cache) More...
 
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration ()
 Determines which subgraphs have more than one conflicting bus label. More...
 
int RunERC ()
 Runs electrical rule checks on the connectivity graph. More...
 
const NET_MAPGetNetMap () const
 
CONNECTION_SUBGRAPHFindSubgraphByName (const wxString &aNetName, const SCH_SHEET_PATH &aPath)
 Returns the subgraph for a given net name on a given sheet. More...
 
CONNECTION_SUBGRAPHFindFirstSubgraphByName (const wxString &aNetName)
 Retrieves a subgraph for the given net name, if one exists. More...
 
CONNECTION_SUBGRAPHGetSubgraphForItem (SCH_ITEM *aItem)
 

Static Public Attributes

static bool m_allowRealTime = true
 

Private Member Functions

void updateItemConnectivity (const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
 Updates the graphical connectivity between items (i.e. More...
 
void buildConnectionGraph ()
 Generates the connection graph (after all item connectivity has been updated) More...
 
int assignNewNetCode (SCH_CONNECTION &aConnection)
 Helper to assign a new net code to a connection. More...
 
void assignNetCodesToBus (SCH_CONNECTION *aConnection)
 Ensures all members of the bus connection have a valid net code assigned. More...
 
void propagateToNeighbors (CONNECTION_SUBGRAPH *aSubgraph)
 Updates all neighbors of a subgraph with this one's connectivity info. More...
 
std::shared_ptr< SCH_CONNECTIONgetDefaultConnection (SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
 Builds a new default connection for the given item based on its properties. More...
 
void recacheSubgraphName (CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
 
bool ercCheckMultipleDrivers (const CONNECTION_SUBGRAPH *aSubgraph)
 If the subgraph has multiple drivers of equal priority that are graphically connected, ResolveDrivers() will have stored the second driver for use by this function, which actually creates the markers. More...
 
bool ercCheckBusToNetConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting connections between net and bus labels. More...
 
bool ercCheckBusToBusConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting connections between two bus items. More...
 
bool ercCheckBusToBusEntryConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting bus entry to bus connections. More...
 
bool ercCheckNoConnects (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for proper presence or absence of no-connect symbols. More...
 
bool ercCheckFloatingWires (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for floating wires. More...
 
bool ercCheckLabels (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for proper connection of labels. More...
 
int ercCheckHierSheets ()
 Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on the parent sheet object. More...
 

Static Private Member Functions

static SCH_CONNECTIONmatchBusMember (SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
 Search for a matching bus member inside a bus connection. More...
 

Private Attributes

SCH_SHEET_LIST m_sheetList
 
std::vector< SCH_ITEM * > m_items
 
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
 
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
 
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
 
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
 
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
 
std::map< wxString, int > m_net_name_to_code_map
 
std::map< wxString, int > m_bus_name_to_code_map
 
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
 
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
 
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
 
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
 
NET_MAP m_net_code_to_subgraphs_map
 
int m_last_net_code
 
int m_last_bus_code
 
int m_last_subgraph_code
 
SCHEMATICm_schematic
 The schematic this graph represents. More...
 

Detailed Description

Calculates the connectivity of a schematic and generates netlists.

Definition at line 248 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCHEMATIC aSchematic = nullptr)
inline

Definition at line 251 of file connection_graph.h.

251  :
252  m_last_net_code( 1 ),
253  m_last_bus_code( 1 ),
255  m_schematic( aSchematic )
256  {}
SCHEMATIC * m_schematic
The schematic this graph represents.

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 258 of file connection_graph.h.

259  {
260  Reset();
261  }

References Reset().

Member Function Documentation

◆ assignNetCodesToBus()

void CONNECTION_GRAPH::assignNetCodesToBus ( SCH_CONNECTION aConnection)
private

Ensures all members of the bus connection have a valid net code assigned.

Parameters
aConnectionis a bus connection

Definition at line 1595 of file connection_graph.cpp.

1596 {
1597  auto connections_to_check( aConnection->Members() );
1598 
1599  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1600  {
1601  auto member = connections_to_check[i];
1602 
1603  if( member->IsBus() )
1604  {
1605  connections_to_check.insert( connections_to_check.end(),
1606  member->Members().begin(),
1607  member->Members().end() );
1608  continue;
1609  }
1610 
1611  assignNewNetCode( *member );
1612  }
1613 }
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()

References assignNewNetCode(), and SCH_CONNECTION::Members().

Referenced by buildConnectionGraph().

◆ assignNewNetCode()

int CONNECTION_GRAPH::assignNewNetCode ( SCH_CONNECTION aConnection)
private

Helper to assign a new net code to a connection.

Returns
the assigned code

Definition at line 1573 of file connection_graph.cpp.

1574 {
1575  int code;
1576 
1577  auto it = m_net_name_to_code_map.find( aConnection.Name() );
1578 
1579  if( it == m_net_name_to_code_map.end() )
1580  {
1581  code = m_last_net_code++;
1582  m_net_name_to_code_map[ aConnection.Name() ] = code;
1583  }
1584  else
1585  {
1586  code = it->second;
1587  }
1588 
1589  aConnection.SetNetCode( code );
1590 
1591  return code;
1592 }
wxString Name(bool aIgnoreSheet=false) const
std::map< wxString, int > m_net_name_to_code_map
void SetNetCode(int aCode)

References m_last_net_code, m_net_name_to_code_map, SCH_CONNECTION::Name(), and SCH_CONNECTION::SetNetCode().

Referenced by assignNetCodesToBus(), and buildConnectionGraph().

◆ buildConnectionGraph()

void CONNECTION_GRAPH::buildConnectionGraph ( )
private

Generates the connection graph (after all item connectivity has been updated)

In the first phase, the algorithm iterates over all items, and then over all items that are connected (graphically) to each item, placing them into CONNECTION_SUBGRAPHs. Items that can potentially drive connectivity (i.e. labels, pins, etc.) are added to the m_drivers vector of the subgraph.

In the second phase, each subgraph is resolved. To resolve a subgraph, the driver is first selected by CONNECTION_SUBGRAPH::ResolveDrivers(), and then the connection for the chosen driver is propagated to all the other items in the subgraph.

TODO(JE): Net codes are non-deterministic. Fortunately, they are also not really used for anything. We should consider removing them entirely and just using net names everywhere.

Definition at line 704 of file connection_graph.cpp.

705 {
706  // Recache all bus aliases for later use
707  wxCHECK_RET( m_schematic, "Connection graph cannot be built without schematic pointer" );
708 
709  SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
710 
711  for( unsigned i = 0; i < all_sheets.size(); i++ )
712  {
713  for( const auto& alias : all_sheets[i].LastScreen()->GetBusAliases() )
714  m_bus_alias_cache[ alias->GetName() ] = alias;
715  }
716 
717  // Build subgraphs from items (on a per-sheet basis)
718 
719  for( SCH_ITEM* item : m_items )
720  {
721  for( const auto& it : item->m_connection_map )
722  {
723  const auto sheet = it.first;
724  auto connection = it.second;
725 
726  if( connection->SubgraphCode() == 0 )
727  {
728  CONNECTION_SUBGRAPH* subgraph = new CONNECTION_SUBGRAPH( this );
729 
730  subgraph->m_code = m_last_subgraph_code++;
731  subgraph->m_sheet = sheet;
732 
733  subgraph->AddItem( item );
734 
735  connection->SetSubgraphCode( subgraph->m_code );
736  m_item_to_subgraph_map[item] = subgraph;
737 
738  std::list<SCH_ITEM*> members;
739 
740  auto get_items =
741  [&]( SCH_ITEM* aItem ) -> bool
742  {
743  SCH_CONNECTION* conn = aItem->Connection( &sheet );
744 
745  if( !conn )
746  conn = aItem->InitializeConnection( sheet, this );
747 
748  return ( conn->SubgraphCode() == 0 );
749  };
750 
751  std::copy_if( item->ConnectedItems( sheet ).begin(),
752  item->ConnectedItems( sheet ).end(),
753  std::back_inserter( members ), get_items );
754 
755  for( SCH_ITEM* connected_item : members )
756  {
757  if( connected_item->Type() == SCH_NO_CONNECT_T )
758  subgraph->m_no_connect = connected_item;
759 
760  SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
761 
762  wxASSERT( connected_conn );
763 
764  if( connected_conn->SubgraphCode() == 0 )
765  {
766  connected_conn->SetSubgraphCode( subgraph->m_code );
767  m_item_to_subgraph_map[connected_item] = subgraph;
768  subgraph->AddItem( connected_item );
769 
770  std::copy_if( connected_item->ConnectedItems( sheet ).begin(),
771  connected_item->ConnectedItems( sheet ).end(),
772  std::back_inserter( members ), get_items );
773  }
774  }
775 
776  subgraph->m_dirty = true;
777  m_subgraphs.push_back( subgraph );
778  }
779  }
780  }
781 
787  // Resolve drivers for subgraphs and propagate connectivity info
788 
789  // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
790  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
791  ( m_subgraphs.size() + 3 ) / 4 );
792 
793  std::atomic<size_t> nextSubgraph( 0 );
794  std::vector<std::future<size_t>> returns( parallelThreadCount );
795  std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
796 
797  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( dirty_graphs ),
798  [&] ( const CONNECTION_SUBGRAPH* candidate )
799  {
800  return candidate->m_dirty;
801  } );
802 
803  auto update_lambda = [&nextSubgraph, &dirty_graphs]() -> size_t
804  {
805  for( size_t subgraphId = nextSubgraph++; subgraphId < dirty_graphs.size(); subgraphId = nextSubgraph++ )
806  {
807  auto subgraph = dirty_graphs[subgraphId];
808 
809  if( !subgraph->m_dirty )
810  continue;
811 
812  // Special processing for some items
813  for( auto item : subgraph->m_items )
814  {
815  switch( item->Type() )
816  {
817  case SCH_NO_CONNECT_T:
818  subgraph->m_no_connect = item;
819  break;
820 
822  subgraph->m_bus_entry = item;
823  break;
824 
825  case SCH_PIN_T:
826  {
827  auto pin = static_cast<SCH_PIN*>( item );
828 
829  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
830  subgraph->m_no_connect = item;
831 
832  break;
833  }
834 
835  default:
836  break;
837  }
838  }
839 
840  subgraph->ResolveDrivers( true );
841  subgraph->m_dirty = false;
842  }
843 
844  return 1;
845  };
846 
847  if( parallelThreadCount == 1 )
848  update_lambda();
849  else
850  {
851  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
852  returns[ii] = std::async( std::launch::async, update_lambda );
853 
854  // Finalize the threads
855  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
856  returns[ii].wait();
857  }
858 
859  // Now discard any non-driven subgraphs from further consideration
860 
861  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( m_driver_subgraphs ),
862  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
863  {
864  return candidate->m_driver;
865  } );
866 
867  // Check for subgraphs with the same net name but only weak drivers.
868  // For example, two wires that are both connected to hierarchical
869  // sheet pins that happen to have the same name, but are not the same.
870 
871  for( auto&& subgraph : m_driver_subgraphs )
872  {
873  wxString full_name = subgraph->m_driver_connection->Name();
874  wxString name = subgraph->m_driver_connection->Name( true );
875  m_net_name_to_subgraphs_map[full_name].emplace_back( subgraph );
876 
877  // For vector buses, we need to cache the prefix also, as two different instances of the
878  // weakly driven pin may have the same prefix but different vector start and end. We need
879  // to treat those as needing renaming also, because otherwise if they end up on a sheet with
880  // common usage, they will be incorrectly merged.
881  if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
882  {
883  wxString prefixOnly = full_name.BeforeFirst( '[' ) + wxT( "[]" );
884  m_net_name_to_subgraphs_map[prefixOnly].emplace_back( subgraph );
885  }
886 
887  subgraph->m_dirty = true;
888 
889  if( subgraph->m_strong_driver )
890  {
891  SCH_ITEM* driver = subgraph->m_driver;
892  SCH_SHEET_PATH sheet = subgraph->m_sheet;
893 
894  switch( driver->Type() )
895  {
896  case SCH_LABEL_T:
897  case SCH_HIER_LABEL_T:
898  {
899  m_local_label_cache[std::make_pair( sheet, name )].push_back( subgraph );
900  break;
901  }
902  case SCH_GLOBAL_LABEL_T:
903  {
904  m_global_label_cache[name].push_back( subgraph );
905  break;
906  }
907  case SCH_PIN_T:
908  {
909  auto pin = static_cast<SCH_PIN*>( driver );
910  wxASSERT( pin->IsPowerConnection() );
911  m_global_label_cache[name].push_back( subgraph );
912  break;
913  }
914  default:
915  wxLogTrace( ConnTrace, "Unexpected strong driver %s",
917  break;
918  }
919  }
920  }
921 
922  // Generate subgraphs for invisible power pins. These will be merged with other subgraphs
923  // on the same sheet in the next loop.
924 
925  std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
926 
927  for( const auto& it : m_invisible_power_pins )
928  {
929  SCH_SHEET_PATH sheet = it.first;
930  SCH_PIN* pin = it.second;
931 
932  if( !pin->ConnectedItems( sheet ).empty() && !pin->GetLibPin()->GetParent()->IsPower() )
933  {
934  // ERC will warn about this: user has wired up an invisible pin
935  continue;
936  }
937 
938  SCH_CONNECTION* connection = pin->Connection( &sheet );
939 
940  if( !connection )
941  connection = pin->InitializeConnection( sheet, this );
942 
943  // If this pin already has a subgraph, don't need to process
944  if( connection->SubgraphCode() > 0 )
945  continue;
946 
947  connection->SetName( pin->GetName() );
948 
949  int code = assignNewNetCode( *connection );
950 
951  connection->SetNetCode( code );
952 
953  CONNECTION_SUBGRAPH* subgraph;
954  auto jj = invisible_pin_subgraphs.find( code );
955 
956  if( jj != invisible_pin_subgraphs.end() )
957  {
958  subgraph = jj->second;
959  subgraph->AddItem( pin );
960  }
961  else
962  {
963  subgraph = new CONNECTION_SUBGRAPH( this );
964 
965  subgraph->m_code = m_last_subgraph_code++;
966  subgraph->m_sheet = sheet;
967 
968  subgraph->AddItem( pin );
969  subgraph->ResolveDrivers();
970 
971  auto key = std::make_pair( subgraph->GetNetName(), code );
972  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
973  m_subgraphs.push_back( subgraph );
974  m_driver_subgraphs.push_back( subgraph );
975 
976  invisible_pin_subgraphs[code] = subgraph;
977  }
978 
979  connection->SetSubgraphCode( subgraph->m_code );
980  }
981 
982  // Here we do all the local (sheet) processing of each subgraph, including assigning net
983  // codes, merging subgraphs together that use label connections, etc.
984 
985  // Cache remaining valid subgraphs by sheet path
986  for( auto subgraph : m_driver_subgraphs )
987  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
988 
989  std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
990 
991  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
992  {
993  if( subgraph->m_absorbed )
994  continue;
995 
996  SCH_CONNECTION* connection = subgraph->m_driver_connection;
997  SCH_SHEET_PATH sheet = subgraph->m_sheet;
998  wxString name = connection->Name();
999 
1000  // Test subgraphs with weak drivers for net name conflicts and fix them
1001  unsigned suffix = 1;
1002 
1003  auto create_new_name =
1004  [&suffix]( SCH_CONNECTION* aConn ) -> wxString
1005  {
1006  wxString newName;
1007 
1008  // For group buses with a prefix, we can add the suffix to the prefix.
1009  // If they don't have a prefix, we force the creation of a prefix so that
1010  // two buses don't get inadvertently shorted together.
1011  if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1012  {
1013  wxString prefix = aConn->BusPrefix();
1014 
1015  if( prefix.empty() )
1016  prefix = wxT( "BUS" ); // So result will be "BUS_1{...}"
1017 
1018  wxString oldName = aConn->Name().AfterFirst( '{' );
1019 
1020  newName = wxString::Format( "%s_%u{%s", prefix, suffix, oldName );
1021 
1022  aConn->ConfigureFromLabel( newName );
1023  }
1024  else
1025  {
1026  newName = wxString::Format( "%s_%u", aConn->Name(), suffix );
1027  aConn->SetSuffix( wxString::Format( "_%u", suffix ) );
1028  }
1029 
1030  suffix++;
1031  return newName;
1032  };
1033 
1034  if( !subgraph->m_strong_driver )
1035  {
1036  std::vector<CONNECTION_SUBGRAPH*>* vec = &m_net_name_to_subgraphs_map.at( name );
1037 
1038  // If we are a unique bus vector, check if we aren't actually unique because of another
1039  // subgraph with a similar bus vector
1040  if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1041  {
1042  wxString prefixOnly = name.BeforeFirst( '[' ) + wxT( "[]" );
1043  vec = &m_net_name_to_subgraphs_map.at( prefixOnly );
1044  }
1045 
1046  if( vec->size() > 1 )
1047  {
1048  wxString new_name = create_new_name( connection );
1049 
1050  while( m_net_name_to_subgraphs_map.count( new_name ) )
1051  new_name = create_new_name( connection );
1052 
1053  wxLogTrace( ConnTrace, "%ld (%s) is weakly driven and not unique. Changing to %s.",
1054  subgraph->m_code, name, new_name );
1055 
1056  vec->erase( std::remove( vec->begin(), vec->end(), subgraph ), vec->end() );
1057 
1058  m_net_name_to_subgraphs_map[new_name].emplace_back( subgraph );
1059 
1060  name = new_name;
1061  }
1062  else
1063  {
1064  // If there is no conflict, promote sheet pins to be strong drivers so that they
1065  // will be considered below for propagation/merging.
1066 
1067  // It is possible for this to generate a conflict if the sheet pin has the same
1068  // name as a global label on the same sheet, because global merging will then treat
1069  // this subgraph as if it had a matching local label. So, for those cases, we
1070  // don't apply this promotion
1071 
1072  if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1073  {
1074  bool conflict = false;
1075  wxString global_name = connection->Name( true );
1076  auto kk = m_net_name_to_subgraphs_map.find( global_name );
1077 
1078  if( kk != m_net_name_to_subgraphs_map.end() )
1079  {
1080  // A global will conflict if it is on the same sheet as this subgraph, since
1081  // it would be connected by implicit local label linking
1082  std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1083 
1084  for( const CONNECTION_SUBGRAPH* candidate : candidates )
1085  {
1086  if( candidate->m_sheet == sheet )
1087  conflict = true;
1088  }
1089  }
1090 
1091  if( conflict )
1092  {
1093  wxLogTrace( ConnTrace,
1094  "%ld (%s) skipped for promotion due to potential conflict",
1095  subgraph->m_code, name );
1096  }
1097  else
1098  {
1099  wxLogTrace( ConnTrace,
1100  "%ld (%s) weakly driven by unique sheet pin %s, promoting",
1101  subgraph->m_code, name,
1103 
1104  subgraph->m_strong_driver = true;
1105  }
1106  }
1107  }
1108  }
1109 
1110  // Assign net codes
1111 
1112  if( connection->IsBus() )
1113  {
1114  int code = -1;
1115  auto it = m_bus_name_to_code_map.find( name );
1116 
1117  if( it != m_bus_name_to_code_map.end() )
1118  {
1119  code = it->second;
1120  }
1121  else
1122  {
1123  code = m_last_bus_code++;
1124  m_bus_name_to_code_map[ name ] = code;
1125  }
1126 
1127  connection->SetBusCode( code );
1128  assignNetCodesToBus( connection );
1129  }
1130  else
1131  {
1132  assignNewNetCode( *connection );
1133  }
1134 
1135  // Reset the flag for the next loop below
1136  subgraph->m_dirty = true;
1137 
1138  // Next, we merge together subgraphs that have label connections, and create
1139  // neighbor links for subgraphs that are part of a bus on the same sheet.
1140  // For merging, we consider each possible strong driver.
1141 
1142  // If this subgraph doesn't have a strong driver, let's skip it, since there is no
1143  // way it will be merged with anything.
1144 
1145  if( !subgraph->m_strong_driver )
1146  continue;
1147 
1148  // candidate_subgraphs will contain each valid, non-bus subgraph on the same sheet
1149  // as the subgraph we are considering that has a strong driver.
1150  // Weakly driven subgraphs are not considered since they will never be absorbed or
1151  // form neighbor links.
1152 
1153  std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1154  std::copy_if( m_sheet_to_subgraphs_map[ subgraph->m_sheet ].begin(),
1155  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].end(),
1156  std::back_inserter( candidate_subgraphs ),
1157  [&] ( const CONNECTION_SUBGRAPH* candidate )
1158  {
1159  return ( !candidate->m_absorbed &&
1160  candidate->m_strong_driver &&
1161  candidate != subgraph );
1162  } );
1163 
1164  // This is a list of connections on the current subgraph to compare to the
1165  // drivers of each candidate subgraph. If the current subgraph is a bus,
1166  // we should consider each bus member.
1167  std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1168 
1169  // Also check the main driving connection
1170  connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1171 
1172  auto add_connections_to_check = [&] ( CONNECTION_SUBGRAPH* aSubgraph ) {
1173  for( SCH_ITEM* possible_driver : aSubgraph->m_items )
1174  {
1175  if( possible_driver == aSubgraph->m_driver )
1176  continue;
1177 
1178  auto c = getDefaultConnection( possible_driver, aSubgraph );
1179 
1180  if( c )
1181  {
1182  if( c->Type() != aSubgraph->m_driver_connection->Type() )
1183  continue;
1184 
1185  if( c->Name( true ) == aSubgraph->m_driver_connection->Name( true ) )
1186  continue;
1187 
1188  connections_to_check.push_back( c );
1189  wxLogTrace( ConnTrace,
1190  "%lu (%s): Adding secondary driver %s", aSubgraph->m_code,
1191  aSubgraph->m_driver_connection->Name( true ), c->Name( true ) );
1192  }
1193  }
1194  };
1195 
1196  // Now add other strong drivers
1197  // The actual connection attached to these items will have been overwritten
1198  // by the chosen driver of the subgraph, so we need to create a dummy connection
1199  add_connections_to_check( subgraph );
1200 
1201  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1202  {
1203  auto member = connections_to_check[i];
1204 
1205  if( member->IsBus() )
1206  {
1207  connections_to_check.insert( connections_to_check.end(),
1208  member->Members().begin(),
1209  member->Members().end() );
1210  }
1211 
1212  wxString test_name = member->Name( true );
1213 
1214  for( auto candidate : candidate_subgraphs )
1215  {
1216  if( candidate->m_absorbed )
1217  continue;
1218 
1219  bool match = false;
1220 
1221  if( candidate->m_driver_connection->Name( true ) == test_name )
1222  {
1223  match = true;
1224  }
1225  else
1226  {
1227  if( !candidate->m_multiple_drivers )
1228  continue;
1229 
1230  for( SCH_ITEM *driver : candidate->m_drivers )
1231  {
1232  if( driver == candidate->m_driver )
1233  continue;
1234 
1235  // Sheet pins are not candidates for merging
1236  if( driver->Type() == SCH_SHEET_PIN_T )
1237  continue;
1238 
1239  if( driver->Type() == SCH_PIN_T )
1240  {
1241  auto pin = static_cast<SCH_PIN*>( driver );
1242 
1243  if( pin->IsPowerConnection() && pin->GetName() == test_name )
1244  {
1245  match = true;
1246  break;
1247  }
1248  }
1249  else
1250  {
1251  wxASSERT( driver->Type() == SCH_LABEL_T ||
1252  driver->Type() == SCH_GLOBAL_LABEL_T ||
1253  driver->Type() == SCH_HIER_LABEL_T );
1254 
1255  if( subgraph->GetNameForDriver( driver ) == test_name )
1256  {
1257  match = true;
1258  break;
1259  }
1260  }
1261  }
1262  }
1263 
1264  if( match )
1265  {
1266  if( connection->IsBus() && candidate->m_driver_connection->IsNet() )
1267  {
1268  wxLogTrace( ConnTrace, "%lu (%s) has bus child %lu (%s)", subgraph->m_code,
1269  connection->Name(), candidate->m_code, member->Name() );
1270 
1271  subgraph->m_bus_neighbors[member].insert( candidate );
1272  candidate->m_bus_parents[member].insert( subgraph );
1273  }
1274  else
1275  {
1276  wxLogTrace( ConnTrace, "%lu (%s) absorbs neighbor %lu (%s)",
1277  subgraph->m_code, connection->Name(),
1278  candidate->m_code, candidate->m_driver_connection->Name() );
1279 
1280  // Candidate may have other non-chosen drivers we need to follow
1281  add_connections_to_check( candidate );
1282 
1283  subgraph->Absorb( candidate );
1284  invalidated_subgraphs.insert( subgraph );
1285  }
1286  }
1287  }
1288  }
1289  }
1290 
1291  // Update any subgraph that was invalidated above
1292  for( CONNECTION_SUBGRAPH* subgraph : invalidated_subgraphs )
1293  {
1294  if( subgraph->m_absorbed )
1295  continue;
1296 
1297  subgraph->ResolveDrivers();
1298 
1299  if( subgraph->m_driver_connection->IsBus() )
1301  else
1302  assignNewNetCode( *subgraph->m_driver_connection );
1303 
1304  wxLogTrace( ConnTrace, "Re-resolving drivers for %lu (%s)", subgraph->m_code,
1305  subgraph->m_driver_connection->Name() );
1306  }
1307 
1308  // Absorbed subgraphs should no longer be considered
1309  m_driver_subgraphs.erase( std::remove_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1310  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1311  {
1312  return candidate->m_absorbed;
1313  } ),
1314  m_driver_subgraphs.end() );
1315 
1316  // Store global subgraphs for later reference
1317  std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1318  std::copy_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1319  std::back_inserter( global_subgraphs ),
1320  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1321  {
1322  return !candidate->m_local_driver;
1323  } );
1324 
1325  // Recache remaining valid subgraphs by sheet path
1326  m_sheet_to_subgraphs_map.clear();
1327 
1328  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1329  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1330 
1331  // Update item connections at this point so that neighbor propagation works
1332  nextSubgraph.store( 0 );
1333 
1334  auto preliminaryUpdateTask =
1335  [&]() -> size_t
1336  {
1337  for( size_t subgraphId = nextSubgraph++;
1338  subgraphId < m_driver_subgraphs.size();
1339  subgraphId = nextSubgraph++ )
1340  {
1341  m_driver_subgraphs[subgraphId]->UpdateItemConnections();
1342  }
1343 
1344  return 1;
1345  };
1346 
1347  if( parallelThreadCount == 1 )
1348  preliminaryUpdateTask();
1349  else
1350  {
1351  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1352  returns[ii] = std::async( std::launch::async, preliminaryUpdateTask );
1353 
1354  // Finalize the threads
1355  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1356  returns[ii].wait();
1357  }
1358 
1359  // Next time through the subgraphs, we do some post-processing to handle things like
1360  // connecting bus members to their neighboring subgraphs, and then propagate connections
1361  // through the hierarchy
1362 
1363  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1364  {
1365  if( !subgraph->m_dirty )
1366  continue;
1367 
1368  // For subgraphs that are driven by a global (power port or label) and have more
1369  // than one global driver, we need to seek out other subgraphs driven by the
1370  // same name as the non-chosen driver and update them to match the chosen one.
1371 
1372  if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1373  {
1374  for( SCH_ITEM* driver : subgraph->m_drivers )
1375  {
1376  if( driver == subgraph->m_driver )
1377  continue;
1378 
1379  wxString secondary_name = subgraph->GetNameForDriver( driver );
1380 
1381  if( secondary_name == subgraph->m_driver_connection->Name() )
1382  continue;
1383 
1384  bool secondary_is_global = CONNECTION_SUBGRAPH::GetDriverPriority( driver )
1386 
1387  for( CONNECTION_SUBGRAPH* candidate : global_subgraphs )
1388  {
1389  if( candidate == subgraph )
1390  continue;
1391 
1392  if( !secondary_is_global && candidate->m_sheet != subgraph->m_sheet )
1393  continue;
1394 
1395  SCH_CONNECTION* conn = candidate->m_driver_connection;
1396 
1397  if( conn->Name() == secondary_name )
1398  {
1399  wxLogTrace( ConnTrace, "Global %lu (%s) promoted to %s", candidate->m_code,
1400  conn->Name(), subgraph->m_driver_connection->Name() );
1401 
1402  conn->Clone( *subgraph->m_driver_connection );
1403 
1404  candidate->m_dirty = false;
1405  }
1406  }
1407  }
1408  }
1409 
1410  // This call will handle descending the hierarchy and updating child subgraphs
1411  propagateToNeighbors( subgraph );
1412  }
1413 
1414  // Handle buses that have been linked together somewhere by member (net) connections.
1415  // This feels a bit hacky, perhaps this algorithm should be revisited in the future.
1416 
1417  // For net subgraphs that have more than one bus parent, we need to ensure that those
1418  // buses are linked together in the final netlist. The final name of each bus might not
1419  // match the local name that was used to establish the parent-child relationship, because
1420  // the bus may have been renamed by a hierarchical connection. So, for each of these cases,
1421  // we need to identify the appropriate bus members to link together (and their final names),
1422  // and then update all instances of the old name in the hierarchy.
1423 
1424  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1425  {
1426  if( subgraph->m_bus_parents.size() < 2 )
1427  continue;
1428 
1429  SCH_CONNECTION* conn = subgraph->m_driver_connection;
1430 
1431  wxLogTrace( ConnTrace, "%lu (%s) has multiple bus parents",
1432  subgraph->m_code, conn->Name() );
1433 
1434  wxASSERT( conn->IsNet() );
1435 
1436  for( const auto& ii : subgraph->m_bus_parents )
1437  {
1438  SCH_CONNECTION* link_member = ii.first.get();
1439 
1440  for( CONNECTION_SUBGRAPH* parent : ii.second )
1441  {
1442  while( parent->m_absorbed )
1443  parent = parent->m_absorbed_by;
1444 
1445  SCH_CONNECTION* match = matchBusMember( parent->m_driver_connection, link_member );
1446 
1447  if( !match )
1448  {
1449  wxLogTrace( ConnTrace, "Warning: could not match %s inside %lu (%s)",
1450  conn->Name(), parent->m_code, parent->m_driver_connection->Name() );
1451  continue;
1452  }
1453 
1454  if( conn->Name() != match->Name() )
1455  {
1456  wxString old_name = match->Name();
1457 
1458  wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", parent->m_code,
1459  parent->m_driver_connection->Name(), old_name, conn->Name() );
1460 
1461  match->Clone( *conn );
1462 
1463  auto jj = m_net_name_to_subgraphs_map.find( old_name );
1464 
1465  if( jj == m_net_name_to_subgraphs_map.end() )
1466  continue;
1467 
1468  for( CONNECTION_SUBGRAPH* old_sg : jj->second )
1469  {
1470  while( old_sg->m_absorbed )
1471  old_sg = old_sg->m_absorbed_by;
1472 
1473  old_sg->m_driver_connection->Clone( *conn );
1474  }
1475  }
1476  }
1477  }
1478  }
1479 
1480  nextSubgraph.store( 0 );
1481 
1482  auto updateItemConnectionsTask =
1483  [&]() -> size_t
1484  {
1485  for( size_t subgraphId = nextSubgraph++;
1486  subgraphId < m_driver_subgraphs.size();
1487  subgraphId = nextSubgraph++ )
1488  {
1489  CONNECTION_SUBGRAPH* subgraph = m_driver_subgraphs[subgraphId];
1490 
1491  // Make sure weakly-driven single-pin nets get the unconnected_ prefix
1492  if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
1493  subgraph->m_driver->Type() == SCH_PIN_T )
1494  {
1495  SCH_PIN* pin = static_cast<SCH_PIN*>( subgraph->m_driver );
1496  wxString name = pin->GetDefaultNetName( subgraph->m_sheet, true );
1497 
1499  }
1500 
1501  subgraph->m_dirty = false;
1502  subgraph->UpdateItemConnections();
1503 
1504  // No other processing to do on buses
1505  if( subgraph->m_driver_connection->IsBus() )
1506  continue;
1507 
1508  // As a visual aid, we can check sheet pins that are driven by themselves to see
1509  // if they should be promoted to buses
1510 
1511  if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1512  {
1513  SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( subgraph->m_driver );
1514 
1515  if( SCH_SHEET* sheet = pin->GetParent() )
1516  {
1517  wxString pinText = pin->GetText();
1518  SCH_SCREEN* screen = sheet->GetScreen();
1519 
1520  for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
1521  {
1522  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
1523 
1524  if( label->GetText() == pinText )
1525  {
1526  SCH_SHEET_PATH path = subgraph->m_sheet;
1527  path.push_back( sheet );
1528 
1529  SCH_CONNECTION* parent_conn = label->Connection( &path );
1530 
1531  if( parent_conn && parent_conn->IsBus() )
1533 
1534  break;
1535  }
1536  }
1537 
1538  if( subgraph->m_driver_connection->IsBus() )
1539  continue;
1540  }
1541  }
1542  }
1543 
1544  return 1;
1545  };
1546 
1547  if( parallelThreadCount == 1 )
1548  updateItemConnectionsTask();
1549  else
1550  {
1551  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1552  returns[ii] = std::async( std::launch::async, updateItemConnectionsTask );
1553 
1554  // Finalize the threads
1555  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1556  returns[ii].wait();
1557  }
1558 
1561 
1562  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1563  {
1564  auto key = std::make_pair( subgraph->GetNetName(),
1565  subgraph->m_driver_connection->NetCode() );
1566  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1567 
1568  m_net_name_to_subgraphs_map[subgraph->m_driver_connection->Name()].push_back( subgraph );
1569  }
1570 }
SCH_SHEET_PATH m_sheet
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:216
void SetBusCode(int aCode)
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_neighbors
If a subgraph is a bus, this map contains links between the bus members and any local sheet neighbors...
SCH_ITEM * m_bus_entry
Bus entry in graph, if any.
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combines another subgraph on the same sheet into this one.
This item represents a bus group.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_parents
If this is a net, this vector contains links to any same-sheet buses that contain it.
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
void SetName(const wxString &aName)
NET_MAP m_net_code_to_subgraphs_map
std::vector< SCH_ITEM * > m_items
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:131
int NetCode() const
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
void SetSubgraphCode(int aCode)
std::vector< SCH_ITEM * > m_items
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
int SubgraphCode() const
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensures all members of the bus connection have a valid net code assigned.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:87
bool IsNet() const
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
const char * name
Definition: DXF_plotter.cpp:59
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Builds a new default connection for the given item based on its properties.
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:107
EE_RTREE & Items()
Definition: sch_screen.h:103
std::map< wxString, int > m_bus_name_to_code_map
void SetType(CONNECTION_TYPE aType)
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
not connected (must be left open)
bool IsBus() const
CONNECTION_TYPE Type() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
void SetNetCode(int aCode)
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
PRIORITY GetDriverPriority()
This item represents a bus vector.
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163
void UpdateItemConnections()
Updates all items to match the driver connection.

References CONNECTION_SUBGRAPH::AddItem(), assignNetCodesToBus(), assignNewNetCode(), BUS, BUS_GROUP, SCH_CONNECTION::Clone(), SCH_CONNECTION::ConfigureFromLabel(), SCH_ITEM::Connection(), ConnTrace, Format(), getDefaultConnection(), CONNECTION_SUBGRAPH::GetDriverPriority(), CONNECTION_SUBGRAPH::GetNetName(), EDA_ITEM::GetSelectMenuText(), SCHEMATIC::GetSheets(), EDA_TEXT::GetText(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::IsNet(), SCH_SCREEN::Items(), CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, m_bus_alias_cache, m_bus_name_to_code_map, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, m_driver_subgraphs, CONNECTION_SUBGRAPH::m_drivers, m_global_label_cache, m_invisible_power_pins, m_item_to_subgraph_map, m_items, m_last_bus_code, m_last_subgraph_code, m_local_label_cache, m_net_code_to_subgraphs_map, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, CONNECTION_SUBGRAPH::m_strong_driver, m_subgraphs, matchBusMember(), MILLIMETRES, name, SCH_CONNECTION::Name(), EE_RTREE::OfType(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, propagateToNeighbors(), PT_NC, CONNECTION_SUBGRAPH::ResolveDrivers(), SCH_BUS_WIRE_ENTRY_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_NO_CONNECT_T, SCH_PIN_T, SCH_SHEET_PIN_T, SCH_CONNECTION::SetBusCode(), SCH_CONNECTION::SetName(), SCH_CONNECTION::SetNetCode(), SCH_CONNECTION::SetSubgraphCode(), SCH_CONNECTION::SetType(), SCH_CONNECTION::SubgraphCode(), EDA_ITEM::Type(), and CONNECTION_SUBGRAPH::UpdateItemConnections().

Referenced by Recalculate().

◆ ercCheckBusToBusConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting connections between two bus items.

For example, a labeled bus wire connected to a hierarchical sheet pin where the labeled bus doesn't contain any of the same bus members as the sheet pin

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2309 of file connection_graph.cpp.

2310 {
2311  wxString msg;
2312  auto sheet = aSubgraph->m_sheet;
2313  auto screen = sheet.LastScreen();
2314 
2315  SCH_ITEM* label = nullptr;
2316  SCH_ITEM* port = nullptr;
2317 
2318  for( auto item : aSubgraph->m_items )
2319  {
2320  switch( item->Type() )
2321  {
2322  case SCH_TEXT_T:
2323  case SCH_GLOBAL_LABEL_T:
2324  {
2325  if( !label && item->Connection( &sheet )->IsBus() )
2326  label = item;
2327  break;
2328  }
2329 
2330  case SCH_SHEET_PIN_T:
2331  case SCH_HIER_LABEL_T:
2332  {
2333  if( !port && item->Connection( &sheet )->IsBus() )
2334  port = item;
2335  break;
2336  }
2337 
2338  default:
2339  break;
2340  }
2341  }
2342 
2343  if( label && port )
2344  {
2345  bool match = false;
2346 
2347  for( const auto& member : label->Connection( &sheet )->Members() )
2348  {
2349  for( const auto& test : port->Connection( &sheet )->Members() )
2350  {
2351  if( test != member && member->Name() == test->Name() )
2352  {
2353  match = true;
2354  break;
2355  }
2356  }
2357 
2358  if( match )
2359  break;
2360  }
2361 
2362  if( !match )
2363  {
2364  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
2365  ercItem->SetItems( label, port );
2366 
2367  SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
2368  screen->Append( marker );
2369 
2370  return false;
2371  }
2372  }
2373 
2374  return true;
2375 }
SCH_SHEET_PATH m_sheet
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:59
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
virtual wxPoint GetPosition() const
Definition: eda_item.h:302
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:131
std::vector< SCH_ITEM * > m_items
SCH_SCREEN * LastScreen()
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197

References SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_TO_BUS_CONFLICT, EDA_ITEM::GetPosition(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_SHEET_PIN_T, and SCH_TEXT_T.

Referenced by RunERC().

◆ ercCheckBusToBusEntryConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting bus entry to bus connections.

For example, a wire with label "A0" is connected to a bus labeled "D[8..0]"

Will also check for mistakes related to bus group names, for example: A bus group named "USB{DP DM}" should have bus entry connections like "USB.DP" but someone might accidentally just enter "DP"

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2378 of file connection_graph.cpp.

2379 {
2380  bool conflict = false;
2381  auto sheet = aSubgraph->m_sheet;
2382  auto screen = sheet.LastScreen();
2383 
2384  SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2385  SCH_ITEM* bus_wire = nullptr;
2386  wxString bus_name;
2387 
2388  if( !aSubgraph->m_driver_connection )
2389  {
2390  // Incomplete bus entry. Let the unconnected tests handle it.
2391  return true;
2392  }
2393 
2394  for( auto item : aSubgraph->m_items )
2395  {
2396  switch( item->Type() )
2397  {
2398  case SCH_BUS_WIRE_ENTRY_T:
2399  {
2400  if( !bus_entry )
2401  bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2402  break;
2403  }
2404 
2405  default:
2406  break;
2407  }
2408  }
2409 
2410  if( bus_entry && bus_entry->m_connected_bus_item )
2411  {
2412  bus_wire = bus_entry->m_connected_bus_item;
2413 
2414  wxASSERT( bus_wire->Type() == SCH_LINE_T );
2415 
2416  // In some cases, the connection list (SCH_CONNECTION*) can be null.
2417  // Skip null connections.
2418  if( bus_entry->Connection( &sheet )
2419  && bus_wire->Type() == SCH_LINE_T
2420  && bus_wire->Connection( &sheet ) )
2421  {
2422  conflict = true; // Assume a conflict; we'll reset if we find it's OK
2423 
2424  bus_name = bus_wire->Connection( &sheet )->Name();
2425 
2426  wxString test_name = bus_entry->Connection( &sheet )->Name();
2427 
2428  for( const auto& member : bus_wire->Connection( &sheet )->Members() )
2429  {
2430  if( member->Type() == CONNECTION_TYPE::BUS )
2431  {
2432  for( const auto& sub_member : member->Members() )
2433  {
2434  if( sub_member->Name() == test_name )
2435  conflict = false;
2436  }
2437  }
2438  else if( member->Name() == test_name )
2439  {
2440  conflict = false;
2441  }
2442  }
2443  }
2444  }
2445 
2446  // Don't report warnings if this bus member has been overridden by a higher priority power pin
2447  // or global label
2448  if( conflict && CONNECTION_SUBGRAPH::GetDriverPriority( aSubgraph->m_driver )
2450  conflict = false;
2451 
2452  if( conflict )
2453  {
2454  wxString netName = aSubgraph->m_driver_connection->Name();
2455  wxString msg = wxString::Format( _( "Net %s is graphically connected to bus %s but is not a"
2456  " member of that bus" ),
2457  UnescapeString( netName ),
2458  UnescapeString( bus_name ) );
2459  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
2460  ercItem->SetItems( bus_entry, bus_wire );
2461  ercItem->SetErrorMessage( msg );
2462 
2463  SCH_MARKER* marker = new SCH_MARKER( ercItem, bus_entry->GetPosition() );
2464  screen->Append( marker );
2465 
2466  return false;
2467  }
2468 
2469  return true;
2470 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:131
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:57
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SCH_SCREEN * LastScreen()
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:151
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
PRIORITY GetDriverPriority()
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163
wxPoint GetPosition() const override

References _, BUS, SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_ENTRY_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetDriverPriority(), SCH_BUS_ENTRY_BASE::GetPosition(), SCH_SHEET_PATH::LastScreen(), SCH_BUS_WIRE_ENTRY::m_connected_bus_item, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_CONNECTION::Name(), CONNECTION_SUBGRAPH::POWER_PIN, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, EDA_ITEM::Type(), and UnescapeString().

Referenced by RunERC().

◆ ercCheckBusToNetConflicts()

bool CONNECTION_GRAPH::ercCheckBusToNetConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting connections between net and bus labels.

For example, a net wire connected to a bus port/pin, or vice versa

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2252 of file connection_graph.cpp.

2253 {
2254  auto sheet = aSubgraph->m_sheet;
2255  auto screen = sheet.LastScreen();
2256 
2257  SCH_ITEM* net_item = nullptr;
2258  SCH_ITEM* bus_item = nullptr;
2259  SCH_CONNECTION conn( this );
2260 
2261  for( SCH_ITEM* item : aSubgraph->m_items )
2262  {
2263  switch( item->Type() )
2264  {
2265  case SCH_LINE_T:
2266  {
2267  if( item->GetLayer() == LAYER_BUS )
2268  bus_item = ( !bus_item ) ? item : bus_item;
2269  else
2270  net_item = ( !net_item ) ? item : net_item;
2271  break;
2272  }
2273 
2274  case SCH_LABEL_T:
2275  case SCH_GLOBAL_LABEL_T:
2276  case SCH_SHEET_PIN_T:
2277  case SCH_HIER_LABEL_T:
2278  {
2279  SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2280  conn.ConfigureFromLabel( EscapeString( text->GetShownText(), CTX_NETNAME ) );
2281 
2282  if( conn.IsBus() )
2283  bus_item = ( !bus_item ) ? item : bus_item;
2284  else
2285  net_item = ( !net_item ) ? item : net_item;
2286  break;
2287  }
2288 
2289  default:
2290  break;
2291  }
2292  }
2293 
2294  if( net_item && bus_item )
2295  {
2296  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
2297  ercItem->SetItems( net_item, bus_item );
2298 
2299  SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
2300  screen->Append( marker );
2301 
2302  return false;
2303  }
2304 
2305  return true;
2306 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:61
virtual wxPoint GetPosition() const
Definition: eda_item.h:302
std::vector< SCH_ITEM * > m_items
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:272
SCH_SCREEN * LastScreen()
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
Definition: string.cpp:78
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163

References SCH_CONNECTION::ConfigureFromLabel(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_BUS_TO_NET_CONFLICT, EscapeString(), SCH_ITEM::GetLayer(), EDA_ITEM::GetPosition(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_LINE_T, SCH_SHEET_PIN_T, text, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckFloatingWires()

bool CONNECTION_GRAPH::ercCheckFloatingWires ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for floating wires.

Will throw an error for any subgraph that consists of just wires with no driver

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2647 of file connection_graph.cpp.

2648 {
2649  if( aSubgraph->m_driver )
2650  return true;
2651 
2652  std::vector<SCH_ITEM*> wires;
2653 
2654  // We've gotten this far, so we know we have no valid driver. All we need to do is check
2655  // for a wire that we can place the error on.
2656 
2657  for( SCH_ITEM* item : aSubgraph->m_items )
2658  {
2659  if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
2660  wires.emplace_back( item );
2661  else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
2662  wires.emplace_back( item );
2663  }
2664 
2665  if( !wires.empty() )
2666  {
2667  SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2668 
2669  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
2670  ercItem->SetItems( wires[0],
2671  wires.size() > 1 ? wires[1] : nullptr,
2672  wires.size() > 2 ? wires[2] : nullptr,
2673  wires.size() > 3 ? wires[3] : nullptr );
2674 
2675  SCH_MARKER* marker = new SCH_MARKER( ercItem, wires[0]->GetPosition() );
2676  screen->Append( marker );
2677 
2678  return false;
2679  }
2680 
2681  return true;
2682 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
Some wires are not connected to anything else.
Definition: erc_settings.h:65
std::vector< SCH_ITEM * > m_items
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:272
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:128
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_WIRE_DANGLING, SCH_ITEM::GetLayer(), SCH_SHEET_PATH::LastScreen(), LAYER_WIRE, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckHierSheets()

int CONNECTION_GRAPH::ercCheckHierSheets ( )
private

Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on the parent sheet object.

Parameters
aSubgraphis the subgraph to examine
Returns
the number of errors found

Definition at line 2809 of file connection_graph.cpp.

2810 {
2811  int errors = 0;
2812 
2813  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2814 
2815  for( const SCH_SHEET_PATH& sheet : m_sheetList )
2816  {
2817  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
2818  {
2819  if( item->Type() != SCH_SHEET_T )
2820  continue;
2821 
2822  SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
2823 
2824  std::map<wxString, SCH_SHEET_PIN*> pins;
2825  std::map<wxString, SCH_HIERLABEL*> labels;
2826 
2827  for( SCH_SHEET_PIN* pin : parentSheet->GetPins() )
2828  {
2829  pins[pin->GetText()] = pin;
2830 
2831  if( pin->IsDangling() && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2832  {
2833  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2834  ercItem->SetItems( pin );
2835 
2836  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
2837  sheet.LastScreen()->Append( marker );
2838 
2839  errors++;
2840  }
2841  }
2842 
2843  std::set<wxString> matchedPins;
2844 
2845  for( SCH_ITEM* subItem : parentSheet->GetScreen()->Items() )
2846  {
2847  if( subItem->Type() == SCH_HIER_LABEL_T )
2848  {
2849  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
2850 
2851  if( !pins.count( label->GetText() ) )
2852  labels[label->GetText()] = label;
2853  else
2854  matchedPins.insert( label->GetText() );
2855  }
2856  }
2857 
2858  for( const wxString& matched : matchedPins )
2859  pins.erase( matched );
2860 
2861  for( const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
2862  {
2863  wxString msg = wxString::Format( _( "Sheet pin %s has no matching hierarchical "
2864  "label inside the sheet" ),
2865  UnescapeString( unmatched.first ) );
2866 
2867  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
2868  ercItem->SetItems( unmatched.second );
2869  ercItem->SetErrorMessage( msg );
2870  ercItem->SetIsSheetSpecific();
2871 
2872  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
2873  sheet.LastScreen()->Append( marker );
2874 
2875  errors++;
2876  }
2877 
2878  for( const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
2879  {
2880  wxString msg = wxString::Format( _( "Hierarchical label %s has no matching "
2881  "sheet pin in the parent sheet" ),
2882  UnescapeString( unmatched.first ) );
2883 
2884  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
2885  ercItem->SetItems( unmatched.second );
2886  ercItem->SetErrorMessage( msg );
2887  ercItem->SetIsSheetSpecific();
2888 
2889  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
2890  parentSheet->GetScreen()->Append( marker );
2891 
2892  errors++;
2893  }
2894  }
2895  }
2896 
2897  return errors;
2898 }
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:122
SCHEMATIC * m_schematic
The schematic this graph represents.
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:103
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Container for ERC settings.
Definition: erc_settings.h:105
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:184
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:46
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:128
#define _(s)
Definition: 3d_actions.cpp:33
SCH_SHEET_LIST m_sheetList
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:151
EE_RTREE & Items()
Definition: sch_screen.h:103
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:134
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_HIERACHICAL_LABEL, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), Format(), SCH_SHEET::GetPins(), SCH_SHEET::GetScreen(), EDA_TEXT::GetText(), ERC_SETTINGS::IsTestEnabled(), SCH_SCREEN::Items(), m_schematic, m_sheetList, pin, SCH_HIER_LABEL_T, SCH_SHEET_T, and UnescapeString().

Referenced by RunERC().

◆ ercCheckLabels()

bool CONNECTION_GRAPH::ercCheckLabels ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for proper connection of labels.

Labels should be connected to something

Parameters
aSubgraphis the subgraph to examine
aCheckGlobalLabelsis true if global labels should be checked for loneliness
Returns
true for no errors, false for errors

Definition at line 2685 of file connection_graph.cpp.

2686 {
2687  // Label connection rules:
2688  // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2689  // Global labels are flagged if they appear only once, don't connect to any local labels,
2690  // and don't have a no-connect marker
2691 
2692  // So, if there is a no-connect, we will never generate a warning here
2693  if( aSubgraph->m_no_connect )
2694  return true;
2695 
2696  if( !aSubgraph->m_driver_connection )
2697  return true;
2698 
2699  // Buses are excluded from this test: many users create buses with only a single instance
2700  // and it's not really a problem as long as the nets in the bus pass ERC
2701  if( aSubgraph->m_driver_connection->IsBus() )
2702  return true;
2703 
2704  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2705  bool ok = true;
2706  SCH_TEXT* text = nullptr;
2707  bool hasOtherConnections = false;
2708  int pinCount = 0;
2709 
2710  for( auto item : aSubgraph->m_items )
2711  {
2712  switch( item->Type() )
2713  {
2714  case SCH_LABEL_T:
2715  case SCH_GLOBAL_LABEL_T:
2716  case SCH_HIER_LABEL_T:
2717  {
2718  text = static_cast<SCH_TEXT*>( item );
2719 
2720  // Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
2721  // we want to error if an individual label in the subgraph is floating, even if it's
2722  // connected to other valid things by way of another label on the same sheet.
2723 
2724  if( text->IsDangling() && settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
2725  {
2726  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LABEL_NOT_CONNECTED );
2727  ercItem->SetItems( text );
2728 
2729  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2730  aSubgraph->m_sheet.LastScreen()->Append( marker );
2731  ok = false;
2732  }
2733 
2734  break;
2735  }
2736 
2737  case SCH_PIN_T:
2738  case SCH_SHEET_PIN_T:
2739  hasOtherConnections = true;
2740  pinCount++;
2741  break;
2742 
2743  default:
2744  break;
2745  }
2746  }
2747 
2748  if( !text )
2749  return true;
2750 
2751  bool isGlobal = text->Type() == SCH_GLOBAL_LABEL_T;
2752  int errCode = isGlobal ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
2753 
2754  wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" );
2755 
2756  wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
2757 
2758  if( isGlobal )
2759  {
2760  // This will be set to true if the global is connected to a pin above, but we
2761  // want to reset this to false so that globals get flagged if they only have a
2762  // single instance connected to a single pin
2763  hasOtherConnections = ( pinCount > 1 );
2764 
2765  auto it = m_net_name_to_subgraphs_map.find( name );
2766 
2767  if( it != m_net_name_to_subgraphs_map.end() )
2768  {
2769  if( it->second.size() > 1 || aSubgraph->m_multiple_drivers )
2770  hasOtherConnections = true;
2771  }
2772  }
2773  else if( text->Type() == SCH_HIER_LABEL_T )
2774  {
2775  // For a hier label, check if the parent pin is connected
2776  if( aSubgraph->m_hier_parent &&
2777  ( aSubgraph->m_hier_parent->m_strong_driver ||
2778  aSubgraph->m_hier_parent->m_drivers.size() > 1) )
2779  {
2780  // For now, a simple check: if there is more than one driver, the parent is probably
2781  // connected elsewhere (because at least one driver will be the hier pin itself)
2782  hasOtherConnections = true;
2783  }
2784  }
2785  else
2786  {
2787  auto pair = std::make_pair( aSubgraph->m_sheet, name );
2788  auto it = m_local_label_cache.find( pair );
2789 
2790  if( it != m_local_label_cache.end() && it->second.size() > 1 )
2791  hasOtherConnections = true;
2792  }
2793 
2794  if( !hasOtherConnections && settings.IsTestEnabled( errCode ) )
2795  {
2796  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
2797  ercItem->SetItems( text );
2798 
2799  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2800  aSubgraph->m_sheet.LastScreen()->Append( marker );
2801 
2802  return false;
2803  }
2804 
2805  return ok;
2806 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:122
Label not connected to anything.
Definition: erc_settings.h:49
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
std::vector< SCH_ITEM * > m_items
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Container for ERC settings.
Definition: erc_settings.h:105
A global label is unique.
Definition: erc_settings.h:63
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:59
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:128
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
Definition: string.cpp:78
CONNECTION_SUBGRAPH * m_hier_parent
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:134
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
bool IsBus() const

References SCH_SCREEN::Append(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, SCHEMATIC::ErcSettings(), EscapeString(), SCH_CONNECTION::IsBus(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_multiple_drivers, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, CONNECTION_SUBGRAPH::m_strong_driver, name, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, and text.

Referenced by RunERC().

◆ ercCheckMultipleDrivers()

bool CONNECTION_GRAPH::ercCheckMultipleDrivers ( const CONNECTION_SUBGRAPH aSubgraph)
private

If the subgraph has multiple drivers of equal priority that are graphically connected, ResolveDrivers() will have stored the second driver for use by this function, which actually creates the markers.

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2222 of file connection_graph.cpp.

2223 {
2224  if( !aSubgraph->m_second_driver )
2225  return true;
2226 
2227  SCH_ITEM* primary = aSubgraph->m_first_driver;
2228  SCH_ITEM* secondary = aSubgraph->m_second_driver;
2229 
2230  wxPoint pos = primary->Type() == SCH_PIN_T ?
2231  static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2232  primary->GetPosition();
2233 
2234  wxString primaryName = aSubgraph->GetNameForDriver( primary );
2235  wxString secondaryName = aSubgraph->GetNameForDriver( secondary );
2236 
2237  wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2238  "items; %s will be used in the netlist" ),
2239  primaryName, secondaryName, primaryName );
2240 
2241  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2242  ercItem->SetItems( primary, secondary );
2243  ercItem->SetErrorMessage( msg );
2244 
2245  SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2246  aSubgraph->m_sheet.LastScreen()->Append( marker );
2247 
2248  return false;
2249 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
virtual wxPoint GetPosition() const
Definition: eda_item.h:302
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:128
#define _(s)
Definition: 3d_actions.cpp:33
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:56
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_DRIVER_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetNameForDriver(), EDA_ITEM::GetPosition(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_first_driver, CONNECTION_SUBGRAPH::m_second_driver, CONNECTION_SUBGRAPH::m_sheet, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckNoConnects()

bool CONNECTION_GRAPH::ercCheckNoConnects ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for proper presence or absence of no-connect symbols.

A pin with a no-connect symbol should not have any connections A pin without a no-connect symbol should have at least one connection

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2474 of file connection_graph.cpp.

2475 {
2476  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2477  wxString msg;
2478  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2479  SCH_SCREEN* screen = sheet.LastScreen();
2480  bool ok = true;
2481 
2482  if( aSubgraph->m_no_connect != nullptr )
2483  {
2484  bool has_invalid_items = false;
2485  bool has_other_items = false;
2486  SCH_PIN* pin = nullptr;
2487  std::vector<SCH_ITEM*> invalid_items;
2488  wxPoint noConnectPos = aSubgraph->m_no_connect->GetPosition();
2489  double minDist = 0;
2490 
2491  // Any subgraph that contains both a pin and a no-connect should not
2492  // contain any other driving items.
2493 
2494  for( auto item : aSubgraph->m_items )
2495  {
2496  switch( item->Type() )
2497  {
2498  case SCH_PIN_T:
2499  {
2500  SCH_PIN* candidate = static_cast<SCH_PIN*>( item );
2501  double dist = VECTOR2I( candidate->GetTransformedPosition() - noConnectPos )
2502  .SquaredEuclideanNorm();
2503 
2504  if( !pin || dist < minDist )
2505  {
2506  pin = candidate;
2507  minDist = dist;
2508  }
2509 
2510  has_invalid_items |= has_other_items;
2511  has_other_items = true;
2512  break;
2513  }
2514 
2515  case SCH_LINE_T:
2516  case SCH_JUNCTION_T:
2517  case SCH_NO_CONNECT_T:
2518  break;
2519 
2520  default:
2521  has_invalid_items = true;
2522  has_other_items = true;
2523  invalid_items.push_back( item );
2524  }
2525  }
2526 
2527  if( pin && has_invalid_items && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
2528  {
2529  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
2530  ercItem->SetItems( pin );
2531 
2532  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2533  screen->Append( marker );
2534 
2535  ok = false;
2536  }
2537 
2538  if( !has_other_items && settings.IsTestEnabled(ERCE_NOCONNECT_NOT_CONNECTED ) )
2539  {
2540  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
2541  ercItem->SetItems( aSubgraph->m_no_connect );
2542 
2543  SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
2544  screen->Append( marker );
2545 
2546  ok = false;
2547  }
2548  }
2549  else
2550  {
2551  bool has_other_connections = false;
2552  std::vector<SCH_PIN*> pins;
2553 
2554  // Any subgraph that lacks a no-connect and contains a pin should also
2555  // contain at least one other potential driver
2556 
2557  for( SCH_ITEM* item : aSubgraph->m_items )
2558  {
2559  switch( item->Type() )
2560  {
2561  case SCH_PIN_T:
2562  {
2563  if( !pins.empty() )
2564  has_other_connections = true;
2565 
2566  pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2567 
2568  break;
2569  }
2570 
2571  default:
2572  if( aSubgraph->GetDriverPriority( item ) != CONNECTION_SUBGRAPH::PRIORITY::NONE )
2573  has_other_connections = true;
2574 
2575  break;
2576  }
2577  }
2578 
2579  // For many checks, we can just use the first pin
2580  SCH_PIN* pin = pins.empty() ? nullptr : pins[0];
2581 
2582  // Check if invisible power input pins connect to anything else via net name,
2583  // but not for power symbols as the ones in the standard library all have invisible pins
2584  // and we want to throw unconnected errors for those even if they are connected to other
2585  // net items by name, because usually failing to connect them graphically is a mistake
2586  if( pin && !has_other_connections
2587  && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
2588  && !pin->IsVisible()
2589  && !pin->GetLibPin()->GetParent()->IsPower() )
2590  {
2591  wxString name = pin->Connection( &sheet )->Name();
2592  wxString local_name = pin->Connection( &sheet )->Name( true );
2593 
2594  if( m_global_label_cache.count( name ) ||
2595  ( m_local_label_cache.count( std::make_pair( sheet, local_name ) ) ) )
2596  {
2597  has_other_connections = true;
2598  }
2599  }
2600 
2601  // Only one pin, and it's not a no-connect pin
2602  if( pin && !has_other_connections
2603  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
2604  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
2605  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2606  {
2607  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2608  ercItem->SetItems( pin );
2609 
2610  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2611  screen->Append( marker );
2612 
2613  ok = false;
2614  }
2615 
2616  // If there are multiple pins in this SG, they might be indirectly connected (by netname)
2617  // rather than directly connected (by wires). We want to flag dangling pins even if they
2618  // join nets with another pin, as it's often a mistake
2619  if( pins.size() > 1 )
2620  {
2621  for( SCH_PIN* testPin : pins )
2622  {
2623  // We only apply this test to power symbols, because other symbols have invisible
2624  // pins that are meant to be dangling, but the KiCad standard library power symbols
2625  // have invisible pins that are *not* meant to be dangling.
2626  if( testPin->GetLibPin()->GetParent()->IsPower()
2627  && testPin->ConnectedItems( sheet ).empty()
2628  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2629  {
2630  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2631  ercItem->SetItems( testPin );
2632 
2633  SCH_MARKER* marker = new SCH_MARKER( ercItem,
2634  testPin->GetTransformedPosition() );
2635  screen->Append( marker );
2636 
2637  ok = false;
2638  }
2639  }
2640  }
2641  }
2642 
2643  return ok;
2644 }
power input (GND, VCC for ICs). Must be connected to a power output.
SCH_SHEET_PATH m_sheet
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:189
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:122
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Returns the priority (higher is more important) of a candidate driver.
SCHEMATIC * m_schematic
The schematic this graph represents.
virtual wxPoint GetPosition() const
Definition: eda_item.h:302
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
not internally connected (may be connected to anything)
std::vector< SCH_ITEM * > m_items
Container for ERC settings.
Definition: erc_settings.h:105
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
A no connect symbol is not connected to anything.
Definition: erc_settings.h:48
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
A no connect symbol is connected to more than 1 pin.
Definition: erc_settings.h:47
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:59
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:128
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:134
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
not connected (must be left open)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163
wxPoint GetTransformedPosition() const
Definition: sch_pin.cpp:275

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), CONNECTION_SUBGRAPH::GetDriverPriority(), EDA_ITEM::GetPosition(), SCH_PIN::GetTransformedPosition(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), m_global_label_cache, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, name, CONNECTION_SUBGRAPH::NONE, pin, PT_NC, PT_NIC, PT_POWER_IN, SCH_JUNCTION_T, SCH_LINE_T, SCH_NO_CONNECT_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ FindFirstSubgraphByName()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::FindFirstSubgraphByName ( const wxString &  aNetName)

Retrieves a subgraph for the given net name, if one exists.

Searches every sheet

Parameters
aNetNameis the full net name to search for
Returns
the subgraph matching the query, or nullptr if none is found

Definition at line 2107 of file connection_graph.cpp.

2108 {
2109  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2110 
2111  if( it == m_net_name_to_subgraphs_map.end() )
2112  return nullptr;
2113 
2114  wxASSERT( !it->second.empty() );
2115 
2116  return it->second[0];
2117 }
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map

References m_net_name_to_subgraphs_map.

◆ FindSubgraphByName()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::FindSubgraphByName ( const wxString &  aNetName,
const SCH_SHEET_PATH aPath 
)

Returns the subgraph for a given net name on a given sheet.

Parameters
aNetNameis the local net name to look for
aPathis a sheet path to look on
Returns
the subgraph matching the query, or nullptr if none is found

Definition at line 2086 of file connection_graph.cpp.

2088 {
2089  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2090 
2091  if( it == m_net_name_to_subgraphs_map.end() )
2092  return nullptr;
2093 
2094  for( CONNECTION_SUBGRAPH* sg : it->second )
2095  {
2096  // Cache is supposed to be valid by now
2097  wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
2098 
2099  if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
2100  return sg;
2101  }
2102 
2103  return nullptr;
2104 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
wxString Name(bool aIgnoreSheet=false) const

References CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_driver_connection, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_sheet, and SCH_CONNECTION::Name().

Referenced by NETLIST_EXPORTER_BASE::CreatePinList(), and NETLIST_EXPORTER_BASE::findAllUnitsOfSymbol().

◆ GetBusAlias()

std::shared_ptr< BUS_ALIAS > CONNECTION_GRAPH::GetBusAlias ( const wxString &  aName)

Returns a bus alias pointer for the given name if it exists (from cache)

CONNECTION_GRAPH caches these, they are owned by the SCH_SCREEN that the alias was defined on. The cache is only used to update the graph.

Definition at line 2030 of file connection_graph.cpp.

2031 {
2032  auto it = m_bus_alias_cache.find( aName );
2033 
2034  return it != m_bus_alias_cache.end() ? it->second : nullptr;
2035 }
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache

References m_bus_alias_cache.

Referenced by SCH_CONNECTION::AppendInfoToMsgPanel(), and SCH_CONNECTION::ConfigureFromLabel().

◆ GetBusesNeedingMigration()

std::vector< const CONNECTION_SUBGRAPH * > CONNECTION_GRAPH::GetBusesNeedingMigration ( )

Determines which subgraphs have more than one conflicting bus label.

See also
DIALOG_MIGRATE_BUSES
Returns
a list of subgraphs that need migration

Definition at line 2038 of file connection_graph.cpp.

2039 {
2040  std::vector<const CONNECTION_SUBGRAPH*> ret;
2041 
2042  for( auto&& subgraph : m_subgraphs )
2043  {
2044  // Graph is supposed to be up-to-date before calling this
2045  wxASSERT( !subgraph->m_dirty );
2046 
2047  if( !subgraph->m_driver )
2048  continue;
2049 
2050  auto sheet = subgraph->m_sheet;
2051  auto connection = subgraph->m_driver->Connection( &sheet );
2052 
2053  if( !connection->IsBus() )
2054  continue;
2055 
2056  auto labels = subgraph->GetBusLabels();
2057 
2058  if( labels.size() > 1 )
2059  {
2060  bool different = false;
2061  wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2062 
2063  for( unsigned i = 1; i < labels.size(); ++i )
2064  {
2065  if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2066  {
2067  different = true;
2068  break;
2069  }
2070  }
2071 
2072  if( !different )
2073  continue;
2074 
2075  wxLogTrace( ConnTrace, "SG %ld (%s) has multiple bus labels", subgraph->m_code,
2076  connection->Name() );
2077 
2078  ret.push_back( subgraph );
2079  }
2080  }
2081 
2082  return ret;
2083 }
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
static const wxChar ConnTrace[]

References ConnTrace, and m_subgraphs.

Referenced by DIALOG_MIGRATE_BUSES::loadGraphData().

◆ getDefaultConnection()

std::shared_ptr< SCH_CONNECTION > CONNECTION_GRAPH::getDefaultConnection ( SCH_ITEM aItem,
CONNECTION_SUBGRAPH aSubgraph 
)
private

Builds a new default connection for the given item based on its properties.

Handles strong drivers (power pins and labels) only

Parameters
aItemis an item that can generate a connection name
aSubgraphis used to determine the sheet to use and retrieve the cached name
Returns
a connection generated from the item, or nullptr if item is not valid

Definition at line 1921 of file connection_graph.cpp.

1923 {
1924  auto c = std::shared_ptr<SCH_CONNECTION>( nullptr );
1925 
1926  switch( aItem->Type() )
1927  {
1928  case SCH_PIN_T:
1929  {
1930  auto pin = static_cast<SCH_PIN*>( aItem );
1931 
1932  if( pin->IsPowerConnection() )
1933  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
1934 
1935  break;
1936  }
1937 
1938  case SCH_GLOBAL_LABEL_T:
1939  case SCH_HIER_LABEL_T:
1940  case SCH_LABEL_T:
1941  {
1942  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
1943  break;
1944  }
1945 
1946  default:
1947  break;
1948  }
1949 
1950  if( c )
1951  {
1952  c->SetGraph( this );
1953  c->ConfigureFromLabel( aSubgraph->GetNameForDriver( aItem ) );
1954  }
1955 
1956  return c;
1957 }
SCH_SHEET_PATH m_sheet
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163

References CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::m_sheet, pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ GetNetMap()

◆ GetSubgraphForItem()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::GetSubgraphForItem ( SCH_ITEM aItem)

Definition at line 2120 of file connection_graph.cpp.

2121 {
2122  auto it = m_item_to_subgraph_map.find( aItem );
2123  CONNECTION_SUBGRAPH* ret = it != m_item_to_subgraph_map.end() ? it->second : nullptr;
2124 
2125  while( ret && ret->m_absorbed )
2126  ret = ret->m_absorbed_by;
2127 
2128  return ret;
2129 }
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
A subgraph is a set of items that are electrically connected on a single sheet.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

References CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, and m_item_to_subgraph_map.

Referenced by inheritNetclass(), and SCH_EDITOR_CONTROL::UpdateNetHighlighting().

◆ matchBusMember()

SCH_CONNECTION * CONNECTION_GRAPH::matchBusMember ( SCH_CONNECTION aBusConnection,
SCH_CONNECTION aSearch 
)
staticprivate

Search for a matching bus member inside a bus connection.

For bus groups, this returns a bus member that matches aSearch by name. For bus vectors, this returns a bus member that matches by vector index.

Parameters
aBusConnectionis the bus connection to search
aSearchis the net connection to search for
Returns
a member of aBusConnection that matches aSearch

Definition at line 1960 of file connection_graph.cpp.

1962 {
1963  wxASSERT( aBusConnection->IsBus() );
1964 
1965  SCH_CONNECTION* match = nullptr;
1966 
1967  if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
1968  {
1969  // Vector bus: compare against index, because we allow the name
1970  // to be different
1971 
1972  for( const auto& bus_member : aBusConnection->Members() )
1973  {
1974  if( bus_member->VectorIndex() == aSearch->VectorIndex() )
1975  {
1976  match = bus_member.get();
1977  break;
1978  }
1979  }
1980  }
1981  else
1982  {
1983  // Group bus
1984  for( const auto& c : aBusConnection->Members() )
1985  {
1986  // Vector inside group: compare names, because for bus groups
1987  // we expect the naming to be consistent across all usages
1988  // TODO(JE) explain this in the docs
1989  if( c->Type() == CONNECTION_TYPE::BUS )
1990  {
1991  for( const auto& bus_member : c->Members() )
1992  {
1993  if( bus_member->LocalName() == aSearch->LocalName() )
1994  {
1995  match = bus_member.get();
1996  break;
1997  }
1998  }
1999  }
2000  else if( c->LocalName() == aSearch->LocalName() )
2001  {
2002  match = c.get();
2003  break;
2004  }
2005  }
2006  }
2007 
2008  return match;
2009 }
wxString LocalName() const
long VectorIndex() const
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
bool IsBus() const
CONNECTION_TYPE Type() const
This item represents a bus vector.

References BUS, SCH_CONNECTION::IsBus(), SCH_CONNECTION::LocalName(), SCH_CONNECTION::Members(), SCH_CONNECTION::Type(), and SCH_CONNECTION::VectorIndex().

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ propagateToNeighbors()

void CONNECTION_GRAPH::propagateToNeighbors ( CONNECTION_SUBGRAPH aSubgraph)
private

Updates all neighbors of a subgraph with this one's connectivity info.

If this subgraph contains hierarchical links, this method will descent the hierarchy and propagate the connectivity across all linked sheets.

Definition at line 1616 of file connection_graph.cpp.

1617 {
1618  SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1619  std::vector<CONNECTION_SUBGRAPH*> search_list;
1620  std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1621  std::vector<SCH_CONNECTION*> stale_bus_members;
1622 
1623  auto visit =
1624  [&]( CONNECTION_SUBGRAPH* aParent )
1625  {
1626  for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1627  {
1628  SCH_SHEET_PATH path = aParent->m_sheet;
1629  path.push_back( pin->GetParent() );
1630 
1631  auto it = m_sheet_to_subgraphs_map.find( path );
1632 
1633  if( it == m_sheet_to_subgraphs_map.end() )
1634  continue;
1635 
1636  for( CONNECTION_SUBGRAPH* candidate : it->second )
1637  {
1638  if( !candidate->m_strong_driver
1639  || candidate->m_hier_ports.empty()
1640  || visited.count( candidate ) )
1641  {
1642  continue;
1643  }
1644 
1645  for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1646  {
1647  if( candidate->GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1648  {
1649  wxLogTrace( ConnTrace, "%lu: found child %lu (%s)", aParent->m_code,
1650  candidate->m_code, candidate->m_driver_connection->Name() );
1651 
1652  candidate->m_hier_parent = aParent;
1653 
1654  search_list.push_back( candidate );
1655  break;
1656  }
1657  }
1658  }
1659  }
1660 
1661  for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1662  {
1663  SCH_SHEET_PATH path = aParent->m_sheet;
1664  path.pop_back();
1665 
1666  auto it = m_sheet_to_subgraphs_map.find( path );
1667 
1668  if( it == m_sheet_to_subgraphs_map.end() )
1669  continue;
1670 
1671  for( CONNECTION_SUBGRAPH* candidate : it->second )
1672  {
1673  if( candidate->m_hier_pins.empty()
1674  || visited.count( candidate )
1675  || candidate->m_driver_connection->Type() != aParent->m_driver_connection->Type() )
1676  {
1677  continue;
1678  }
1679 
1680  for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1681  {
1682  SCH_SHEET_PATH pin_path = path;
1683  pin_path.push_back( pin->GetParent() );
1684 
1685  if( pin_path != aParent->m_sheet )
1686  continue;
1687 
1688  if( aParent->GetNameForDriver( label ) == candidate->GetNameForDriver( pin ) )
1689  {
1690  wxLogTrace( ConnTrace, "%lu: found additional parent %lu (%s)",
1691  aParent->m_code, candidate->m_code,
1692  candidate->m_driver_connection->Name() );
1693 
1694  search_list.push_back( candidate );
1695  break;
1696  }
1697  }
1698  }
1699  }
1700  };
1701 
1702  auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1703  for( const auto& kv : aParentGraph->m_bus_neighbors )
1704  {
1705  for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1706  {
1707  // May have been absorbed but won't have been deleted
1708  while( neighbor->m_absorbed )
1709  neighbor = neighbor->m_absorbed_by;
1710 
1711  SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1712 
1713  // Now member may be out of date, since we just cloned the
1714  // connection from higher up in the hierarchy. We need to
1715  // figure out what the actual new connection is.
1716  SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1717 
1718  if( !member )
1719  {
1720  // Try harder: we might match on a secondary driver
1721  for( CONNECTION_SUBGRAPH* sg : kv.second )
1722  {
1723  if( sg->m_multiple_drivers )
1724  {
1725  SCH_SHEET_PATH sheet = sg->m_sheet;
1726 
1727  for( SCH_ITEM* driver : sg->m_drivers )
1728  {
1729  auto c = getDefaultConnection( driver, sg );
1730  member = matchBusMember( parent, c.get() );
1731 
1732  if( member )
1733  break;
1734  }
1735  }
1736 
1737  if( member )
1738  break;
1739  }
1740  }
1741 
1742  // This is bad, probably an ERC error
1743  if( !member )
1744  {
1745  wxLogTrace( ConnTrace, "Could not match bus member %s in %s",
1746  kv.first->Name(), parent->Name() );
1747  continue;
1748  }
1749 
1750  auto neighbor_conn = neighbor->m_driver_connection;
1751  auto neighbor_name = neighbor_conn->Name();
1752 
1753  // Matching name: no update needed
1754  if( neighbor_name == member->Name() )
1755  continue;
1756 
1757  // Was this neighbor already updated from a different sheet? Don't rename it again
1758  if( neighbor_conn->Sheet() != neighbor->m_sheet )
1759  continue;
1760 
1761  // Safety check against infinite recursion
1762  wxASSERT( neighbor_conn->IsNet() );
1763 
1764  wxLogTrace( ConnTrace, "%lu (%s) connected to bus member %s (local %s)",
1765  neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1766 
1767  // Take whichever name is higher priority
1770  {
1771  member->Clone( *neighbor_conn );
1772  stale_bus_members.push_back( member );
1773  }
1774  else
1775  {
1776  neighbor_conn->Clone( *member );
1777 
1778  recacheSubgraphName( neighbor, neighbor_name );
1779 
1780  // Recurse onto this neighbor in case it needs to re-propagate
1781  neighbor->m_dirty = true;
1782  propagateToNeighbors( neighbor );
1783  }
1784  }
1785  }
1786  };
1787 
1788  // If we are a bus, we must propagate to local neighbors and then the hierarchy
1789  if( conn->IsBus() )
1790  propagate_bus_neighbors( aSubgraph );
1791 
1792  // If we don't have any hier pins (i.e. no children), nothing to do
1793  if( aSubgraph->m_hier_pins.empty() )
1794  {
1795  // If we also don't have any parents, we'll never be visited again
1796  if( aSubgraph->m_hier_ports.empty() )
1797  aSubgraph->m_dirty = false;
1798 
1799  return;
1800  }
1801 
1802  // If we do have hier ports, skip this subgraph as it will be visited by a parent
1803  // TODO(JE) this will leave the subgraph dirty if there is no matching parent subgraph,
1804  // which should be flagged as an ERC error
1805  if( !aSubgraph->m_hier_ports.empty() )
1806  return;
1807 
1808  visited.insert( aSubgraph );
1809 
1810  wxLogTrace( ConnTrace, "Propagating %lu (%s) to subsheets",
1811  aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1812 
1813  visit( aSubgraph );
1814 
1815  for( unsigned i = 0; i < search_list.size(); i++ )
1816  {
1817  auto child = search_list[i];
1818 
1819  visited.insert( child );
1820 
1821  visit( child );
1822 
1823  child->m_dirty = false;
1824  }
1825 
1826  // Now, find the best driver for this chain of subgraphs
1827  CONNECTION_SUBGRAPH* original = aSubgraph;
1830  bool originalStrong = ( highest >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1831  wxString originalName = original->m_driver_connection->Name();
1832 
1833  // Check if a subsheet has a higher-priority connection to the same net
1835  {
1836  for( CONNECTION_SUBGRAPH* subgraph : visited )
1837  {
1838  if( subgraph == original )
1839  continue;
1840 
1842  CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
1843 
1844  bool candidateStrong = ( priority >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1845  wxString candidateName = subgraph->m_driver_connection->Name();
1846  bool shorterPath = subgraph->m_sheet.size() < original->m_sheet.size();
1847  bool asGoodPath = subgraph->m_sheet.size() <= original->m_sheet.size();
1848 
1849  // Pick a better driving subgraph if it:
1850  // a) has a power pin or global driver
1851  // b) is a strong driver and we're a weak driver
1852  // c) is a higher priority strong driver
1853  // d) matches our priority, is a strong driver, and has a shorter path
1854  // e) matches our strength and is at least as short, and is alphabetically lower
1855 
1856  if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
1857  ( !originalStrong && candidateStrong ) ||
1858  ( priority > highest && candidateStrong ) ||
1859  ( priority == highest && candidateStrong && shorterPath ) ||
1860  ( ( originalStrong == candidateStrong ) && asGoodPath &&
1861  ( candidateName < originalName ) ) )
1862  {
1863  original = subgraph;
1864  highest = priority;
1865  originalStrong = candidateStrong;
1866  originalName = subgraph->m_driver_connection->Name();
1867  }
1868  }
1869  }
1870 
1871  if( original != aSubgraph )
1872  {
1873  wxLogTrace( ConnTrace, "%lu (%s) overridden by new driver %lu (%s)",
1874  aSubgraph->m_code, aSubgraph->m_driver_connection->Name(), original->m_code,
1875  original->m_driver_connection->Name() );
1876  }
1877 
1878  conn = original->m_driver_connection;
1879 
1880  for( CONNECTION_SUBGRAPH* subgraph : visited )
1881  {
1882  wxString old_name = subgraph->m_driver_connection->Name();
1883 
1884  subgraph->m_driver_connection->Clone( *conn );
1885 
1886  if( old_name != conn->Name() )
1887  recacheSubgraphName( subgraph, old_name );
1888 
1889  if( conn->IsBus() )
1890  propagate_bus_neighbors( subgraph );
1891  }
1892 
1893  // Somewhere along the way, a bus member may have been upgraded to a global or power label.
1894  // Because this can happen anywhere, we need a second pass to update all instances of that bus
1895  // member to have the correct connection info
1896  if( conn->IsBus() && !stale_bus_members.empty() )
1897  {
1898  for( auto stale_member : stale_bus_members )
1899  {
1900  for( CONNECTION_SUBGRAPH* subgraph : visited )
1901  {
1902  SCH_CONNECTION* member = matchBusMember( subgraph->m_driver_connection,
1903  stale_member );
1904  wxASSERT( member );
1905 
1906  wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", subgraph->m_code,
1907  subgraph->m_driver_connection->Name(), member->LocalName(),
1908  stale_member->Name() );
1909 
1910  member->Clone( *stale_member );
1911 
1912  propagate_bus_neighbors( subgraph );
1913  }
1914  }
1915  }
1916 
1917  aSubgraph->m_dirty = false;
1918 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
#define kv
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
std::vector< SCH_SHEET_PIN * > m_hier_pins
wxString LocalName() const
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
size_t size() const
Forwarded method from std::vector.
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::vector< SCH_HIERLABEL * > m_hier_ports
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Builds a new default connection for the given item based on its properties.
CONNECTION_SUBGRAPH * m_hier_parent
bool IsBus() const
CONNECTION_TYPE Type() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
PRIORITY GetDriverPriority()
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.

References SCH_CONNECTION::Clone(), ConnTrace, getDefaultConnection(), CONNECTION_SUBGRAPH::GetDriverPriority(), CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::HIER_LABEL, SCH_CONNECTION::IsBus(), kv, SCH_CONNECTION::LocalName(), CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_hier_pins, CONNECTION_SUBGRAPH::m_hier_ports, CONNECTION_SUBGRAPH::m_multiple_drivers, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, CONNECTION_SUBGRAPH::m_strong_driver, matchBusMember(), SCH_CONNECTION::Name(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, SCH_SHEET_PATH::push_back(), recacheSubgraphName(), SCH_SHEET_PATH::size(), and SCH_CONNECTION::Type().

Referenced by buildConnectionGraph().

◆ recacheSubgraphName()

void CONNECTION_GRAPH::recacheSubgraphName ( CONNECTION_SUBGRAPH aSubgraph,
const wxString &  aOldName 
)
private

Definition at line 2012 of file connection_graph.cpp.

2014 {
2015  auto it = m_net_name_to_subgraphs_map.find( aOldName );
2016 
2017  if( it != m_net_name_to_subgraphs_map.end() )
2018  {
2019  std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2020  vec.erase( std::remove( vec.begin(), vec.end(), aSubgraph ), vec.end() );
2021  }
2022 
2023  wxLogTrace( ConnTrace, "recacheSubgraphName: %s => %s", aOldName,
2024  aSubgraph->m_driver_connection->Name() );
2025 
2026  m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
2027 }
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
static const wxChar ConnTrace[]
wxString Name(bool aIgnoreSheet=false) const

References ConnTrace, CONNECTION_SUBGRAPH::m_driver_connection, m_net_name_to_subgraphs_map, and SCH_CONNECTION::Name().

Referenced by propagateToNeighbors().

◆ Recalculate()

void CONNECTION_GRAPH::Recalculate ( const SCH_SHEET_LIST aSheetList,
bool  aUnconditional = false,
std::function< void(SCH_ITEM *)> *  aChangedItemHandler = nullptr 
)

Updates the connection graph for the given list of sheets.

Parameters
aSheetListis the list of possibly modified sheets
aUnconditionalis true if an unconditional full recalculation should be done
aChangedItemHandleran optional handler to receive any changed items

Definition at line 439 of file connection_graph.cpp.

441 {
442  PROF_COUNTER recalc_time( "CONNECTION_GRAPH::Recalculate" );
443 
444  if( aUnconditional )
445  Reset();
446 
447  PROF_COUNTER update_items( "updateItemConnectivity" );
448 
449  m_sheetList = aSheetList;
450 
451  for( const SCH_SHEET_PATH& sheet : aSheetList )
452  {
453  std::vector<SCH_ITEM*> items;
454 
455  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
456  {
457  if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
458  items.push_back( item );
459  }
460 
461  m_items.reserve( m_items.size() + items.size() );
462 
463  updateItemConnectivity( sheet, items );
464 
465  // UpdateDanglingState() also adds connected items for SCH_TEXT
466  sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
467  }
468 
469  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
470  update_items.Show();
471 
472  PROF_COUNTER build_graph( "buildConnectionGraph" );
473 
475 
476  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
477  build_graph.Show();
478 
479  recalc_time.Stop();
480 
481  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
482  recalc_time.Show();
483 
484 #ifndef DEBUG
485  // Pressure relief valve for release builds
486  const double max_recalc_time_msecs = 250.;
487 
488  if( m_allowRealTime && ADVANCED_CFG::GetCfg().m_RealTimeConnectivity &&
489  recalc_time.msecs() > max_recalc_time_msecs )
490  {
491  m_allowRealTime = false;
492  }
493 #endif
494 }
void buildConnectionGraph()
Generates the connection graph (after all item connectivity has been updated)
std::vector< SCH_ITEM * > m_items
A small class to help profiling.
Definition: profile.h:45
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
static const wxChar ConnProfileMask[]
static bool m_allowRealTime
SCH_SHEET_LIST m_sheetList
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197

References buildConnectionGraph(), ConnProfileMask, ADVANCED_CFG::GetCfg(), m_allowRealTime, m_items, m_sheetList, PROF_COUNTER::msecs(), Reset(), PROF_COUNTER::Show(), PROF_COUNTER::Stop(), and updateItemConnectivity().

Referenced by TEST_NETLISTS_FIXTURE::loadSchematic(), SCH_EDIT_FRAME::RecalculateConnections(), and SCH_SCREENS::UpdateSymbolLinks().

◆ Reset()

void CONNECTION_GRAPH::Reset ( )

Definition at line 415 of file connection_graph.cpp.

416 {
417  for( auto& subgraph : m_subgraphs )
418  delete subgraph;
419 
420  m_items.clear();
421  m_subgraphs.clear();
422  m_driver_subgraphs.clear();
423  m_sheet_to_subgraphs_map.clear();
424  m_invisible_power_pins.clear();
425  m_bus_alias_cache.clear();
426  m_net_name_to_code_map.clear();
427  m_bus_name_to_code_map.clear();
430  m_item_to_subgraph_map.clear();
431  m_local_label_cache.clear();
432  m_global_label_cache.clear();
433  m_last_net_code = 1;
434  m_last_bus_code = 1;
436 }
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
NET_MAP m_net_code_to_subgraphs_map
std::vector< SCH_ITEM * > m_items
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
std::map< wxString, int > m_bus_name_to_code_map
std::map< wxString, int > m_net_name_to_code_map
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

References m_bus_alias_cache, m_bus_name_to_code_map, m_driver_subgraphs, m_global_label_cache, m_invisible_power_pins, m_item_to_subgraph_map, m_items, m_last_bus_code, m_last_net_code, m_last_subgraph_code, m_local_label_cache, m_net_code_to_subgraphs_map, m_net_name_to_code_map, m_net_name_to_subgraphs_map, m_sheet_to_subgraphs_map, and m_subgraphs.

Referenced by SCH_EDIT_FRAME::OpenProjectFiles(), Recalculate(), SCHEMATIC::Reset(), SCHEMATIC::SetRoot(), and ~CONNECTION_GRAPH().

◆ RunERC()

int CONNECTION_GRAPH::RunERC ( )

Runs electrical rule checks on the connectivity graph.

Precondition: graph is up-to-date

Returns
the number of errors found

NOTE:

We could check that labels attached to bus subgraphs follow the proper format (i.e. actually define a bus).

This check doesn't need to be here right now because labels won't actually be connected to bus wires if they aren't in the right format due to their TestDanglingEnds() implementation.

Definition at line 2132 of file connection_graph.cpp.

2133 {
2134  int error_count = 0;
2135 
2136  wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::RunERC" );
2137 
2138  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2139 
2140  // We don't want to run many ERC checks more than once on a given screen even though it may
2141  // represent multiple sheets with multiple subgraphs. We can tell these apart by drivers.
2142  std::set<SCH_ITEM*> seenDriverInstances;
2143 
2144  for( auto&& subgraph : m_subgraphs )
2145  {
2146  // Graph is supposed to be up-to-date before calling RunERC()
2147  wxASSERT( !subgraph->m_dirty );
2148 
2149  if( subgraph->m_absorbed )
2150  continue;
2151 
2152  if( seenDriverInstances.count( subgraph->m_driver ) )
2153  continue;
2154 
2155  if( subgraph->m_driver )
2156  seenDriverInstances.insert( subgraph->m_driver );
2157 
2168  if( settings.IsTestEnabled( ERCE_DRIVER_CONFLICT ) )
2169  {
2170  if( !ercCheckMultipleDrivers( subgraph ) )
2171  error_count++;
2172  }
2173 
2174  subgraph->ResolveDrivers( false );
2175 
2176  if( settings.IsTestEnabled( ERCE_BUS_TO_NET_CONFLICT ) )
2177  {
2178  if( !ercCheckBusToNetConflicts( subgraph ) )
2179  error_count++;
2180  }
2181 
2182  if( settings.IsTestEnabled( ERCE_BUS_ENTRY_CONFLICT ) )
2183  {
2184  if( !ercCheckBusToBusEntryConflicts( subgraph ) )
2185  error_count++;
2186  }
2187 
2188  if( settings.IsTestEnabled( ERCE_BUS_TO_BUS_CONFLICT ) )
2189  {
2190  if( !ercCheckBusToBusConflicts( subgraph ) )
2191  error_count++;
2192  }
2193 
2194  if( settings.IsTestEnabled( ERCE_WIRE_DANGLING ) )
2195  {
2196  if( !ercCheckFloatingWires( subgraph ) )
2197  error_count++;
2198  }
2199 
2200  // The following checks are always performed since they don't currently
2201  // have an option exposed to the user
2202 
2203  if( !ercCheckNoConnects( subgraph ) )
2204  error_count++;
2205 
2206  if( settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED )
2207  || settings.IsTestEnabled( ERCE_GLOBLABEL ) )
2208  {
2209  if( !ercCheckLabels( subgraph ) )
2210  error_count++;
2211  }
2212  }
2213 
2214  // Hierarchical sheet checking is done at the schematic level
2215  if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
2216  error_count += ercCheckHierSheets();
2217 
2218  return error_count;
2219 }
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:59
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:122
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:61
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
Some wires are not connected to anything else.
Definition: erc_settings.h:65
Label not connected to anything.
Definition: erc_settings.h:49
SCHEMATIC * m_schematic
The schematic this graph represents.
int ercCheckHierSheets()
Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on th...
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between net and bus labels.
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper presence or absence of no-connect symbols.
Container for ERC settings.
Definition: erc_settings.h:105
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:57
A global label is unique.
Definition: erc_settings.h:63
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:46
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:134
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:56
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.

References ercCheckBusToBusConflicts(), ercCheckBusToBusEntryConflicts(), ercCheckBusToNetConflicts(), ercCheckFloatingWires(), ercCheckHierSheets(), ercCheckLabels(), ercCheckMultipleDrivers(), ercCheckNoConnects(), ERCE_BUS_ENTRY_CONFLICT, ERCE_BUS_TO_BUS_CONFLICT, ERCE_BUS_TO_NET_CONFLICT, ERCE_DRIVER_CONFLICT, ERCE_GLOBLABEL, ERCE_HIERACHICAL_LABEL, ERCE_LABEL_NOT_CONNECTED, ERCE_WIRE_DANGLING, SCHEMATIC::ErcSettings(), ERC_SETTINGS::IsTestEnabled(), m_schematic, and m_subgraphs.

Referenced by DIALOG_ERC::testErc().

◆ SetSchematic()

void CONNECTION_GRAPH::SetSchematic ( SCHEMATIC aSchematic)
inline

Definition at line 265 of file connection_graph.h.

266  {
267  m_schematic = aSchematic;
268  }
SCHEMATIC * m_schematic
The schematic this graph represents.

References m_schematic.

◆ updateItemConnectivity()

void CONNECTION_GRAPH::updateItemConnectivity ( const SCH_SHEET_PATH aSheet,
const std::vector< SCH_ITEM * > &  aItemList 
)
private

Updates the graphical connectivity between items (i.e.

where they touch) The items passed in must be on the same sheet.

In the first phase, all items in aItemList have their connections initialized for the given sheet (since they may have connections on more than one sheet, and each needs to be calculated individually). The graphical connection points for the item are added to a map that stores (x, y) -> [list of items].

Any item that is stored in the list of items that have a connection point at a given (x, y) location will eventually be electrically connected. This means that we can't store SCH_COMPONENTs in this map – we must store a structure that links a specific pin on a component back to that component: a SCH_PIN_CONNECTION. This wrapper class is a convenience for linking a pin and component to a specific (x, y) point.

In the second phase, we iterate over each value in the map, which is a vector of items that have overlapping connection points. After some checks to ensure that the items should actually connect, the items are linked together using ConnectedItems().

As a side effect, items are loaded into m_items for BuildConnectionGraph()

Parameters
aSheetis the path to the sheet of all items in the list
aItemListis a list of items to consider

Definition at line 497 of file connection_graph.cpp.

499 {
500  std::map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
501 
502  for( SCH_ITEM* item : aItemList )
503  {
504  std::vector< wxPoint > points = item->GetConnectionPoints();
505  item->ConnectedItems( aSheet ).clear();
506 
507  if( item->Type() == SCH_SHEET_T )
508  {
509  for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
510  {
511  pin->InitializeConnection( aSheet, this );
512 
513  pin->ConnectedItems( aSheet ).clear();
514 
515  connection_map[ pin->GetTextPos() ].push_back( pin );
516  m_items.emplace_back( pin );
517  }
518  }
519  else if( item->Type() == SCH_COMPONENT_T )
520  {
521  SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
522 
523  for( SCH_PIN* pin : component->GetPins( &aSheet ) )
524  {
525  pin->InitializeConnection( aSheet, this );
526 
527  wxPoint pos = pin->GetPosition();
528 
529  // because calling the first time is not thread-safe
530  pin->GetDefaultNetName( aSheet );
531  pin->ConnectedItems( aSheet ).clear();
532 
533  // Invisible power pins need to be post-processed later
534 
535  if( pin->IsPowerConnection() && !pin->IsVisible() )
536  m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) );
537 
538  connection_map[ pos ].push_back( pin );
539  m_items.emplace_back( pin );
540  }
541  }
542  else
543  {
544  m_items.emplace_back( item );
545  auto conn = item->InitializeConnection( aSheet, this );
546 
547  // Set bus/net property here so that the propagation code uses it
548  switch( item->Type() )
549  {
550  case SCH_LINE_T:
551  conn->SetType( item->GetLayer() == LAYER_BUS ? CONNECTION_TYPE::BUS :
553  break;
554 
555  case SCH_BUS_BUS_ENTRY_T:
556  conn->SetType( CONNECTION_TYPE::BUS );
557  // clean previous (old) links:
558  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] = nullptr;
559  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] = nullptr;
560  break;
561 
562  case SCH_PIN_T:
563  conn->SetType( CONNECTION_TYPE::NET );
564  break;
565 
567  conn->SetType( CONNECTION_TYPE::NET );
568  // clean previous (old) link:
569  static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item = nullptr;
570  break;
571 
572  default:
573  break;
574  }
575 
576  for( const wxPoint& point : points )
577  connection_map[ point ].push_back( item );
578  }
579 
580  item->SetConnectivityDirty( false );
581  }
582 
583  for( const auto& it : connection_map )
584  {
585  auto connection_vec = it.second;
586 
587  for( auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ )
588  {
589  SCH_ITEM* connected_item = *primary_it;
590 
591  // Bus entries are special: they can have connection points in the
592  // middle of a wire segment, because the junction algo doesn't split
593  // the segment in two where you place a bus entry. This means that
594  // bus entries that don't land on the end of a line segment need to
595  // have "virtual" connection points to the segments they graphically
596  // touch.
597  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
598  {
599  // If this location only has the connection point of the bus
600  // entry itself, this means that either the bus entry is not
601  // connected to anything graphically, or that it is connected to
602  // a segment at some point other than at one of the endpoints.
603  if( connection_vec.size() == 1 )
604  {
605  SCH_SCREEN* screen = aSheet.LastScreen();
606  SCH_LINE* bus = screen->GetBus( it.first );
607 
608  if( bus )
609  {
610  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
611  bus_entry->m_connected_bus_item = bus;
612  }
613  }
614  }
615 
616  // Bus-to-bus entries are treated just like bus wires
617  else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
618  {
619  if( connection_vec.size() < 2 )
620  {
621  SCH_SCREEN* screen = aSheet.LastScreen();
622  SCH_LINE* bus = screen->GetBus( it.first );
623 
624  if( bus )
625  {
626  auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
627 
628  if( it.first == bus_entry->GetPosition() )
629  bus_entry->m_connected_bus_items[0] = bus;
630  else
631  bus_entry->m_connected_bus_items[1] = bus;
632 
633  bus_entry->ConnectedItems( aSheet ).insert( bus );
634  bus->ConnectedItems( aSheet ).insert( bus_entry );
635  }
636  }
637  }
638 
639  // Change junctions to be on bus junction layer if they are touching a bus
640  else if( connected_item->Type() == SCH_JUNCTION_T )
641  {
642  SCH_SCREEN* screen = aSheet.LastScreen();
643  SCH_LINE* bus = screen->GetBus( it.first );
644 
645  connected_item->SetLayer( bus ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
646  }
647 
648  for( auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ )
649  {
650  auto test_item = *test_it;
651 
652  if( connected_item != test_item &&
653  connected_item->ConnectionPropagatesTo( test_item ) &&
654  test_item->ConnectionPropagatesTo( connected_item ) )
655  {
656  connected_item->ConnectedItems( aSheet ).insert( test_item );
657  test_item->ConnectedItems( aSheet ).insert( connected_item );
658  }
659 
660  // Set up the link between the bus entry net and the bus
661  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
662  {
663  if( test_item->Connection( &aSheet )->IsBus() )
664  {
665  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
666  bus_entry->m_connected_bus_item = test_item;
667  }
668  }
669  }
670 
671  // If we got this far and did not find a connected bus item for a bus entry,
672  // we should do a manual scan in case there is a bus item on this connection
673  // point but we didn't pick it up earlier because there is *also* a net item here.
674  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
675  {
676  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
677 
678  if( !bus_entry->m_connected_bus_item )
679  {
680  auto screen = aSheet.LastScreen();
681  auto bus = screen->GetBus( it.first );
682 
683  if( bus )
684  bus_entry->m_connected_bus_item = bus;
685  }
686  }
687  }
688  }
689 }
virtual bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const
Return true if this item should propagate connection info to aItem.
Definition: sch_item.h:422
std::vector< SCH_ITEM * > m_items
SCH_LINE * GetBus(const wxPoint &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:394
void SetLayer(SCH_LAYER_ID aLayer)
Set the layer this item is on.
Definition: sch_item.h:279
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
This item represents a net.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:884
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
SCH_SCREEN * LastScreen()
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
SCH_ITEM_SET & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieve the set of items connected to this item on the given sheet.
Definition: sch_item.cpp:164
Schematic symbol object.
Definition: sch_symbol.h:78
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:163

References BUS, SCH_ITEM::ConnectedItems(), SCH_ITEM::ConnectionPropagatesTo(), SCH_SCREEN::GetBus(), SCH_COMPONENT::GetPins(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, LAYER_BUS_JUNCTION, LAYER_JUNCTION, m_invisible_power_pins, m_items, NET, pin, SCH_BUS_BUS_ENTRY_T, SCH_BUS_WIRE_ENTRY_T, SCH_COMPONENT_T, SCH_JUNCTION_T, SCH_LINE_T, SCH_PIN_T, SCH_SHEET_T, SCH_ITEM::SetLayer(), and EDA_ITEM::Type().

Referenced by Recalculate().

Member Data Documentation

◆ m_allowRealTime

◆ m_bus_alias_cache

std::unordered_map< wxString, std::shared_ptr<BUS_ALIAS> > CONNECTION_GRAPH::m_bus_alias_cache
private

Definition at line 528 of file connection_graph.h.

Referenced by buildConnectionGraph(), GetBusAlias(), and Reset().

◆ m_bus_name_to_code_map

std::map<wxString, int> CONNECTION_GRAPH::m_bus_name_to_code_map
private

Definition at line 532 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_driver_subgraphs

std::vector<CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_driver_subgraphs
private

Definition at line 521 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_global_label_cache

std::map<wxString, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_global_label_cache
private

Definition at line 534 of file connection_graph.h.

Referenced by buildConnectionGraph(), ercCheckNoConnects(), and Reset().

◆ m_invisible_power_pins

std::vector<std::pair<SCH_SHEET_PATH, SCH_PIN*> > CONNECTION_GRAPH::m_invisible_power_pins
private

Definition at line 526 of file connection_graph.h.

Referenced by buildConnectionGraph(), Reset(), and updateItemConnectivity().

◆ m_item_to_subgraph_map

std::map<SCH_ITEM*, CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_item_to_subgraph_map
private

Definition at line 541 of file connection_graph.h.

Referenced by buildConnectionGraph(), GetSubgraphForItem(), and Reset().

◆ m_items

std::vector<SCH_ITEM*> CONNECTION_GRAPH::m_items
private

◆ m_last_bus_code

int CONNECTION_GRAPH::m_last_bus_code
private

Definition at line 547 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_last_net_code

int CONNECTION_GRAPH::m_last_net_code
private

Definition at line 545 of file connection_graph.h.

Referenced by assignNewNetCode(), and Reset().

◆ m_last_subgraph_code

int CONNECTION_GRAPH::m_last_subgraph_code
private

Definition at line 549 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_local_label_cache

std::map< std::pair<SCH_SHEET_PATH, wxString>, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_local_label_cache
private

◆ m_net_code_to_subgraphs_map

NET_MAP CONNECTION_GRAPH::m_net_code_to_subgraphs_map
private

Definition at line 543 of file connection_graph.h.

Referenced by buildConnectionGraph(), GetNetMap(), and Reset().

◆ m_net_name_to_code_map

std::map<wxString, int> CONNECTION_GRAPH::m_net_name_to_code_map
private

Definition at line 530 of file connection_graph.h.

Referenced by assignNewNetCode(), and Reset().

◆ m_net_name_to_subgraphs_map

std::unordered_map<wxString, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_net_name_to_subgraphs_map
private

◆ m_schematic

SCHEMATIC* CONNECTION_GRAPH::m_schematic
private

The schematic this graph represents.

Definition at line 551 of file connection_graph.h.

Referenced by buildConnectionGraph(), ercCheckHierSheets(), ercCheckLabels(), ercCheckNoConnects(), RunERC(), and SetSchematic().

◆ m_sheet_to_subgraphs_map

std::unordered_map<SCH_SHEET_PATH, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_sheet_to_subgraphs_map
private

Definition at line 524 of file connection_graph.h.

Referenced by buildConnectionGraph(), propagateToNeighbors(), and Reset().

◆ m_sheetList

SCH_SHEET_LIST CONNECTION_GRAPH::m_sheetList
private

Definition at line 512 of file connection_graph.h.

Referenced by ercCheckHierSheets(), and Recalculate().

◆ m_subgraphs

std::vector<CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_subgraphs
private

Definition at line 518 of file connection_graph.h.

Referenced by buildConnectionGraph(), GetBusesNeedingMigration(), Reset(), and RunERC().


The documentation for this class was generated from the following files: