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 (SCH_EDIT_FRAME *aFrame)
 
 ~CONNECTION_GRAPH ()
 
void Reset ()
 
void Recalculate (const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false)
 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 (const ERC_SETTINGS &aSettings, bool aCreateMarkers=true)
 Runs electrical rule checks on the connectivity graph. More...
 
const NET_MAPGetNetMap () const
 

Static Public Attributes

static bool m_allowRealTime = true
 

Private Member Functions

void updateItemConnectivity (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...
 
void recacheSubgraphName (CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
 
bool ercCheckBusToNetConflicts (const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
 Checks one subgraph for conflicting connections between net and bus labels. More...
 
bool ercCheckBusToBusConflicts (const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
 Checks one subgraph for conflicting connections between two bus items. More...
 
bool ercCheckBusToBusEntryConflicts (const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
 Checks one subgraph for conflicting bus entry to bus connections. More...
 
bool ercCheckNoConnects (const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
 Checks one subgraph for proper presence or absence of no-connect symbols. More...
 
bool ercCheckLabels (const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers, bool aCheckGlobalLabels)
 Checks one subgraph for proper connection of labels. 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

std::unordered_set< 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
 
NET_MAP m_net_code_to_subgraphs_map
 
int m_last_net_code
 
int m_last_bus_code
 
int m_last_subgraph_code
 
std::mutex m_item_mutex
 
SCH_EDIT_FRAMEm_frame
 

Detailed Description

Calculates the connectivity of a schematic and generates netlists.

Definition at line 210 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCH_EDIT_FRAME aFrame)
inline

Definition at line 213 of file connection_graph.h.

214  : m_last_net_code( 1 ),
215  m_last_bus_code( 1 ),
217  m_frame( aFrame )
218  {}
SCH_EDIT_FRAME * m_frame

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 220 of file connection_graph.h.

221  {
222  Reset();
223  }

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 1455 of file connection_graph.cpp.

1456 {
1457  auto connections_to_check( aConnection->Members() );
1458 
1459  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1460  {
1461  auto member = connections_to_check[i];
1462 
1463  if( member->IsBus() )
1464  {
1465  connections_to_check.insert( connections_to_check.end(),
1466  member->Members().begin(),
1467  member->Members().end() );
1468  continue;
1469  }
1470 
1471  assignNewNetCode( *member );
1472  }
1473 }
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 1435 of file connection_graph.cpp.

1436 {
1437  int code;
1438 
1439  if( m_net_name_to_code_map.count( aConnection.Name() ) )
1440  {
1441  code = m_net_name_to_code_map.at( aConnection.Name() );
1442  }
1443  else
1444  {
1445  code = m_last_net_code++;
1446  m_net_name_to_code_map[ aConnection.Name() ] = code;
1447  }
1448 
1449  aConnection.SetNetCode( code );
1450 
1451  return code;
1452 }
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)

It would be good if net codes were preserved as much as possible when generating netlists, so that unnamed nets don't keep shifting around when you regenerate.

Right now, we are clearing out the old connections up in UpdateItemConnectivity(), but that is useful information, so maybe we need to just set the dirty flag or something.

That way, ResolveDrivers() can check what the driver of the subgraph was previously, and if it is in the situation of choosing between equal candidates for an auto-generated net name, pick the previous one.

N.B. the old algorithm solves this by sorting the possible net names alphabetically, so as long as the same refdes components are involved, the net will be the same.

Definition at line 645 of file connection_graph.cpp.

646 {
647  // Recache all bus aliases for later use
648 
649  SCH_SHEET_LIST all_sheets( g_RootSheet );
650 
651  for( unsigned i = 0; i < all_sheets.size(); i++ )
652  {
653  for( const auto& alias : all_sheets[i].LastScreen()->GetBusAliases() )
654  {
655  m_bus_alias_cache[ alias->GetName() ] = alias;
656  }
657  }
658 
659  // Build subgraphs from items (on a per-sheet basis)
660 
661  for( SCH_ITEM* item : m_items )
662  {
663  for( const auto& it : item->m_connection_map )
664  {
665  const auto sheet = it.first;
666  auto connection = it.second;
667 
668  if( connection->SubgraphCode() == 0 )
669  {
670  auto subgraph = new CONNECTION_SUBGRAPH( m_frame );
671 
672  subgraph->m_code = m_last_subgraph_code++;
673  subgraph->m_sheet = sheet;
674 
675  subgraph->AddItem( item );
676 
677  connection->SetSubgraphCode( subgraph->m_code );
678 
679  std::list<SCH_ITEM*> members;
680 
681  auto get_items = [ &sheet ] ( SCH_ITEM* aItem ) -> bool
682  {
683  auto* conn = aItem->Connection( sheet );
684 
685  if( !conn )
686  conn = aItem->InitializeConnection( sheet );
687 
688  return ( conn->SubgraphCode() == 0 );
689  };
690 
691  std::copy_if( item->ConnectedItems().begin(),
692  item->ConnectedItems().end(),
693  std::back_inserter( members ), get_items );
694 
695  for( auto connected_item : members )
696  {
697  if( connected_item->Type() == SCH_NO_CONNECT_T )
698  subgraph->m_no_connect = connected_item;
699 
700  auto connected_conn = connected_item->Connection( sheet );
701 
702  wxASSERT( connected_conn );
703 
704  if( connected_conn->SubgraphCode() == 0 )
705  {
706  connected_conn->SetSubgraphCode( subgraph->m_code );
707  subgraph->AddItem( connected_item );
708 
709  std::copy_if( connected_item->ConnectedItems().begin(),
710  connected_item->ConnectedItems().end(),
711  std::back_inserter( members ), get_items );
712  }
713  }
714 
715  subgraph->m_dirty = true;
716  m_subgraphs.push_back( subgraph );
717  }
718  }
719  }
720 
741  // Resolve drivers for subgraphs and propagate connectivity info
742 
743  // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
744  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
745  ( m_subgraphs.size() + 3 ) / 4 );
746 
747  std::atomic<size_t> nextSubgraph( 0 );
748  std::vector<std::future<size_t>> returns( parallelThreadCount );
749  std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
750 
751  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( dirty_graphs ),
752  [&] ( const CONNECTION_SUBGRAPH* candidate ) {
753  return candidate->m_dirty;
754  } );
755 
756  auto update_lambda = [&nextSubgraph, &dirty_graphs]() -> size_t
757  {
758  for( size_t subgraphId = nextSubgraph++; subgraphId < dirty_graphs.size(); subgraphId = nextSubgraph++ )
759  {
760  auto subgraph = dirty_graphs[subgraphId];
761 
762  if( !subgraph->m_dirty )
763  continue;
764 
765  // Special processing for some items
766  for( auto item : subgraph->m_items )
767  {
768  switch( item->Type() )
769  {
770  case SCH_NO_CONNECT_T:
771  subgraph->m_no_connect = item;
772  break;
773 
775  subgraph->m_bus_entry = item;
776  break;
777 
778  case SCH_PIN_T:
779  {
780  auto pin = static_cast<SCH_PIN*>( item );
781 
782  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
783  subgraph->m_no_connect = item;
784 
785  break;
786  }
787 
788  default:
789  break;
790  }
791  }
792 
793  if( !subgraph->ResolveDrivers() )
794  {
795  subgraph->m_dirty = false;
796  }
797  else
798  {
799  // Now the subgraph has only one driver
800  SCH_ITEM* driver = subgraph->m_driver;
801  SCH_SHEET_PATH sheet = subgraph->m_sheet;
802  SCH_CONNECTION* connection = driver->Connection( sheet );
803 
804  // TODO(JE) This should live in SCH_CONNECTION probably
805  switch( driver->Type() )
806  {
807  case SCH_LABEL_T:
808  case SCH_GLOBAL_LABEL_T:
809  case SCH_HIER_LABEL_T:
810  {
811  auto text = static_cast<SCH_TEXT*>( driver );
812  connection->ConfigureFromLabel( text->GetText() );
813  break;
814  }
815  case SCH_SHEET_PIN_T:
816  {
817  auto pin = static_cast<SCH_SHEET_PIN*>( driver );
818  connection->ConfigureFromLabel( pin->GetText() );
819  break;
820  }
821  case SCH_PIN_T:
822  {
823  auto pin = static_cast<SCH_PIN*>( driver );
824  // NOTE(JE) GetDefaultNetName is not thread-safe.
825  connection->ConfigureFromLabel( pin->GetDefaultNetName( sheet ) );
826 
827  break;
828  }
829  default:
830  wxLogTrace( "CONN", "Driver type unsupported: %s",
832  break;
833  }
834 
835  connection->SetDriver( driver );
836  connection->ClearDirty();
837 
838  subgraph->m_dirty = false;
839  }
840  }
841 
842  return 1;
843  };
844 
845  if( parallelThreadCount == 1 )
846  update_lambda();
847  else
848  {
849  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
850  returns[ii] = std::async( std::launch::async, update_lambda );
851 
852  // Finalize the threads
853  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
854  returns[ii].wait();
855  }
856 
857  // Now discard any non-driven subgraphs from further consideration
858 
859  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( m_driver_subgraphs ),
860  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool {
861  return candidate->m_driver;
862  } );
863 
864  // Check for subgraphs with the same net name but only weak drivers.
865  // For example, two wires that are both connected to hierarchical
866  // sheet pins that happen to have the same name, but are not the same.
867 
868  for( auto&& subgraph : m_driver_subgraphs )
869  {
870  wxString full_name = subgraph->m_driver_connection->Name();
871  wxString name = subgraph->m_driver_connection->Name( true );
872  m_net_name_to_subgraphs_map[full_name].emplace_back( subgraph );
873 
874  subgraph->m_dirty = true;
875 
876  if( subgraph->m_strong_driver )
877  {
878  SCH_ITEM* driver = subgraph->m_driver;
879  SCH_SHEET_PATH sheet = subgraph->m_sheet;
880 
881  switch( driver->Type() )
882  {
883  case SCH_LABEL_T:
884  case SCH_HIER_LABEL_T:
885  {
886  m_local_label_cache[std::make_pair( sheet, name )].push_back( subgraph );
887  break;
888  }
889  case SCH_GLOBAL_LABEL_T:
890  {
891  m_global_label_cache[name].push_back( subgraph );
892  break;
893  }
894  case SCH_PIN_T:
895  {
896  auto pin = static_cast<SCH_PIN*>( driver );
897  wxASSERT( pin->IsPowerConnection() );
898  m_global_label_cache[name].push_back( subgraph );
899  break;
900  }
901  default:
902  wxLogTrace( "CONN", "Unexpected strong driver %s",
904  break;
905  }
906  }
907  }
908 
909  // Generate subgraphs for invisible power pins. These will be merged with other subgraphs
910  // on the same sheet in the next loop.
911 
912  std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
913 
914  for( const auto& it : m_invisible_power_pins )
915  {
916  SCH_PIN* pin = it.second;
917 
918  if( !pin->ConnectedItems().empty() && !pin->GetLibPin()->GetParent()->IsPower() )
919  {
920  // ERC will warn about this: user has wired up an invisible pin
921  continue;
922  }
923 
924  SCH_SHEET_PATH sheet = it.first;
925  SCH_CONNECTION* connection = pin->Connection( sheet );
926 
927  if( !connection )
928  connection = pin->InitializeConnection( sheet );
929 
930  // If this pin already has a subgraph, don't need to process
931  if( connection->SubgraphCode() > 0 )
932  continue;
933 
934  connection->SetName( pin->GetName() );
935 
936  int code = assignNewNetCode( *connection );
937 
938  connection->SetNetCode( code );
939 
940  CONNECTION_SUBGRAPH* subgraph;
941 
942  if( invisible_pin_subgraphs.count( code ) )
943  {
944  subgraph = invisible_pin_subgraphs.at( code );
945  subgraph->AddItem( pin );
946  }
947  else
948  {
949  subgraph = new CONNECTION_SUBGRAPH( m_frame );
950 
951  subgraph->m_code = m_last_subgraph_code++;
952  subgraph->m_sheet = sheet;
953 
954  subgraph->AddItem( pin );
955  subgraph->ResolveDrivers();
956 
957  auto key = std::make_pair( subgraph->GetNetName(), code );
958  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
959  m_subgraphs.push_back( subgraph );
960  m_driver_subgraphs.push_back( subgraph );
961 
962  invisible_pin_subgraphs[code] = subgraph;
963  }
964 
965  connection->SetSubgraphCode( subgraph->m_code );
966  }
967 
968  for( auto it : invisible_pin_subgraphs )
969  it.second->UpdateItemConnections();
970 
971  // Here we do all the local (sheet) processing of each subgraph, including assigning net
972  // codes, merging subgraphs together that use label connections, etc.
973 
974  // Cache remaining valid subgraphs by sheet path
975  for( auto subgraph : m_driver_subgraphs )
976  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
977 
978  std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
979 
980  for( auto subgraph_it = m_driver_subgraphs.begin();
981  subgraph_it != m_driver_subgraphs.end(); subgraph_it++ )
982  {
983  auto subgraph = *subgraph_it;
984 
985  if( subgraph->m_absorbed )
986  continue;
987 
988  SCH_CONNECTION* connection = subgraph->m_driver_connection;
989  SCH_SHEET_PATH sheet = subgraph->m_sheet;
990  wxString name = connection->Name();
991 
992  // Test subgraphs with weak drivers for net name conflicts and fix them
993  unsigned suffix = 1;
994 
995  auto create_new_name = [&] ( SCH_CONNECTION* aConn, wxString aName ) -> wxString {
996  wxString new_name = wxString::Format( "%s_%u", aName, suffix );
997  aConn->SetSuffix( wxString::Format( "_%u", suffix ) );
998  suffix++;
999  return new_name;
1000  };
1001 
1002  if( !subgraph->m_strong_driver )
1003  {
1004  auto& vec = m_net_name_to_subgraphs_map.at( name );
1005 
1006  if( vec.size() > 1 )
1007  {
1008  wxString new_name = create_new_name( connection, name );
1009 
1010  while( m_net_name_to_subgraphs_map.count( new_name ) )
1011  new_name = create_new_name( connection, name );
1012 
1013  wxLogTrace( "CONN", "%ld (%s) is weakly driven and not unique. Changing to %s.",
1014  subgraph->m_code, name, new_name );
1015 
1016  vec.erase( std::remove( vec.begin(), vec.end(), subgraph ), vec.end() );
1017 
1018  m_net_name_to_subgraphs_map[new_name].emplace_back( subgraph );
1019 
1020  name = new_name;
1021 
1022  subgraph->UpdateItemConnections();
1023  }
1024  }
1025 
1026  // Assign net codes
1027 
1028  if( connection->IsBus() )
1029  {
1030  int code = -1;
1031 
1032  if( m_bus_name_to_code_map.count( name ) )
1033  {
1034  code = m_bus_name_to_code_map.at( name );
1035  }
1036  else
1037  {
1038  code = m_last_bus_code++;
1039  m_bus_name_to_code_map[ name ] = code;
1040  }
1041 
1042  connection->SetBusCode( code );
1043  assignNetCodesToBus( connection );
1044  }
1045  else
1046  {
1047  assignNewNetCode( *connection );
1048  }
1049 
1050  subgraph->UpdateItemConnections();
1051 
1052  // Reset the flag for the next loop below
1053  subgraph->m_dirty = true;
1054 
1055  // Next, we merge together subgraphs that have label connections, and create
1056  // neighbor links for subgraphs that are part of a bus on the same sheet.
1057  // For merging, we consider each possible strong driver.
1058 
1059  // If this subgraph doesn't have a strong driver, let's skip it, since there is no
1060  // way it will be merged with anything.
1061 
1062  if( !subgraph->m_strong_driver )
1063  continue;
1064 
1065  // candidate_subgraphs will contain each valid, non-bus subgraph on the same sheet
1066  // as the subgraph we are considering that has a strong driver.
1067  // Weakly driven subgraphs are not considered since they will never be absorbed or
1068  // form neighbor links.
1069 
1070  std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1071  std::copy_if( m_sheet_to_subgraphs_map[ subgraph->m_sheet ].begin(),
1072  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].end(),
1073  std::back_inserter( candidate_subgraphs ),
1074  [&] ( const CONNECTION_SUBGRAPH* candidate )
1075  { return ( !candidate->m_absorbed &&
1076  candidate->m_strong_driver &&
1077  candidate != subgraph );
1078  } );
1079 
1080  // This is a list of connections on the current subgraph to compare to the
1081  // drivers of each candidate subgraph. If the current subgraph is a bus,
1082  // we should consider each bus member.
1083  std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1084 
1085  // Also check the main driving connection
1086  connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1087 
1088  auto add_connections_to_check = [&] ( CONNECTION_SUBGRAPH* aSubgraph ) {
1089  for( SCH_ITEM* possible_driver : aSubgraph->m_items )
1090  {
1091  if( possible_driver == aSubgraph->m_driver )
1092  continue;
1093 
1094  switch( possible_driver->Type() )
1095  {
1096  case SCH_PIN_T:
1097  {
1098  auto sch_pin = static_cast<SCH_PIN*>( possible_driver );
1099 
1100  if( sch_pin->IsPowerConnection() )
1101  {
1102  auto pin = static_cast<SCH_PIN *>( possible_driver );
1103  auto c = std::make_shared<SCH_CONNECTION>( pin, aSubgraph->m_sheet );
1104  c->ConfigureFromLabel( pin->GetName() );
1105 
1106  if( c->Type() != aSubgraph->m_driver_connection->Type() )
1107  continue;
1108 
1109  if( c->Name( true ) == aSubgraph->m_driver_connection->Name( true ) )
1110  continue;
1111 
1112  connections_to_check.push_back( c );
1113  wxLogTrace( "CONN", "%lu (%s): Adding secondary pin %s",
1114  aSubgraph->m_code,
1115  aSubgraph->m_driver_connection->Name( true ),
1116  c->Name( true ) );
1117  }
1118  break;
1119  }
1120 
1121  case SCH_GLOBAL_LABEL_T:
1122  case SCH_HIER_LABEL_T:
1123  case SCH_LABEL_T:
1124  {
1125  auto text = static_cast<SCH_TEXT*>( possible_driver );
1126  auto c = std::make_shared<SCH_CONNECTION>( text, aSubgraph->m_sheet );
1127  c->ConfigureFromLabel( text->GetText() );
1128 
1129  if( c->Type() != aSubgraph->m_driver_connection->Type() )
1130  continue;
1131 
1132  if( c->Name( true ) == aSubgraph->m_driver_connection->Name( true ) )
1133  continue;
1134 
1135  connections_to_check.push_back( c );
1136  wxLogTrace( "CONN", "%lu (%s): Adding secondary label %s",
1137  aSubgraph->m_code,
1138  aSubgraph->m_driver_connection->Name( true ),
1139  c->Name( true ) );
1140  break;
1141  }
1142 
1143  default:
1144  break;
1145  }
1146  }
1147  };
1148 
1149  // Now add other strong drivers
1150  // The actual connection attached to these items will have been overwritten
1151  // by the chosen driver of the subgraph, so we need to create a dummy connection
1152  add_connections_to_check( subgraph );
1153 
1154  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1155  {
1156  auto member = connections_to_check[i];
1157 
1158  if( member->IsBus() )
1159  {
1160  connections_to_check.insert( connections_to_check.end(),
1161  member->Members().begin(),
1162  member->Members().end() );
1163  }
1164 
1165  wxString test_name = member->Name( true );
1166 
1167  for( auto candidate : candidate_subgraphs )
1168  {
1169  if( candidate->m_absorbed )
1170  continue;
1171 
1172  bool match = false;
1173 
1174  if( candidate->m_driver_connection->Name( true ) == test_name )
1175  {
1176  match = true;
1177  }
1178  else
1179  {
1180  if( !candidate->m_multiple_drivers )
1181  continue;
1182 
1183  for( SCH_ITEM *driver : candidate->m_drivers )
1184  {
1185  if( driver == candidate->m_driver )
1186  continue;
1187 
1188  // Sheet pins are not candidates for merging
1189  if( driver->Type() == SCH_SHEET_PIN_T )
1190  continue;
1191 
1192  if( driver->Type() == SCH_PIN_T )
1193  {
1194  auto pin = static_cast<SCH_PIN*>( driver );
1195 
1196  if( pin->IsPowerConnection() && pin->GetName() == test_name )
1197  {
1198  match = true;
1199  break;
1200  }
1201  }
1202  else
1203  {
1204  wxASSERT( driver->Type() == SCH_LABEL_T ||
1205  driver->Type() == SCH_GLOBAL_LABEL_T ||
1206  driver->Type() == SCH_HIER_LABEL_T );
1207 
1208  auto text = static_cast<SCH_TEXT*>( driver );
1209 
1210  if( text->GetShownText() == test_name )
1211  {
1212  match = true;
1213  break;
1214  }
1215  }
1216  }
1217  }
1218 
1219  if( match )
1220  {
1221  if( connection->IsBus() && candidate->m_driver_connection->IsNet() )
1222  {
1223  wxLogTrace( "CONN", "%lu (%s) has bus child %lu (%s)", subgraph->m_code,
1224  connection->Name(), candidate->m_code, member->Name() );
1225 
1226  subgraph->m_bus_neighbors[member].insert( candidate );
1227  candidate->m_bus_parents[member].insert( subgraph );
1228  }
1229  else
1230  {
1231  wxLogTrace( "CONN", "%lu (%s) absorbs neighbor %lu (%s)",
1232  subgraph->m_code, connection->Name(),
1233  candidate->m_code, candidate->m_driver_connection->Name() );
1234 
1235  // Candidate may have other non-chosen drivers we need to follow
1236  add_connections_to_check( candidate );
1237 
1238  subgraph->Absorb( candidate );
1239  invalidated_subgraphs.insert( subgraph );
1240  }
1241  }
1242  }
1243  }
1244  }
1245 
1246  // Update any subgraph that was invalidated above
1247  for( auto subgraph : invalidated_subgraphs )
1248  {
1249  if( subgraph->m_absorbed )
1250  continue;
1251 
1252  subgraph->ResolveDrivers();
1253 
1254  if( subgraph->m_driver_connection->IsBus() )
1256  else
1257  assignNewNetCode( *subgraph->m_driver_connection );
1258 
1259  subgraph->UpdateItemConnections();
1260 
1261  wxLogTrace( "CONN", "Re-resolving drivers for %lu (%s)", subgraph->m_code,
1262  subgraph->m_driver_connection->Name() );
1263  }
1264 
1265  // Absorbed subgraphs should no longer be considered
1266  m_driver_subgraphs.erase( std::remove_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1267  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool {
1268  return candidate->m_absorbed;
1269  } ), m_driver_subgraphs.end() );
1270 
1271  // Store global subgraphs for later reference
1272  std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1273  std::copy_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1274  std::back_inserter( global_subgraphs ),
1275  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool {
1276  return !candidate->m_local_driver;
1277  } );
1278 
1279  // Recache remaining valid subgraphs by sheet path
1280  m_sheet_to_subgraphs_map.clear();
1281  for( auto subgraph : m_driver_subgraphs )
1282  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1283 
1284  // Next time through the subgraphs, we do some post-processing to handle things like
1285  // connecting bus members to their neighboring subgraphs, and then propagate connections
1286  // through the hierarchy
1287 
1288  for( auto subgraph : m_driver_subgraphs )
1289  {
1290  if( !subgraph->m_dirty )
1291  continue;
1292 
1293  // For subgraphs that are driven by a global (power port or label) and have more
1294  // than one global driver, we need to seek out other subgraphs driven by the
1295  // same name as the non-chosen driver and update them to match the chosen one.
1296 
1297  if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1298  {
1299  for( SCH_ITEM* driver : subgraph->m_drivers )
1300  {
1301  if( driver == subgraph->m_driver )
1302  continue;
1303 
1304  wxString secondary_name = subgraph->GetNameForDriver( driver );
1305 
1306  if( secondary_name == subgraph->m_driver_connection->Name() )
1307  continue;
1308 
1309  for( CONNECTION_SUBGRAPH* candidate : global_subgraphs )
1310  {
1311  if( candidate == subgraph )
1312  continue;
1313 
1314  SCH_CONNECTION* conn = candidate->m_driver_connection;
1315 
1316  if( conn->Name() == secondary_name )
1317  {
1318  wxLogTrace( "CONN", "Global %lu (%s) promoted to %s", candidate->m_code,
1319  conn->Name(), subgraph->m_driver_connection->Name() );
1320 
1321  conn->Clone( *subgraph->m_driver_connection );
1322  candidate->UpdateItemConnections();
1323 
1324  candidate->m_dirty = false;
1325  }
1326  }
1327  }
1328  }
1329 
1330  // This call will handle descending the hierarchy and updating child subgraphs
1331  propagateToNeighbors( subgraph );
1332  }
1333 
1334  // Handle buses that have been linked together somewhere by member (net) connections.
1335  // This feels a bit hacky, perhaps this algorithm should be revisited in the future.
1336 
1337  // For net subgraphs that have more than one bus parent, we need to ensure that those
1338  // buses are linked together in the final netlist. The final name of each bus might not
1339  // match the local name that was used to establish the parent-child relationship, because
1340  // the bus may have been renamed by a hierarchical connection. So, for each of these cases,
1341  // we need to identify the appropriate bus members to link together (and their final names),
1342  // and then update all instances of the old name in the hierarchy.
1343 
1344  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1345  {
1346  if( subgraph->m_bus_parents.size() < 2 )
1347  continue;
1348 
1349  SCH_CONNECTION* conn = subgraph->m_driver_connection;
1350 
1351  wxLogTrace( "CONN", "%lu (%s) has multiple bus parents", subgraph->m_code, conn->Name() );
1352 
1353  wxASSERT( conn->IsNet() );
1354 
1355  for( const auto& it : subgraph->m_bus_parents )
1356  {
1357  SCH_CONNECTION* link_member = it.first.get();
1358 
1359  for( CONNECTION_SUBGRAPH* parent : it.second )
1360  {
1361  while( parent->m_absorbed )
1362  parent = parent->m_absorbed_by;
1363 
1364  SCH_CONNECTION* match = matchBusMember( parent->m_driver_connection, link_member );
1365 
1366  if( !match )
1367  {
1368  wxLogTrace( "CONN", "Warning: could not match %s inside %lu (%s)", conn->Name(),
1369  parent->m_code, parent->m_driver_connection->Name() );
1370  continue;
1371  }
1372 
1373  if( conn->Name() != match->Name() )
1374  {
1375  wxString old_name = match->Name();
1376 
1377  wxLogTrace( "CONN", "Updating %lu (%s) member %s to %s", parent->m_code,
1378  parent->m_driver_connection->Name(), old_name, conn->Name() );
1379 
1380  match->Clone( *conn );
1381 
1382  if( !m_net_name_to_subgraphs_map.count( old_name ) )
1383  continue;
1384 
1385  for( CONNECTION_SUBGRAPH* old_sg : m_net_name_to_subgraphs_map.at( old_name ) )
1386  {
1387  while( old_sg->m_absorbed )
1388  old_sg = old_sg->m_absorbed_by;
1389 
1390  old_sg->m_driver_connection->Clone( *conn );
1391  old_sg->UpdateItemConnections();
1392  }
1393  }
1394  }
1395  }
1396  }
1397 
1399 
1400  for( auto subgraph : m_driver_subgraphs )
1401  {
1402  // Every driven subgraph should have been marked by now
1403  if( subgraph->m_dirty )
1404  {
1405  // TODO(JE) this should be caught by hierarchical sheet port/pin ERC, check this
1406  // Reset to false so no complaints come up later
1407  subgraph->m_dirty = false;
1408  }
1409 
1410  if( subgraph->m_driver_connection->IsBus() )
1411  continue;
1412 
1413  auto key = std::make_pair( subgraph->GetNetName(),
1414  subgraph->m_driver_connection->NetCode() );
1415  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1416  }
1417 
1418  // Clean up and deallocate stale subgraphs
1419  m_subgraphs.erase( std::remove_if( m_subgraphs.begin(), m_subgraphs.end(),
1420  [&]( const CONNECTION_SUBGRAPH* sg ) {
1421  if( sg->m_absorbed )
1422  {
1423  delete sg;
1424  return true;
1425  }
1426  else
1427  {
1428  return false;
1429  }
1430  } ),
1431  m_subgraphs.end() );
1432 }
SCH_SHEET_PATH m_sheet
SCH_SHEET_LIST.
void SetBusCode(int aCode)
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:65
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
const wxString & GetName() const
Definition: sch_pin.h:101
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...
LIB_PART * GetParent() const
Definition: lib_item.h:176
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combines another subgraph on the same sheet into this one.
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 SetDriver(SCH_ITEM *aItem)
void SetName(const wxString &aName)
NET_MAP m_net_code_to_subgraphs_map
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.
bool ResolveDrivers(bool aCreateMarkers=false)
Determines which potential driver should drive the subgraph.
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
int NetCode() const
wxString Name(bool aIgnoreSheet=false) const
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
void SetSubgraphCode(int aCode)
SCH_EDIT_FRAME * m_frame
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
int SubgraphCode() const
void ConfigureFromLabel(wxString aLabel)
Configures the connection given a label.
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
SCH_SHEET_PATH.
void Clone(SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
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.
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet Note: the returned value can ...
Definition: sch_item.cpp:128
std::unordered_set< SCH_ITEM * > & ConnectedItems()
Retrieves the set of items connected to this item (schematic only)
Definition: sch_item.cpp:138
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
bool IsNet() const
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
bool IsPower() const
const char * name
Definition: DXF_plotter.cpp:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void SetSuffix(const wxString &aSuffix)
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
std::map< wxString, int > m_bus_name_to_code_map
std::unordered_set< SCH_ITEM * > m_items
bool IsPowerConnection() const
Definition: sch_pin.h:107
SCH_SHEET * g_RootSheet
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
SCH_CONNECTION * InitializeConnection(const SCH_SHEET_PATH &aPath)
Creates a new connection object associated with this object.
Definition: sch_item.cpp:150
not connected (must be left open)
bool IsBus() const
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:136
void SetNetCode(int aCode)
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
wxString GetNameForDriver(SCH_ITEM *aItem) const
Returns the candidate net name for a driver.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207
void UpdateItemConnections()
Updates all items to match the driver connection.

References CONNECTION_SUBGRAPH::AddItem(), assignNetCodesToBus(), assignNewNetCode(), SCH_CONNECTION::ClearDirty(), SCH_CONNECTION::Clone(), SCH_CONNECTION::ConfigureFromLabel(), SCH_ITEM::ConnectedItems(), SCH_ITEM::Connection(), Format(), g_RootSheet, SCH_PIN::GetLibPin(), SCH_PIN::GetName(), CONNECTION_SUBGRAPH::GetNetName(), LIB_ITEM::GetParent(), EDA_ITEM::GetSelectMenuText(), SCH_ITEM::InitializeConnection(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::IsNet(), LIB_PART::IsPower(), 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_driver_connection, m_driver_subgraphs, m_frame, m_global_label_cache, m_invisible_power_pins, 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_sheet, m_sheet_to_subgraphs_map, m_subgraphs, matchBusMember(), MILLIMETRES, name, SCH_CONNECTION::Name(), 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::SetDriver(), SCH_CONNECTION::SetName(), SCH_CONNECTION::SetNetCode(), SCH_CONNECTION::SetSubgraphCode(), SCH_CONNECTION::SetSuffix(), SCH_CONNECTION::SubgraphCode(), and EDA_ITEM::Type().

Referenced by Recalculate().

◆ ercCheckBusToBusConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusConflicts ( const CONNECTION_SUBGRAPH aSubgraph,
bool  aCreateMarkers 
)
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
aCreateMarkerscontrols whether error markers are created
Returns
true for no errors, false for errors

Definition at line 1937 of file connection_graph.cpp.

1939 {
1940  wxString msg;
1941  auto sheet = aSubgraph->m_sheet;
1942  auto screen = sheet.LastScreen();
1943 
1944  SCH_ITEM* label = nullptr;
1945  SCH_ITEM* port = nullptr;
1946 
1947  for( auto item : aSubgraph->m_items )
1948  {
1949  switch( item->Type() )
1950  {
1951  case SCH_TEXT_T:
1952  case SCH_GLOBAL_LABEL_T:
1953  {
1954  if( !label && item->Connection( sheet )->IsBus() )
1955  label = item;
1956  break;
1957  }
1958 
1959  case SCH_SHEET_PIN_T:
1960  case SCH_HIER_LABEL_T:
1961  {
1962  if( !port && item->Connection( sheet )->IsBus() )
1963  port = item;
1964  break;
1965  }
1966 
1967  default:
1968  break;
1969  }
1970  }
1971 
1972  if( label && port )
1973  {
1974  bool match = false;
1975 
1976  for( const auto& member : label->Connection( sheet )->Members() )
1977  {
1978  for( const auto& test : port->Connection( sheet )->Members() )
1979  {
1980  if( test != member && member->Name() == test->Name() )
1981  {
1982  match = true;
1983  break;
1984  }
1985  }
1986 
1987  if( match )
1988  break;
1989  }
1990 
1991  if( !match )
1992  {
1993  if( aCreateMarkers )
1994  {
1995  msg.Printf( _( "%s and %s are graphically connected but do "
1996  "not share any bus members" ),
1997  label->GetSelectMenuText( m_frame->GetUserUnits() ),
1998  port->GetSelectMenuText( m_frame->GetUserUnits() ) );
1999 
2000  auto marker = new SCH_MARKER();
2001  marker->SetTimeStamp( GetNewTimeStamp() );
2002  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2003  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
2004  marker->SetData( ERCE_BUS_TO_BUS_CONFLICT,
2005  label->GetPosition(), msg,
2006  port->GetPosition() );
2007 
2008  screen->Append( marker );
2009  }
2010 
2011  return false;
2012  }
2013  }
2014 
2015  return true;
2016 }
SCH_SHEET_PATH m_sheet
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
virtual wxPoint GetPosition() const =0
Function GetPosition.
std::vector< SCH_ITEM * > m_items
SCH_EDIT_FRAME * m_frame
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet Note: the returned value can ...
Definition: sch_item.cpp:128
SCH_SCREEN * LastScreen()
Function LastScreen.
#define _(s)
Definition: 3d_actions.cpp:31
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:136
EDA_UNITS GetUserUnits() const
Return the user units currently in use.

References _, SCH_ITEM::Connection(), ERCE_BUS_TO_BUS_CONFLICT, GetNewTimeStamp(), SCH_ITEM::GetPosition(), EDA_ITEM::GetSelectMenuText(), EDA_BASE_FRAME::GetUserUnits(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), m_frame, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, MARKER_BASE::MARKER_ERC, MARKER_BASE::MARKER_SEVERITY_ERROR, 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,
bool  aCreateMarkers 
)
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
aCreateMarkerscontrols whether error markers are created
Returns
true for no errors, false for errors

Definition at line 2019 of file connection_graph.cpp.

2021 {
2022  wxString msg;
2023  bool conflict = false;
2024  auto sheet = aSubgraph->m_sheet;
2025  auto screen = sheet.LastScreen();
2026 
2027  SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2028  SCH_ITEM* bus_wire = nullptr;
2029 
2030  for( auto item : aSubgraph->m_items )
2031  {
2032  switch( item->Type() )
2033  {
2034  case SCH_BUS_WIRE_ENTRY_T:
2035  {
2036  if( !bus_entry )
2037  bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2038  break;
2039  }
2040 
2041  default:
2042  break;
2043  }
2044  }
2045 
2046  if( bus_entry && bus_entry->m_connected_bus_item )
2047  {
2048  bus_wire = bus_entry->m_connected_bus_item;
2049 
2050  wxASSERT( bus_wire->Type() == SCH_LINE_T );
2051 
2052  // In some cases, the connection list (SCH_CONNECTION*) can be null.
2053  // Skip null connections.
2054  if( bus_entry->Connection( sheet ) && bus_wire->Type() == SCH_LINE_T
2055  && bus_wire->Connection( sheet ) )
2056  {
2057  conflict = true;
2058 
2059  auto test_name = bus_entry->Connection( sheet )->Name( true );
2060 
2061  for( const auto& member : bus_wire->Connection( sheet )->Members() )
2062  {
2063  if( member->Type() == CONNECTION_TYPE::BUS )
2064  {
2065  for( const auto& sub_member : member->Members() )
2066  if( sub_member->Name( true ) == test_name )
2067  conflict = false;
2068  }
2069  else if( member->Name( true ) == test_name )
2070  {
2071  conflict = false;
2072  }
2073  }
2074  }
2075  }
2076 
2077  // Don't report warnings if this bus member has been overridden by a higher priority power pin
2078  // or global label
2079  if( conflict
2082  conflict = false;
2083 
2084  if( conflict )
2085  {
2086  if( aCreateMarkers )
2087  {
2088  msg.Printf( _( "%s (%s) is connected to %s (%s) but is not a member of the bus" ),
2089  bus_entry->GetSelectMenuText( m_frame->GetUserUnits() ),
2090  bus_entry->Connection( sheet )->Name( true ),
2091  bus_wire->GetSelectMenuText( m_frame->GetUserUnits() ),
2092  bus_wire->Connection( sheet )->Name( true ) );
2093 
2094  auto marker = new SCH_MARKER();
2095  marker->SetTimeStamp( GetNewTimeStamp() );
2096  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2097  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2098  marker->SetData( ERCE_BUS_ENTRY_CONFLICT,
2099  bus_entry->GetPosition(), msg,
2100  bus_entry->GetPosition() );
2101 
2102  screen->Append( marker );
2103  }
2104 
2105  return false;
2106  }
2107 
2108  return true;
2109 }
SCH_SHEET_PATH m_sheet
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 PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Returns the priority (higher is more important) of a candidate driver.
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
SCH_EDIT_FRAME * m_frame
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet Note: the returned value can ...
Definition: sch_item.cpp:128
SCH_SCREEN * LastScreen()
Function LastScreen.
#define _(s)
Definition: 3d_actions.cpp:31
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:136
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
This item represents a bus vector.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207
wxPoint GetPosition() const override
Function GetPosition.

References _, BUS, SCH_ITEM::Connection(), ERCE_BUS_ENTRY_CONFLICT, CONNECTION_SUBGRAPH::GetDriverPriority(), GetNewTimeStamp(), SCH_BUS_ENTRY_BASE::GetPosition(), SCH_BUS_WIRE_ENTRY::GetSelectMenuText(), EDA_ITEM::GetSelectMenuText(), EDA_BASE_FRAME::GetUserUnits(), SCH_SHEET_PATH::LastScreen(), SCH_BUS_WIRE_ENTRY::m_connected_bus_item, CONNECTION_SUBGRAPH::m_driver, m_frame, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, MARKER_BASE::MARKER_ERC, MARKER_BASE::MARKER_SEVERITY_WARNING, SCH_CONNECTION::Members(), SCH_CONNECTION::Name(), CONNECTION_SUBGRAPH::POWER_PIN, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckBusToNetConflicts()

bool CONNECTION_GRAPH::ercCheckBusToNetConflicts ( const CONNECTION_SUBGRAPH aSubgraph,
bool  aCreateMarkers 
)
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
aCreateMarkerscontrols whether error markers are created
Returns
true for no errors, false for errors

Definition at line 1866 of file connection_graph.cpp.

1868 {
1869  wxString msg;
1870  auto sheet = aSubgraph->m_sheet;
1871  auto screen = sheet.LastScreen();
1872 
1873  SCH_ITEM* net_item = nullptr;
1874  SCH_ITEM* bus_item = nullptr;
1875  SCH_CONNECTION conn;
1876 
1877  for( auto item : aSubgraph->m_items )
1878  {
1879  switch( item->Type() )
1880  {
1881  case SCH_LINE_T:
1882  {
1883  if( item->GetLayer() == LAYER_BUS )
1884  bus_item = ( !bus_item ) ? item : bus_item;
1885  else
1886  net_item = ( !net_item ) ? item : net_item;
1887  break;
1888  }
1889 
1890  case SCH_GLOBAL_LABEL_T:
1891  case SCH_SHEET_PIN_T:
1892  case SCH_HIER_LABEL_T:
1893  {
1894  auto text = static_cast<SCH_TEXT*>( item )->GetShownText();
1895  conn.ConfigureFromLabel( text );
1896 
1897  if( conn.IsBus() )
1898  bus_item = ( !bus_item ) ? item : bus_item;
1899  else
1900  net_item = ( !net_item ) ? item : net_item;
1901  break;
1902  }
1903 
1904  default:
1905  break;
1906  }
1907  }
1908 
1909  if( net_item && bus_item )
1910  {
1911  if( aCreateMarkers )
1912  {
1913  msg.Printf( _( "%s and %s are graphically connected but cannot"
1914  " electrically connect because one is a bus and"
1915  " the other is a net." ),
1916  bus_item->GetSelectMenuText( m_frame->GetUserUnits() ),
1917  net_item->GetSelectMenuText( m_frame->GetUserUnits() ) );
1918 
1919  auto marker = new SCH_MARKER();
1920  marker->SetTimeStamp( GetNewTimeStamp() );
1921  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
1922  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
1923  marker->SetData( ERCE_BUS_TO_NET_CONFLICT,
1924  net_item->GetPosition(), msg,
1925  bus_item->GetPosition() );
1926 
1927  screen->Append( marker );
1928  }
1929 
1930  return false;
1931  }
1932 
1933  return true;
1934 }
SCH_SHEET_PATH m_sheet
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
virtual wxPoint GetPosition() const =0
Function GetPosition.
std::vector< SCH_ITEM * > m_items
SCH_EDIT_FRAME * m_frame
void ConfigureFromLabel(wxString aLabel)
Configures the connection given a label.
SCH_SCREEN * LastScreen()
Function LastScreen.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
#define _(s)
Definition: 3d_actions.cpp:31
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
bool IsBus() const
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:136
EDA_UNITS GetUserUnits() const
Return the user units currently in use.

References _, SCH_CONNECTION::ConfigureFromLabel(), ERCE_BUS_TO_NET_CONFLICT, GetNewTimeStamp(), SCH_ITEM::GetPosition(), EDA_ITEM::GetSelectMenuText(), EDA_BASE_FRAME::GetUserUnits(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, m_frame, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, MARKER_BASE::MARKER_ERC, MARKER_BASE::MARKER_SEVERITY_ERROR, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LINE_T, and SCH_SHEET_PIN_T.

Referenced by RunERC().

◆ ercCheckLabels()

bool CONNECTION_GRAPH::ercCheckLabels ( const CONNECTION_SUBGRAPH aSubgraph,
bool  aCreateMarkers,
bool  aCheckGlobalLabels 
)
private

Checks one subgraph for proper connection of labels.

Labels should be connected to something

Parameters
aSubgraphis the subgraph to examine
aCreateMarkerscontrols whether error markers are created
aCheckGlobalLabelsis true if global labels should be checked for loneliness
Returns
true for no errors, false for errors

Definition at line 2264 of file connection_graph.cpp.

2266 {
2267  // Label connection rules:
2268  // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2269  // Global labels are flagged if they appear only once, don't connect to any local labels,
2270  // and don't have a no-connect marker
2271 
2272  // So, if there is a no-connect, we will never generate a warning here
2273  if( aSubgraph->m_no_connect )
2274  return true;
2275 
2276  SCH_TEXT* text = nullptr;
2277  bool has_other_connections = false;
2278 
2279  for( auto item : aSubgraph->m_items )
2280  {
2281  switch( item->Type() )
2282  {
2283  case SCH_LABEL_T:
2284  case SCH_GLOBAL_LABEL_T:
2285  case SCH_HIER_LABEL_T:
2286  text = static_cast<SCH_TEXT*>( item );
2287  break;
2288 
2289  case SCH_PIN_T:
2290  case SCH_SHEET_PIN_T:
2291  has_other_connections = true;
2292  break;
2293 
2294  default:
2295  break;
2296  }
2297  }
2298 
2299  if( !text )
2300  return true;
2301 
2302  bool is_global = text->Type() == SCH_GLOBAL_LABEL_T;
2303 
2304  // Global label check can be disabled independently
2305  if( !aCheckGlobalLabels && is_global )
2306  return true;
2307 
2308  wxString name = text->GetShownText();
2309 
2310  if( is_global)
2311  {
2312  // This will be set to true if the global is connected to a pin above, but we
2313  // want to reset this to false so that globals get flagged if they only have a
2314  // single instance
2315  has_other_connections = false;
2316 
2317  if( m_net_name_to_subgraphs_map.count( name )
2318  && m_net_name_to_subgraphs_map.at( name ).size() > 1 )
2319  has_other_connections = true;
2320  }
2321  else if (text->Type() == SCH_HIER_LABEL_T)
2322  {
2323  // For a hier label, check if the parent pin is connected
2324  if (aSubgraph->m_hier_parent &&
2325  (aSubgraph->m_hier_parent->m_strong_driver ||
2326  aSubgraph->m_hier_parent->m_drivers.size() > 1))
2327  {
2328  // For now, a simple check: if there is more than one driver, the parent is probably
2329  // connected elsewhere (because at least one driver will be the hier pin itself)
2330  has_other_connections = true;
2331  }
2332  }
2333  else
2334  {
2335  auto pair = std::make_pair( aSubgraph->m_sheet, name );
2336 
2337  if( m_local_label_cache.count( pair ) && m_local_label_cache.at( pair ).size() > 1 )
2338  has_other_connections = true;
2339  }
2340 
2341  if( !has_other_connections )
2342  {
2343  if( aCreateMarkers )
2344  {
2345  SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2346  wxPoint pos = text->GetPosition();
2347  auto marker = new SCH_MARKER();
2348 
2349  wxString msg;
2350  wxString prefix = is_global ? _( "Global label" ) : _( "Label" );
2351  ERCE_T type = is_global ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
2352 
2353  msg.Printf( _( "%s %s is not connected anywhere else in the schematic." ),
2354  prefix, GetChars( text->ShortenedShownText() ) );
2355 
2356  marker->SetTimeStamp( GetNewTimeStamp() );
2357  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2358  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2359  marker->SetData( type, pos, msg, pos );
2360 
2361  screen->Append( marker );
2362  }
2363 
2364  return false;
2365  }
2366 
2367  return true;
2368 }
SCH_SHEET_PATH m_sheet
ERCE_T
DRC error codes:
Definition: erc.h:52
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
std::vector< SCH_ITEM * > m_items
wxString ShortenedShownText() const
Returns a shortened version (max 15 characters) of the shown text.
Definition: eda_text.cpp:163
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:315
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
SCH_SCREEN * LastScreen()
Function LastScreen.
const char * name
Definition: DXF_plotter.cpp:60
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:175
#define _(s)
Definition: 3d_actions.cpp:31
CONNECTION_SUBGRAPH * m_hier_parent
virtual wxString GetShownText() const
Return the string actually shown after processing of the base text.
Definition: eda_text.h:129
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
KICAD_T Type() const
Function Type()
Definition: base_struct.h:207

References _, SCH_SCREEN::Append(), ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, GetChars(), GetNewTimeStamp(), SCH_TEXT::GetPosition(), EDA_TEXT::GetShownText(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, CONNECTION_SUBGRAPH::m_sheet, CONNECTION_SUBGRAPH::m_strong_driver, MARKER_BASE::MARKER_ERC, MARKER_BASE::MARKER_SEVERITY_WARNING, name, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, EDA_TEXT::ShortenedShownText(), and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckNoConnects()

bool CONNECTION_GRAPH::ercCheckNoConnects ( const CONNECTION_SUBGRAPH aSubgraph,
bool  aCreateMarkers 
)
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
aCreateMarkerscontrols whether error markers are created
Returns
true for no errors, false for errors

Definition at line 2113 of file connection_graph.cpp.

2115 {
2116  wxString msg;
2117  auto sheet = aSubgraph->m_sheet;
2118  auto screen = sheet.LastScreen();
2119 
2120  if( aSubgraph->m_no_connect != nullptr )
2121  {
2122  bool has_invalid_items = false;
2123  bool has_other_items = false;
2124  SCH_PIN* pin = nullptr;
2125  std::vector<SCH_ITEM*> invalid_items;
2126 
2127  // Any subgraph that contains both a pin and a no-connect should not
2128  // contain any other driving items.
2129 
2130  for( auto item : aSubgraph->m_items )
2131  {
2132  switch( item->Type() )
2133  {
2134  case SCH_PIN_T:
2135  pin = static_cast<SCH_PIN*>( item );
2136  has_other_items = true;
2137  break;
2138 
2139  case SCH_LINE_T:
2140  case SCH_JUNCTION_T:
2141  case SCH_NO_CONNECT_T:
2142  break;
2143 
2144  default:
2145  has_invalid_items = true;
2146  has_other_items = true;
2147  invalid_items.push_back( item );
2148  }
2149  }
2150 
2151  if( pin && has_invalid_items )
2152  {
2153  if( aCreateMarkers )
2154  {
2155  wxPoint pos = pin->GetTransformedPosition();
2156 
2157  msg.Printf( _( "Pin %s of component %s has a no-connect marker but is connected" ),
2158  pin->GetName(),
2159  pin->GetParentComponent()->GetRef( &aSubgraph->m_sheet ) );
2160 
2161  auto marker = new SCH_MARKER();
2162  marker->SetTimeStamp( GetNewTimeStamp() );
2163  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2164  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2165  marker->SetData( ERCE_NOCONNECT_CONNECTED, pos, msg, pos );
2166 
2167  screen->Append( marker );
2168  }
2169 
2170  return false;
2171  }
2172 
2173  if( !has_other_items )
2174  {
2175  if( aCreateMarkers )
2176  {
2177  wxPoint pos = aSubgraph->m_no_connect->GetPosition();
2178 
2179  msg.Printf( _( "No-connect marker is not connected to anything" ) );
2180 
2181  auto marker = new SCH_MARKER();
2182  marker->SetTimeStamp( GetNewTimeStamp() );
2183  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2184  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2185  marker->SetData( ERCE_NOCONNECT_NOT_CONNECTED, pos, msg, pos );
2186 
2187  screen->Append( marker );
2188  }
2189 
2190  return false;
2191  }
2192  }
2193  else
2194  {
2195  bool has_other_connections = false;
2196  SCH_PIN* pin = nullptr;
2197 
2198  // Any subgraph that lacks a no-connect and contains a pin should also
2199  // contain at least one other connectable item.
2200 
2201  for( auto item : aSubgraph->m_items )
2202  {
2203  switch( item->Type() )
2204  {
2205  case SCH_PIN_T:
2206  if( !pin )
2207  pin = static_cast<SCH_PIN*>( item );
2208  else
2209  has_other_connections = true;
2210 
2211  break;
2212 
2213  default:
2214  if( item->IsConnectable() )
2215  has_other_connections = true;
2216 
2217  break;
2218  }
2219  }
2220 
2221  // Check if invisible power pins connect to anything else.
2222  // Note this won't catch a component with multiple invisible power pins but these don't
2223  // connect to any other net; maybe that should be added as a further optional ERC check?
2224 
2225  if( pin && !has_other_connections && pin->IsPowerConnection() && !pin->IsVisible() )
2226  {
2227  wxString name = pin->Connection( sheet )->Name();
2228  wxString local_name = pin->Connection( sheet )->Name( true );
2229 
2230  if( m_global_label_cache.count( name ) ||
2231  ( m_local_label_cache.count( std::make_pair( sheet, local_name ) ) ) )
2232  {
2233  has_other_connections = true;
2234  }
2235  }
2236 
2237  if( pin && !has_other_connections && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC )
2238  {
2239  if( aCreateMarkers )
2240  {
2241  wxPoint pos = pin->GetTransformedPosition();
2242 
2243  msg.Printf( _( "Pin %s of component %s is unconnected." ),
2244  pin->GetName(),
2245  pin->GetParentComponent()->GetRef( &aSubgraph->m_sheet ) );
2246 
2247  auto marker = new SCH_MARKER();
2248  marker->SetTimeStamp( GetNewTimeStamp() );
2249  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2250  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2251  marker->SetData( ERCE_PIN_NOT_CONNECTED, pos, msg, pos );
2252 
2253  screen->Append( marker );
2254  }
2255 
2256  return false;
2257  }
2258  }
2259 
2260  return true;
2261 }
SCH_SHEET_PATH m_sheet
const wxString & GetName() const
Definition: sch_pin.h:101
bool IsVisible() const
Definition: sch_pin.h:99
timestamp_t GetNewTimeStamp()
Definition: common.cpp:215
virtual wxPoint GetPosition() const =0
Function GetPosition.
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
const wxString GetRef(const SCH_SHEET_PATH *aSheet)
Return the reference for the given sheet path.
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet Note: the returned value can ...
Definition: sch_item.cpp:128
SCH_SCREEN * LastScreen()
Function LastScreen.
const char * name
Definition: DXF_plotter.cpp:60
#define _(s)
Definition: 3d_actions.cpp:31
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.h:105
bool IsPowerConnection() const
Definition: sch_pin.h:107
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)
SCH_COMPONENT * GetParentComponent() const
Definition: sch_pin.cpp:64
wxPoint GetTransformedPosition() const
Returns the pin's position in global coordinates.
Definition: sch_pin.cpp:116

References _, SCH_ITEM::Connection(), ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, SCH_PIN::GetName(), GetNewTimeStamp(), SCH_PIN::GetParentComponent(), SCH_ITEM::GetPosition(), SCH_COMPONENT::GetRef(), SCH_PIN::GetTransformedPosition(), SCH_PIN::GetType(), SCH_PIN::IsPowerConnection(), SCH_PIN::IsVisible(), SCH_SHEET_PATH::LastScreen(), m_global_label_cache, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_no_connect, CONNECTION_SUBGRAPH::m_sheet, MARKER_BASE::MARKER_ERC, MARKER_BASE::MARKER_SEVERITY_WARNING, name, SCH_CONNECTION::Name(), PT_NC, SCH_JUNCTION_T, SCH_LINE_T, SCH_NO_CONNECT_T, and SCH_PIN_T.

Referenced by RunERC().

◆ 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 1759 of file connection_graph.cpp.

1760 {
1761  if( m_bus_alias_cache.count( aName ) )
1762  return m_bus_alias_cache.at( aName );
1763 
1764  return nullptr;
1765 }
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 1768 of file connection_graph.cpp.

1769 {
1770  std::vector<const CONNECTION_SUBGRAPH*> ret;
1771 
1772  for( auto&& subgraph : m_subgraphs )
1773  {
1774  // Graph is supposed to be up-to-date before calling this
1775  wxASSERT( !subgraph->m_dirty );
1776 
1777  if( !subgraph->m_driver )
1778  continue;
1779 
1780  auto sheet = subgraph->m_sheet;
1781  auto connection = subgraph->m_driver->Connection( sheet );
1782 
1783  if( !connection->IsBus() )
1784  continue;
1785 
1786  auto labels = subgraph->GetBusLabels();
1787 
1788  if( labels.size() > 1 )
1789  {
1790  bool different = false;
1791  wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetText();
1792 
1793  for( unsigned i = 1; i < labels.size(); ++i )
1794  {
1795  if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetText() != first )
1796  {
1797  different = true;
1798  break;
1799  }
1800  }
1801 
1802  if( !different )
1803  continue;
1804 
1805  wxLogTrace( "CONN", "SG %ld (%s) has multiple bus labels", subgraph->m_code,
1806  connection->Name() );
1807 
1808  ret.push_back( subgraph );
1809  }
1810  }
1811 
1812  return ret;
1813 }
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
wxString GetText(GRAPHIC_PINSHAPE aShape)
Definition: pin_shape.cpp:58

References GetText(), and m_subgraphs.

Referenced by DIALOG_MIGRATE_BUSES::loadGraphData(), and SCH_EDIT_FRAME::OpenProjectFiles().

◆ GetNetMap()

const NET_MAP& CONNECTION_GRAPH::GetNetMap ( ) const
inline

Definition at line 263 of file connection_graph.h.

263 { return m_net_code_to_subgraphs_map; }
NET_MAP m_net_code_to_subgraphs_map

References m_net_code_to_subgraphs_map.

Referenced by NETLIST_EXPORTER_GENERIC::makeListOfNets().

◆ 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 1694 of file connection_graph.cpp.

1696 {
1697  wxASSERT( aBusConnection->IsBus() );
1698 
1699  SCH_CONNECTION* match = nullptr;
1700 
1701  if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
1702  {
1703  // Vector bus: compare against index, because we allow the name
1704  // to be different
1705 
1706  for( const auto& bus_member : aBusConnection->Members() )
1707  {
1708  if( bus_member->VectorIndex() == aSearch->VectorIndex() )
1709  {
1710  match = bus_member.get();
1711  break;
1712  }
1713  }
1714  }
1715  else
1716  {
1717  // Group bus
1718  for( const auto& c : aBusConnection->Members() )
1719  {
1720  // Vector inside group: compare names, because for bus groups
1721  // we expect the naming to be consistent across all usages
1722  // TODO(JE) explain this in the docs
1723  if( c->Type() == CONNECTION_TYPE::BUS )
1724  {
1725  for( const auto& bus_member : c->Members() )
1726  {
1727  if( bus_member->LocalName() == aSearch->RawName() )
1728  {
1729  match = bus_member.get();
1730  break;
1731  }
1732  }
1733  }
1734  else if( c->LocalName() == aSearch->RawName() )
1735  {
1736  match = c.get();
1737  break;
1738  }
1739  }
1740  }
1741 
1742  return match;
1743 }
wxString RawName() 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::Members(), SCH_CONNECTION::RawName(), 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 1476 of file connection_graph.cpp.

1477 {
1478  SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1479  std::vector<CONNECTION_SUBGRAPH*> search_list;
1480  std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1481 
1482  auto visit = [&] ( CONNECTION_SUBGRAPH* aParent ) {
1483  for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1484  {
1485  SCH_SHEET_PATH path = aParent->m_sheet;
1486  path.push_back( pin->GetParent() );
1487 
1488  if( !m_sheet_to_subgraphs_map.count( path ) )
1489  continue;
1490 
1491  for( auto candidate : m_sheet_to_subgraphs_map.at( path ) )
1492  {
1493  if( !candidate->m_strong_driver ||
1494  candidate->m_hier_ports.empty() ||
1495  visited.count( candidate ) )
1496  continue;
1497 
1498  for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1499  {
1500  if( label->GetShownText() == pin->GetShownText() )
1501  {
1502  wxLogTrace( "CONN", "%lu: found child %lu (%s)", aParent->m_code,
1503  candidate->m_code, candidate->m_driver_connection->Name() );
1504 
1505  candidate->m_hier_parent = aParent;
1506 
1507  search_list.push_back( candidate );
1508  break;
1509  }
1510  }
1511  }
1512  }
1513 
1514  for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1515  {
1516  SCH_SHEET_PATH path = aParent->m_sheet;
1517  path.pop_back();
1518 
1519  if( !m_sheet_to_subgraphs_map.count( path ) )
1520  continue;
1521 
1522  for( auto candidate : m_sheet_to_subgraphs_map.at( path ) )
1523  {
1524  if( candidate->m_hier_pins.empty() ||
1525  visited.count( candidate ) ||
1526  ( candidate->m_driver_connection->Type() !=
1527  aParent->m_driver_connection->Type() ) )
1528  continue;
1529 
1530  for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1531  {
1532  SCH_SHEET_PATH pin_path = path;
1533  pin_path.push_back( pin->GetParent() );
1534 
1535  if( pin_path != aParent->m_sheet )
1536  continue;
1537 
1538  if( label->GetShownText() == pin->GetShownText() )
1539  {
1540  wxLogTrace( "CONN", "%lu: found additional parent %lu (%s)",
1541  aParent->m_code, candidate->m_code,
1542  candidate->m_driver_connection->Name() );
1543 
1544  search_list.push_back( candidate );
1545  break;
1546  }
1547  }
1548  }
1549  }
1550  };
1551 
1552  auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1553  for( const auto& kv : aParentGraph->m_bus_neighbors )
1554  {
1555  for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1556  {
1557  // May have been absorbed but won't have been deleted
1558  while( neighbor->m_absorbed )
1559  neighbor = neighbor->m_absorbed_by;
1560 
1561  SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1562 
1563  // Now member may be out of date, since we just cloned the
1564  // connection from higher up in the hierarchy. We need to
1565  // figure out what the actual new connection is.
1566  SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1567 
1568  // This is bad, probably an ERC error
1569  if( !member )
1570  {
1571  wxLogTrace( "CONN", "Could not match bus member %s in %s",
1572  kv.first->Name(), parent->Name() );
1573  continue;
1574  }
1575 
1576  auto neighbor_conn = neighbor->m_driver_connection;
1577  auto neighbor_name = neighbor_conn->Name();
1578 
1579  // Matching name: no update needed
1580  if( neighbor_name == member->Name() )
1581  continue;
1582 
1583  wxLogTrace( "CONN", "%lu (%s) connected to bus member %s (local %s)",
1584  neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1585 
1586  // Take whichever name is higher priority
1589  {
1590  member->Clone( *neighbor_conn );
1591  }
1592  else
1593  {
1594  neighbor_conn->Clone( *member );
1595  neighbor->UpdateItemConnections();
1596 
1597  recacheSubgraphName( neighbor, neighbor_name );
1598 
1599  // Recurse onto this neighbor in case it needs to re-propagate
1600  neighbor->m_dirty = true;
1601  propagateToNeighbors( neighbor );
1602  }
1603  }
1604  }
1605  };
1606 
1607  // If we are a bus, we must propagate to local neighbors and then the hierarchy
1608  if( conn->IsBus() )
1609  propagate_bus_neighbors( aSubgraph );
1610 
1611  // If we don't have any hier pins (i.e. no children), nothing to do
1612  if( aSubgraph->m_hier_pins.empty() )
1613  {
1614  // If we also don't have any parents, we'll never be visited again
1615  if( aSubgraph->m_hier_ports.empty() )
1616  aSubgraph->m_dirty = false;
1617 
1618  return;
1619  }
1620 
1621  // If we do have hier ports, skip this subgraph as it will be visited by a parent
1622  // TODO(JE) this will leave the subgraph dirty if there is no matching parent subgraph,
1623  // which should be flagged as an ERC error
1624  if( !aSubgraph->m_hier_ports.empty() )
1625  return;
1626 
1627  visited.insert( aSubgraph );
1628 
1629  wxLogTrace( "CONN", "Propagating %lu (%s) to subsheets",
1630  aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1631 
1632  visit( aSubgraph );
1633 
1634  for( unsigned i = 0; i < search_list.size(); i++ )
1635  {
1636  auto child = search_list[i];
1637 
1638  visited.insert( child );
1639 
1640  visit( child );
1641 
1642  child->m_dirty = false;
1643  }
1644 
1645  // Now, find the best driver for this chain of subgraphs
1646  CONNECTION_SUBGRAPH* driver = aSubgraph;
1649 
1650  // Check if a subsheet has a higher-priority connection to the same net
1652  {
1653  for( CONNECTION_SUBGRAPH* subgraph : visited )
1654  {
1656  CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
1657 
1658  // Upgrade driver to be this subgraph if this subgraph has a power pin or global
1659  // Also upgrade if we found something with a shorter sheet path (higher in hierarchy)
1660  // but with an equivalent priority
1661 
1662  if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
1663  ( priority >= highest && subgraph->m_sheet.size() < aSubgraph->m_sheet.size() ) )
1664  driver = subgraph;
1665  }
1666  }
1667 
1668  if( driver != aSubgraph )
1669  {
1670  wxLogTrace( "CONN", "%lu (%s) overridden by new driver %lu (%s)",
1671  aSubgraph->m_code, aSubgraph->m_driver_connection->Name(),
1672  driver->m_code, driver->m_driver_connection->Name() );
1673  }
1674 
1675  conn = driver->m_driver_connection;
1676 
1677  for( CONNECTION_SUBGRAPH* subgraph : visited )
1678  {
1679  wxString old_name = subgraph->m_driver_connection->Name();
1680 
1681  subgraph->m_driver_connection->Clone( *conn );
1682  subgraph->UpdateItemConnections();
1683 
1684  recacheSubgraphName( subgraph, old_name );
1685 
1686  if( conn->IsBus() )
1687  propagate_bus_neighbors( subgraph );
1688  }
1689 
1690  aSubgraph->m_dirty = false;
1691 }
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.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
Definition: sch_sheet.h:158
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
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Returns the priority (higher is more important) of a candidate driver.
std::vector< SCH_SHEET_PIN * > m_hier_pins
wxString LocalName() const
#define kv
A subgraph is a set of items that are electrically connected on a single sheet.
void pop_back()
Forwarded method from std::vector.
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
wxString Name(bool aIgnoreSheet=false) const
size_t size() const
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:75
SCH_SHEET_PATH.
void Clone(SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
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).
virtual wxString GetShownText() const
Return the string actually shown after processing of the base text.
Definition: eda_text.h:129
bool IsBus() const
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
void UpdateItemConnections()
Updates all items to match the driver connection.

References SCH_CONNECTION::Clone(), CONNECTION_SUBGRAPH::GetDriverPriority(), SCH_SHEET_PIN::GetParent(), EDA_TEXT::GetShownText(), 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_hier_pins, CONNECTION_SUBGRAPH::m_hier_ports, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, matchBusMember(), SCH_CONNECTION::Name(), SCH_SHEET_PATH::pop_back(), CONNECTION_SUBGRAPH::POWER_PIN, SCH_SHEET_PATH::push_back(), recacheSubgraphName(), SCH_SHEET_PATH::size(), and CONNECTION_SUBGRAPH::UpdateItemConnections().

Referenced by buildConnectionGraph().

◆ recacheSubgraphName()

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

Definition at line 1746 of file connection_graph.cpp.

1748 {
1749  if( m_net_name_to_subgraphs_map.count( aOldName ) )
1750  {
1751  auto& vec = m_net_name_to_subgraphs_map.at( aOldName );
1752  vec.erase( std::remove( vec.begin(), vec.end(), aSubgraph ), vec.end() );
1753  }
1754 
1755  m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
1756 }
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
wxString Name(bool aIgnoreSheet=false) const

References 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 
)

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

Definition at line 380 of file connection_graph.cpp.

381 {
382  PROF_COUNTER recalc_time;
383  PROF_COUNTER update_items;
384 
385  if( aUnconditional )
386  Reset();
387 
388  for( const SCH_SHEET_PATH& sheet : aSheetList )
389  {
390  std::vector<SCH_ITEM*> items;
391 
392  for( auto item : sheet.LastScreen()->Items() )
393  {
394  if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
395  items.push_back( item );
396  }
397 
398  updateItemConnectivity( sheet, items );
399  }
400 
401  update_items.Stop();
402  wxLogTrace( "CONN_PROFILE", "UpdateItemConnectivity() %0.4f ms", update_items.msecs() );
403 
404  PROF_COUNTER tde;
405 
406  // IsDanglingStateChanged() also adds connected items for things like SCH_TEXT
407  SCH_SCREENS schematic;
408  schematic.TestDanglingEnds();
409 
410  tde.Stop();
411  wxLogTrace( "CONN_PROFILE", "TestDanglingEnds() %0.4f ms", tde.msecs() );
412 
413  PROF_COUNTER build_graph;
414 
416 
417  build_graph.Stop();
418  wxLogTrace( "CONN_PROFILE", "BuildConnectionGraph() %0.4f ms", build_graph.msecs() );
419 
420  recalc_time.Stop();
421  wxLogTrace( "CONN_PROFILE", "Recalculate time %0.4f ms", recalc_time.msecs() );
422 
423 #ifndef DEBUG
424  // Pressure relief valve for release builds
425  const double max_recalc_time_msecs = 250.;
426 
428  recalc_time.msecs() > max_recalc_time_msecs )
429  {
430  m_allowRealTime = false;
431  }
432 #endif
433 }
void Stop()
save the time when this function was called, and set the counter stane to stop
Definition: profile.h:82
void buildConnectionGraph()
Generates the connection graph (after all item connectivity has been updated)
double msecs(bool aSinceLast=false)
Definition: profile.h:143
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:44
SCH_SHEET_PATH.
static bool m_allowRealTime
bool m_realTimeConnectivity
Do real-time connectivity.
void TestDanglingEnds()
void updateItemConnectivity(SCH_SHEET_PATH aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers of advanced config.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:498

References buildConnectionGraph(), ADVANCED_CFG::GetCfg(), m_allowRealTime, ADVANCED_CFG::m_realTimeConnectivity, PROF_COUNTER::msecs(), Reset(), PROF_COUNTER::Stop(), SCH_SCREENS::TestDanglingEnds(), and updateItemConnectivity().

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

◆ Reset()

void CONNECTION_GRAPH::Reset ( )

Definition at line 357 of file connection_graph.cpp.

358 {
359  for( auto& subgraph : m_subgraphs )
360  delete subgraph;
361 
362  m_items.clear();
363  m_subgraphs.clear();
364  m_driver_subgraphs.clear();
365  m_sheet_to_subgraphs_map.clear();
366  m_invisible_power_pins.clear();
367  m_bus_alias_cache.clear();
368  m_net_name_to_code_map.clear();
369  m_bus_name_to_code_map.clear();
372  m_local_label_cache.clear();
373  m_global_label_cache.clear();
374  m_last_net_code = 1;
375  m_last_bus_code = 1;
377 }
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::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::unordered_set< SCH_ITEM * > m_items
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache

References m_bus_alias_cache, m_bus_name_to_code_map, m_driver_subgraphs, m_global_label_cache, m_invisible_power_pins, 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::CreateScreens(), SCH_EDIT_FRAME::OpenProjectFiles(), Recalculate(), SCH_EDIT_FRAME::rescueProject(), and ~CONNECTION_GRAPH().

◆ RunERC()

int CONNECTION_GRAPH::RunERC ( const ERC_SETTINGS aSettings,
bool  aCreateMarkers = true 
)

Runs electrical rule checks on the connectivity graph.

Precondition: graph is up-to-date

Parameters
aSettingsis used to control which tests to run
aCreateMarkerscontrols whether error markers are created
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 1816 of file connection_graph.cpp.

1817 {
1818  int error_count = 0;
1819 
1820  for( auto&& subgraph : m_subgraphs )
1821  {
1822  // Graph is supposed to be up-to-date before calling RunERC()
1823  wxASSERT( !subgraph->m_dirty );
1824 
1836  if( aSettings.check_bus_driver_conflicts &&
1837  !subgraph->ResolveDrivers( aCreateMarkers ) )
1838  error_count++;
1839 
1840  if( aSettings.check_bus_to_net_conflicts &&
1841  !ercCheckBusToNetConflicts( subgraph, aCreateMarkers ) )
1842  error_count++;
1843 
1844  if( aSettings.check_bus_entry_conflicts &&
1845  !ercCheckBusToBusEntryConflicts( subgraph, aCreateMarkers ) )
1846  error_count++;
1847 
1848  if( aSettings.check_bus_to_bus_conflicts &&
1849  !ercCheckBusToBusConflicts( subgraph, aCreateMarkers ) )
1850  error_count++;
1851 
1852  // The following checks are always performed since they don't currently
1853  // have an option exposed to the user
1854 
1855  if( !ercCheckNoConnects( subgraph, aCreateMarkers ) )
1856  error_count++;
1857 
1858  if( !ercCheckLabels( subgraph, aCreateMarkers, aSettings.check_unique_global_labels ) )
1859  error_count++;
1860  }
1861 
1862  return error_count;
1863 }
bool check_unique_global_labels
If true, check to ensure that each global label apperas more than once.
Definition: erc_settings.h:67
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers, bool aCheckGlobalLabels)
Checks one subgraph for proper connection of labels.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
bool check_bus_to_bus_conflicts
If true, check that bus-to-bus connections share at least one member.
Definition: erc_settings.h:76
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
Checks one subgraph for proper presence or absence of no-connect symbols.
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
Checks one subgraph for conflicting connections between two bus items.
bool check_bus_to_net_conflicts
If true, check that bus wires don't graphically connect to net objects (or vice versa)
Definition: erc_settings.h:79
bool check_bus_driver_conflicts
If true, check that buses don't have conflicting drivers.
Definition: erc_settings.h:70
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
Checks one subgraph for conflicting connections between net and bus labels.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph, bool aCreateMarkers)
Checks one subgraph for conflicting bus entry to bus connections.
bool check_bus_entry_conflicts
If true, check that wires connecting to buses actually exist in the bus.
Definition: erc_settings.h:73

References ERC_SETTINGS::check_bus_driver_conflicts, ERC_SETTINGS::check_bus_entry_conflicts, ERC_SETTINGS::check_bus_to_bus_conflicts, ERC_SETTINGS::check_bus_to_net_conflicts, ERC_SETTINGS::check_unique_global_labels, ercCheckBusToBusConflicts(), ercCheckBusToBusEntryConflicts(), ercCheckBusToNetConflicts(), ercCheckLabels(), ercCheckNoConnects(), and m_subgraphs.

Referenced by DIALOG_ERC::TestErc().

◆ updateItemConnectivity()

void CONNECTION_GRAPH::updateItemConnectivity ( 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 436 of file connection_graph.cpp.

438 {
439  std::unordered_map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
440 
441  for( auto item : aItemList )
442  {
443  std::vector< wxPoint > points;
444  item->GetConnectionPoints( points );
445  item->ConnectedItems().clear();
446 
447  if( item->Type() == SCH_SHEET_T )
448  {
449  for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
450  {
451  if( !pin->Connection( aSheet ) )
452  {
453  pin->InitializeConnection( aSheet );
454  }
455 
456  pin->ConnectedItems().clear();
457  pin->Connection( aSheet )->Reset();
458 
459  connection_map[ pin->GetTextPos() ].push_back( pin );
460  m_items.insert( pin );
461  }
462  }
463  else if( item->Type() == SCH_COMPONENT_T )
464  {
465  SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
466  TRANSFORM t = component->GetTransform();
467 
468  // Assumption: we don't need to call UpdatePins() here because anything
469  // that would change the pins of the component will have called it already
470 
471  for( SCH_PIN& pin : component->GetPins() )
472  {
473  pin.InitializeConnection( aSheet );
474 
475  wxPoint pos = t.TransformCoordinate( pin.GetPosition() ) + component->GetPosition();
476 
477  // because calling the first time is not thread-safe
478  pin.GetDefaultNetName( aSheet );
479  pin.ConnectedItems().clear();
480 
481  // Invisible power pins need to be post-processed later
482 
483  if( pin.IsPowerConnection() && !pin.IsVisible() )
484  m_invisible_power_pins.emplace_back( std::make_pair( aSheet, &pin ) );
485 
486  connection_map[ pos ].push_back( &pin );
487  m_items.insert( &pin );
488  }
489  }
490  else
491  {
492  m_items.insert( item );
493  auto conn = item->InitializeConnection( aSheet );
494 
495  // Set bus/net property here so that the propagation code uses it
496  switch( item->Type() )
497  {
498  case SCH_LINE_T:
499  conn->SetType( item->GetLayer() == LAYER_BUS ? CONNECTION_TYPE::BUS :
501  break;
502 
503  case SCH_BUS_BUS_ENTRY_T:
504  conn->SetType( CONNECTION_TYPE::BUS );
505  // clean previous (old) links:
506  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] = nullptr;
507  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] = nullptr;
508  break;
509 
510  case SCH_PIN_T:
511  conn->SetType( CONNECTION_TYPE::NET );
512  break;
513 
515  conn->SetType( CONNECTION_TYPE::NET );
516  // clean previous (old) link:
517  static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item = nullptr;
518  break;
519 
520  default:
521  break;
522  }
523 
524  for( auto point : points )
525  {
526  connection_map[ point ].push_back( item );
527  }
528  }
529 
530  item->SetConnectivityDirty( false );
531  }
532 
533  for( const auto& it : connection_map )
534  {
535  auto connection_vec = it.second;
536 
537  for( auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ )
538  {
539  auto connected_item = *primary_it;
540 
541  // Bus entries are special: they can have connection points in the
542  // middle of a wire segment, because the junction algo doesn't split
543  // the segment in two where you place a bus entry. This means that
544  // bus entries that don't land on the end of a line segment need to
545  // have "virtual" connection points to the segments they graphically
546  // touch.
547  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
548  {
549  // If this location only has the connection point of the bus
550  // entry itself, this means that either the bus entry is not
551  // connected to anything graphically, or that it is connected to
552  // a segment at some point other than at one of the endpoints.
553  if( connection_vec.size() == 1 )
554  {
555  auto screen = aSheet.LastScreen();
556  auto bus = screen->GetBus( it.first );
557 
558  if( bus )
559  {
560  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
561  bus_entry->m_connected_bus_item = bus;
562  }
563  }
564  }
565 
566  // Bus-to-bus entries are treated just like bus wires
567  if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
568  {
569  if( connection_vec.size() < 2 )
570  {
571  auto screen = aSheet.LastScreen();
572  auto bus = screen->GetBus( it.first );
573 
574  if( bus )
575  {
576  auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
577 
578  if( it.first == bus_entry->GetPosition() )
579  bus_entry->m_connected_bus_items[0] = bus;
580  else
581  bus_entry->m_connected_bus_items[1] = bus;
582 
583  bus_entry->ConnectedItems().insert( bus );
584  bus->ConnectedItems().insert( bus_entry );
585  }
586  }
587  }
588 
589  for( auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ )
590  {
591  auto test_item = *test_it;
592 
593  if( connected_item != test_item &&
594  connected_item->ConnectionPropagatesTo( test_item ) &&
595  test_item->ConnectionPropagatesTo( connected_item ) )
596  {
597  connected_item->ConnectedItems().insert( test_item );
598  test_item->ConnectedItems().insert( connected_item );
599  }
600 
601  // Set up the link between the bus entry net and the bus
602  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
603  {
604  if( test_item->Connection( aSheet )->IsBus() )
605  {
606  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
607  bus_entry->m_connected_bus_item = test_item;
608  }
609  }
610  }
611 
612  // If we got this far and did not find a connected bus item for a bus entry,
613  // we should do a manual scan in case there is a bus item on this connection
614  // point but we didn't pick it up earlier because there is *also* a net item here.
615  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
616  {
617  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
618 
619  if( !bus_entry->m_connected_bus_item )
620  {
621  auto screen = aSheet.LastScreen();
622  auto bus = screen->GetBus( it.first );
623 
624  if( bus )
625  bus_entry->m_connected_bus_item = bus;
626  }
627  }
628  }
629  }
630 }
wxPoint TransformCoordinate(const wxPoint &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:42
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
TRANSFORM & GetTransform() const
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:75
This item represents a net.
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
void GetPins(std::vector< LIB_PIN * > &aPinsList)
Populate a vector with all the pins from the library object.
SCH_SCREEN * LastScreen()
Function LastScreen.
SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:89
wxPoint GetPosition() const override
Function GetPosition.
std::unordered_set< SCH_ITEM * > m_items
This item represents a bus vector.
SCH_LINE * GetBus(const wxPoint &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T)
Definition: sch_screen.h:426

References BUS, SCH_SCREEN::GetBus(), SCH_COMPONENT::GetPins(), SCH_COMPONENT::GetPosition(), SCH_COMPONENT::GetTransform(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, m_invisible_power_pins, m_items, NET, SCH_BUS_BUS_ENTRY_T, SCH_BUS_WIRE_ENTRY_T, SCH_COMPONENT_T, SCH_LINE_T, SCH_PIN_T, SCH_SHEET_T, and TRANSFORM::TransformCoordinate().

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 284 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 288 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 276 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_frame

◆ m_global_label_cache

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

Definition at line 290 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 282 of file connection_graph.h.

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

◆ m_item_mutex

std::mutex CONNECTION_GRAPH::m_item_mutex
private

Definition at line 306 of file connection_graph.h.

◆ m_items

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

Definition at line 270 of file connection_graph.h.

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

◆ m_last_bus_code

int CONNECTION_GRAPH::m_last_bus_code
private

Definition at line 302 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 300 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 304 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 298 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 286 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_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 280 of file connection_graph.h.

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

◆ m_subgraphs

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

Definition at line 273 of file connection_graph.h.

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


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