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)
 
void Reset ()
 
void Recalculate (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...
 

Public Attributes

std::map< int, std::vector< CONNECTION_SUBGRAPH * > > m_net_code_to_subgraphs_map
 

Static Public Attributes

static bool m_allowRealTime = true
 

Private Member Functions

void updateItemConnectivity (SCH_SHEET_PATH aSheet, 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
 
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 197 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCH_EDIT_FRAME aFrame)
inline

Definition at line 200 of file connection_graph.h.

200  :
201  m_frame( aFrame )
202  {}
SCH_EDIT_FRAME * m_frame

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

1435 {
1436  auto connections_to_check( aConnection->Members() );
1437 
1438  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1439  {
1440  auto member = connections_to_check[i];
1441 
1442  if( member->IsBus() )
1443  {
1444  connections_to_check.insert( connections_to_check.end(),
1445  member->Members().begin(),
1446  member->Members().end() );
1447  continue;
1448  }
1449 
1450  assignNewNetCode( *member );
1451  }
1452 }
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
size_t i
Definition: json11.cpp:649
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()

References assignNewNetCode(), i, 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 1414 of file connection_graph.cpp.

1415 {
1416  int code;
1417 
1418  if( m_net_name_to_code_map.count( aConnection.Name() ) )
1419  {
1420  code = m_net_name_to_code_map.at( aConnection.Name() );
1421  }
1422  else
1423  {
1424  code = m_last_net_code++;
1425  m_net_name_to_code_map[ aConnection.Name() ] = code;
1426  }
1427 
1428  aConnection.SetNetCode( code );
1429 
1430  return code;
1431 }
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 638 of file connection_graph.cpp.

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

1906 {
1907  wxString msg;
1908  auto sheet = aSubgraph->m_sheet;
1909  auto screen = sheet.LastScreen();
1910 
1911  SCH_ITEM* label = nullptr;
1912  SCH_ITEM* port = nullptr;
1913 
1914  for( auto item : aSubgraph->m_items )
1915  {
1916  switch( item->Type() )
1917  {
1918  case SCH_TEXT_T:
1919  case SCH_GLOBAL_LABEL_T:
1920  {
1921  if( !label && item->Connection( sheet )->IsBus() )
1922  label = item;
1923  break;
1924  }
1925 
1926  case SCH_SHEET_PIN_T:
1927  case SCH_HIER_LABEL_T:
1928  {
1929  if( !port && item->Connection( sheet )->IsBus() )
1930  port = item;
1931  break;
1932  }
1933 
1934  default:
1935  break;
1936  }
1937  }
1938 
1939  if( label && port )
1940  {
1941  bool match = false;
1942 
1943  for( const auto& member : label->Connection( sheet )->Members() )
1944  {
1945  for( const auto& test : port->Connection( sheet )->Members() )
1946  {
1947  if( test != member && member->Name() == test->Name() )
1948  {
1949  match = true;
1950  break;
1951  }
1952  }
1953 
1954  if( match )
1955  break;
1956  }
1957 
1958  if( !match )
1959  {
1960  if( aCreateMarkers )
1961  {
1962  msg.Printf( _( "%s and %s are graphically connected but do "
1963  "not share any bus members" ),
1964  label->GetSelectMenuText( m_frame->GetUserUnits() ),
1965  port->GetSelectMenuText( m_frame->GetUserUnits() ) );
1966 
1967  auto marker = new SCH_MARKER();
1968  marker->SetTimeStamp( GetNewTimeStamp() );
1969  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
1970  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
1971  marker->SetData( ERCE_BUS_TO_BUS_CONFLICT,
1972  label->GetPosition(), msg,
1973  port->GetPosition() );
1974 
1975  screen->Append( marker );
1976  }
1977 
1978  return false;
1979  }
1980  }
1981 
1982  return true;
1983 }
SCH_SHEET_PATH m_sheet
timestamp_t GetNewTimeStamp()
Definition: common.cpp:217
virtual wxPoint GetPosition() const =0
Function GetPosition.
std::vector< SCH_ITEM * > m_items
SCH_EDIT_FRAME * m_frame
#define _(s)
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet.
Definition: sch_item.cpp:128
EDA_UNITS_T GetUserUnits() const
Return the user units currently in use.
virtual wxString GetSelectMenuText(EDA_UNITS_T 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 SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Definition: sch_item.h:114
SCH_SCREEN * LastScreen() const
Function LastScreen.

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

1988 {
1989  wxString msg;
1990  bool conflict = false;
1991  auto sheet = aSubgraph->m_sheet;
1992  auto screen = sheet.LastScreen();
1993 
1994  SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
1995  SCH_ITEM* bus_wire = nullptr;
1996 
1997  for( auto item : aSubgraph->m_items )
1998  {
1999  switch( item->Type() )
2000  {
2001  case SCH_BUS_WIRE_ENTRY_T:
2002  {
2003  if( !bus_entry )
2004  bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2005  break;
2006  }
2007 
2008  default:
2009  break;
2010  }
2011  }
2012 
2013  if( bus_entry && bus_entry->m_connected_bus_item )
2014  {
2015  bus_wire = bus_entry->m_connected_bus_item;
2016  conflict = true;
2017 
2018  auto test_name = bus_entry->Connection( sheet )->Name( true );
2019 
2020  for( const auto& member : bus_wire->Connection( sheet )->Members() )
2021  {
2022  if( member->Type() == CONNECTION_BUS )
2023  {
2024  for( const auto& sub_member : member->Members() )
2025  if( sub_member->Name( true ) == test_name )
2026  conflict = false;
2027  }
2028  else if( member->Name( true ) == test_name )
2029  {
2030  conflict = false;
2031  }
2032  }
2033  }
2034 
2035  if( conflict )
2036  {
2037  if( aCreateMarkers )
2038  {
2039  msg.Printf( _( "%s (%s) is connected to %s (%s) but is not a member of the bus" ),
2040  bus_entry->GetSelectMenuText( m_frame->GetUserUnits() ),
2041  bus_entry->Connection( sheet )->Name( true ),
2042  bus_wire->GetSelectMenuText( m_frame->GetUserUnits() ),
2043  bus_wire->Connection( sheet )->Name( true ) );
2044 
2045  auto marker = new SCH_MARKER();
2046  marker->SetTimeStamp( GetNewTimeStamp() );
2047  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2048  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2049  marker->SetData( ERCE_BUS_ENTRY_CONFLICT,
2050  bus_entry->GetPosition(), msg,
2051  bus_entry->GetPosition() );
2052 
2053  screen->Append( marker );
2054  }
2055 
2056  return false;
2057  }
2058 
2059  return true;
2060 }
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 ...
timestamp_t GetNewTimeStamp()
Definition: common.cpp:217
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
SCH_EDIT_FRAME * m_frame
#define _(s)
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet.
Definition: sch_item.cpp:128
EDA_UNITS_T GetUserUnits() const
Return the user units currently in use.
virtual wxString GetSelectMenuText(EDA_UNITS_T aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
wxString GetSelectMenuText(EDA_UNITS_T aUnits) const override
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.
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Definition: sch_item.h:114
SCH_SCREEN * LastScreen() const
Function LastScreen.
This item represents a bus vector.
wxPoint GetPosition() const override
Function GetPosition.

References _, SCH_ITEM::Connection(), CONNECTION_BUS, ERCE_BUS_ENTRY_CONFLICT, 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, 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(), and SCH_BUS_WIRE_ENTRY_T.

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

1835 {
1836  wxString msg;
1837  auto sheet = aSubgraph->m_sheet;
1838  auto screen = sheet.LastScreen();
1839 
1840  SCH_ITEM* net_item = nullptr;
1841  SCH_ITEM* bus_item = nullptr;
1842  SCH_CONNECTION conn;
1843 
1844  for( auto item : aSubgraph->m_items )
1845  {
1846  switch( item->Type() )
1847  {
1848  case SCH_LINE_T:
1849  {
1850  if( item->GetLayer() == LAYER_BUS )
1851  bus_item = ( !bus_item ) ? item : bus_item;
1852  else
1853  net_item = ( !net_item ) ? item : net_item;
1854  break;
1855  }
1856 
1857  case SCH_GLOBAL_LABEL_T:
1858  case SCH_SHEET_PIN_T:
1859  case SCH_HIER_LABEL_T:
1860  {
1861  auto text = static_cast<SCH_TEXT*>( item )->GetShownText();
1862  conn.ConfigureFromLabel( text );
1863 
1864  if( conn.IsBus() )
1865  bus_item = ( !bus_item ) ? item : bus_item;
1866  else
1867  net_item = ( !net_item ) ? item : net_item;
1868  break;
1869  }
1870 
1871  default:
1872  break;
1873  }
1874  }
1875 
1876  if( net_item && bus_item )
1877  {
1878  if( aCreateMarkers )
1879  {
1880  msg.Printf( _( "%s and %s are graphically connected but cannot"
1881  " electrically connect because one is a bus and"
1882  " the other is a net." ),
1883  bus_item->GetSelectMenuText( m_frame->GetUserUnits() ),
1884  net_item->GetSelectMenuText( m_frame->GetUserUnits() ) );
1885 
1886  auto marker = new SCH_MARKER();
1887  marker->SetTimeStamp( GetNewTimeStamp() );
1888  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
1889  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
1890  marker->SetData( ERCE_BUS_TO_NET_CONFLICT,
1891  net_item->GetPosition(), msg,
1892  bus_item->GetPosition() );
1893 
1894  screen->Append( marker );
1895  }
1896 
1897  return false;
1898  }
1899 
1900  return true;
1901 }
SCH_SHEET_PATH m_sheet
timestamp_t GetNewTimeStamp()
Definition: common.cpp:217
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.
#define _(s)
EDA_UNITS_T GetUserUnits() const
Return the user units currently in use.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
virtual wxString GetSelectMenuText(EDA_UNITS_T aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
bool IsBus() const
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Definition: sch_item.h:114
SCH_SCREEN * LastScreen() const
Function LastScreen.

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

2217 {
2218  // Label connection rules:
2219  // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2220  // Global labels are flagged if they appear only once, don't connect to any local labels,
2221  // and don't have a no-connect marker
2222 
2223  // So, if there is a no-connect, we will never generate a warning here
2224  if( aSubgraph->m_no_connect )
2225  return true;
2226 
2227  SCH_TEXT* text = nullptr;
2228  bool has_other_connections = false;
2229 
2230  for( auto item : aSubgraph->m_items )
2231  {
2232  switch( item->Type() )
2233  {
2234  case SCH_LABEL_T:
2235  case SCH_GLOBAL_LABEL_T:
2236  case SCH_HIER_LABEL_T:
2237  text = static_cast<SCH_TEXT*>( item );
2238  break;
2239 
2240  case SCH_PIN_T:
2241  case SCH_SHEET_PIN_T:
2242  has_other_connections = true;
2243  break;
2244 
2245  default:
2246  break;
2247  }
2248  }
2249 
2250  if( !text )
2251  return true;
2252 
2253  bool is_global = text->Type() == SCH_GLOBAL_LABEL_T;
2254 
2255  // Global label check can be disabled independently
2256  if( !aCheckGlobalLabels && is_global )
2257  return true;
2258 
2259  wxString name = text->GetShownText();
2260 
2261  if( is_global)
2262  {
2263  // This will be set to true if the global is connected to a pin above, but we
2264  // want to reset this to false so that globals get flagged if they only have a
2265  // single instance
2266  has_other_connections = false;
2267 
2268  if( m_net_name_to_subgraphs_map.count( name )
2269  && m_net_name_to_subgraphs_map.at( name ).size() > 1 )
2270  has_other_connections = true;
2271  }
2272  else
2273  {
2274  auto pair = std::make_pair( aSubgraph->m_sheet, name );
2275 
2276  if( m_local_label_cache.count( pair ) && m_local_label_cache.at( pair ).size() > 1 )
2277  has_other_connections = true;
2278  }
2279 
2280  if( !has_other_connections )
2281  {
2282  if( aCreateMarkers )
2283  {
2284  SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2285  wxPoint pos = text->GetPosition();
2286  auto marker = new SCH_MARKER();
2287 
2288  wxString msg;
2289  wxString prefix = is_global ? _( "Global label" ) : _( "Label" );
2290  ERCE_T type = is_global ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
2291 
2292  msg.Printf( _( "%s %s is not connected anywhere else in the schematic." ),
2293  prefix, GetChars( text->ShortenedShownText() ) );
2294 
2295  marker->SetTimeStamp( GetNewTimeStamp() );
2296  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2297  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2298  marker->SetData( type, pos, msg, pos );
2299 
2300  screen->Append( marker );
2301  }
2302 
2303  return false;
2304  }
2305 
2306  return true;
2307 }
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:217
std::vector< SCH_ITEM * > m_items
wxString ShortenedShownText() const
Returns a shortened version (max 15 characters) of the shown text.
Definition: eda_text.cpp:178
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:198
#define _(s)
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
const char * name
Definition: DXF_plotter.cpp:61
void Append(SCH_ITEM *aItem)
Definition: sch_screen.h:154
virtual wxString GetShownText() const
Returns 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
SCH_SCREEN * LastScreen() const
Function LastScreen.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210

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_items, m_local_label_cache, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, CONNECTION_SUBGRAPH::m_sheet, 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 2064 of file connection_graph.cpp.

2066 {
2067  wxString msg;
2068  auto sheet = aSubgraph->m_sheet;
2069  auto screen = sheet.LastScreen();
2070 
2071  if( aSubgraph->m_no_connect != nullptr )
2072  {
2073  bool has_invalid_items = false;
2074  bool has_other_items = false;
2075  SCH_PIN* pin = nullptr;
2076  std::vector<SCH_ITEM*> invalid_items;
2077 
2078  // Any subgraph that contains both a pin and a no-connect should not
2079  // contain any other driving items.
2080 
2081  for( auto item : aSubgraph->m_items )
2082  {
2083  switch( item->Type() )
2084  {
2085  case SCH_PIN_T:
2086  pin = static_cast<SCH_PIN*>( item );
2087  has_other_items = true;
2088  break;
2089 
2090  case SCH_LINE_T:
2091  case SCH_JUNCTION_T:
2092  case SCH_NO_CONNECT_T:
2093  break;
2094 
2095  default:
2096  has_invalid_items = true;
2097  has_other_items = true;
2098  invalid_items.push_back( item );
2099  }
2100  }
2101 
2102  if( pin && has_invalid_items )
2103  {
2104  if( aCreateMarkers )
2105  {
2106  wxPoint pos = pin->GetTransformedPosition();
2107 
2108  msg.Printf( _( "Pin %s of component %s has a no-connect marker but is connected" ),
2109  pin->GetName(),
2110  pin->GetParentComponent()->GetRef( &aSubgraph->m_sheet ) );
2111 
2112  auto marker = new SCH_MARKER();
2113  marker->SetTimeStamp( GetNewTimeStamp() );
2114  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2115  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2116  marker->SetData( ERCE_NOCONNECT_CONNECTED, pos, msg, pos );
2117 
2118  screen->Append( marker );
2119  }
2120 
2121  return false;
2122  }
2123 
2124  if( !has_other_items )
2125  {
2126  if( aCreateMarkers )
2127  {
2128  wxPoint pos = aSubgraph->m_no_connect->GetPosition();
2129 
2130  msg.Printf( _( "No-connect marker is not connected to anything" ) );
2131 
2132  auto marker = new SCH_MARKER();
2133  marker->SetTimeStamp( GetNewTimeStamp() );
2134  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2135  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2136  marker->SetData( ERCE_NOCONNECT_NOT_CONNECTED, pos, msg, pos );
2137 
2138  screen->Append( marker );
2139  }
2140 
2141  return false;
2142  }
2143  }
2144  else
2145  {
2146  bool has_other_connections = false;
2147  SCH_PIN* pin = nullptr;
2148 
2149  // Any subgraph that lacks a no-connect and contains a pin should also
2150  // contain at least one other connectable item.
2151 
2152  for( auto item : aSubgraph->m_items )
2153  {
2154  switch( item->Type() )
2155  {
2156  case SCH_PIN_T:
2157  if( !pin )
2158  pin = static_cast<SCH_PIN*>( item );
2159  else
2160  has_other_connections = true;
2161 
2162  break;
2163 
2164  default:
2165  if( item->IsConnectable() )
2166  has_other_connections = true;
2167 
2168  break;
2169  }
2170  }
2171 
2172  // Check if invisible power pins connect to anything else.
2173  // Note this won't catch a component with multiple invisible power pins but these don't
2174  // connect to any other net; maybe that should be added as a further optional ERC check?
2175 
2176  if( pin && !has_other_connections && pin->IsPowerConnection() && !pin->IsVisible() )
2177  {
2178  wxString name = pin->Connection( sheet )->Name();
2179  wxString local_name = pin->Connection( sheet )->Name( true );
2180 
2181  if( m_global_label_cache.count( name ) ||
2182  ( m_local_label_cache.count( std::make_pair( sheet, local_name ) ) ) )
2183  {
2184  has_other_connections = true;
2185  }
2186  }
2187 
2188  if( pin && !has_other_connections && pin->GetType() != PIN_NC )
2189  {
2190  if( aCreateMarkers )
2191  {
2192  wxPoint pos = pin->GetTransformedPosition();
2193 
2194  msg.Printf( _( "Pin %s of component %s is unconnected." ),
2195  pin->GetName(),
2196  pin->GetParentComponent()->GetRef( &aSubgraph->m_sheet ) );
2197 
2198  auto marker = new SCH_MARKER();
2199  marker->SetTimeStamp( GetNewTimeStamp() );
2200  marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
2201  marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_WARNING );
2202  marker->SetData( ERCE_PIN_NOT_CONNECTED, pos, msg, pos );
2203 
2204  screen->Append( marker );
2205  }
2206 
2207  return false;
2208  }
2209  }
2210 
2211  return true;
2212 }
SCH_SHEET_PATH m_sheet
const wxString & GetName() const
Definition: sch_pin.h:100
bool IsVisible() const
Definition: sch_pin.h:98
timestamp_t GetNewTimeStamp()
Definition: common.cpp:217
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.
#define _(s)
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.
Definition: sch_item.cpp:128
const char * name
Definition: DXF_plotter.cpp:61
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.h:104
bool IsPowerConnection() const
Definition: sch_pin.h:106
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
SCH_COMPONENT * GetParentComponent() const
Definition: sch_pin.cpp:64
SCH_SCREEN * LastScreen() const
Function LastScreen.
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(), PIN_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 1726 of file connection_graph.cpp.

1727 {
1728  if( m_bus_alias_cache.count( aName ) )
1729  return m_bus_alias_cache.at( aName );
1730 
1731  return nullptr;
1732 }
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 1735 of file connection_graph.cpp.

1736 {
1737  std::vector<const CONNECTION_SUBGRAPH*> ret;
1738 
1739  for( auto&& subgraph : m_subgraphs )
1740  {
1741  // Graph is supposed to be up-to-date before calling this
1742  wxASSERT( !subgraph->m_dirty );
1743 
1744  if( !subgraph->m_driver )
1745  continue;
1746 
1747  auto sheet = subgraph->m_sheet;
1748  auto connection = subgraph->m_driver->Connection( sheet );
1749 
1750  if( !connection->IsBus() )
1751  continue;
1752 
1753  auto labels = subgraph->GetBusLabels();
1754 
1755  if( labels.size() > 1 )
1756  {
1757  bool different = false;
1758  wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetText();
1759 
1760  for( unsigned i = 1; i < labels.size(); ++i )
1761  {
1762  if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetText() != first )
1763  {
1764  different = true;
1765  break;
1766  }
1767  }
1768 
1769  if( !different )
1770  continue;
1771 
1772  wxLogTrace( "CONN", "SG %ld (%s) has multiple bus labels", subgraph->m_code,
1773  connection->Name() );
1774 
1775  ret.push_back( subgraph );
1776  }
1777  }
1778 
1779  return ret;
1780 }
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
wxString GetText(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:33
size_t i
Definition: json11.cpp:649

References GetText(), i, and m_subgraphs.

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

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

1663 {
1664  wxASSERT( aBusConnection->IsBus() );
1665 
1666  SCH_CONNECTION* match = nullptr;
1667 
1668  if( aBusConnection->Type() == CONNECTION_BUS )
1669  {
1670  // Vector bus: compare against index, because we allow the name
1671  // to be different
1672 
1673  for( const auto& bus_member : aBusConnection->Members() )
1674  {
1675  if( bus_member->VectorIndex() == aSearch->VectorIndex() )
1676  {
1677  match = bus_member.get();
1678  break;
1679  }
1680  }
1681  }
1682  else
1683  {
1684  // Group bus
1685  for( const auto& c : aBusConnection->Members() )
1686  {
1687  // Vector inside group: compare names, because for bus groups
1688  // we expect the naming to be consistent across all usages
1689  // TODO(JE) explain this in the docs
1690  if( c->Type() == CONNECTION_BUS )
1691  {
1692  for( const auto& bus_member : c->Members() )
1693  {
1694  if( bus_member->RawName() == aSearch->RawName() )
1695  {
1696  match = bus_member.get();
1697  break;
1698  }
1699  }
1700  }
1701  else if( c->RawName() == aSearch->RawName() )
1702  {
1703  match = c.get();
1704  break;
1705  }
1706  }
1707  }
1708 
1709  return match;
1710 }
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 CONNECTION_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 1455 of file connection_graph.cpp.

1456 {
1457  SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1458  std::vector<CONNECTION_SUBGRAPH*> search_list;
1459  std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1460 
1461  auto visit = [&] ( CONNECTION_SUBGRAPH* aParent ) {
1462  for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1463  {
1464  SCH_SHEET_PATH path = aParent->m_sheet;
1465  path.push_back( pin->GetParent() );
1466 
1467  if( !m_sheet_to_subgraphs_map.count( path ) )
1468  continue;
1469 
1470  for( auto candidate : m_sheet_to_subgraphs_map.at( path ) )
1471  {
1472  if( !candidate->m_strong_driver ||
1473  candidate->m_hier_ports.empty() ||
1474  visited.count( candidate ) )
1475  continue;
1476 
1477  for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1478  {
1479  if( label->GetShownText() == pin->GetShownText() )
1480  {
1481  wxLogTrace( "CONN", "%lu: found child %lu (%s)", aParent->m_code,
1482  candidate->m_code, candidate->m_driver_connection->Name() );
1483 
1484  search_list.push_back( candidate );
1485  break;
1486  }
1487  }
1488  }
1489  }
1490 
1491  for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1492  {
1493  SCH_SHEET_PATH path = aParent->m_sheet;
1494  path.pop_back();
1495 
1496  if( !m_sheet_to_subgraphs_map.count( path ) )
1497  continue;
1498 
1499  for( auto candidate : m_sheet_to_subgraphs_map.at( path ) )
1500  {
1501  if( candidate->m_hier_pins.empty() ||
1502  visited.count( candidate ) ||
1503  ( candidate->m_driver_connection->Type() !=
1504  aParent->m_driver_connection->Type() ) )
1505  continue;
1506 
1507  for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1508  {
1509  SCH_SHEET_PATH pin_path = path;
1510  pin_path.push_back( pin->GetParent() );
1511 
1512  if( pin_path != aParent->m_sheet )
1513  continue;
1514 
1515  if( label->GetShownText() == pin->GetShownText() )
1516  {
1517  wxLogTrace( "CONN", "%lu: found additional parent %lu (%s)",
1518  aParent->m_code, candidate->m_code,
1519  candidate->m_driver_connection->Name() );
1520 
1521  search_list.push_back( candidate );
1522  break;
1523  }
1524  }
1525  }
1526  }
1527  };
1528 
1529  auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1530  for( const auto& kv : aParentGraph->m_bus_neighbors )
1531  {
1532  for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1533  {
1534  // May have been absorbed but won't have been deleted
1535  while( neighbor->m_absorbed )
1536  neighbor = neighbor->m_absorbed_by;
1537 
1538  SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1539 
1540  // Now member may be out of date, since we just cloned the
1541  // connection from higher up in the hierarchy. We need to
1542  // figure out what the actual new connection is.
1543  SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1544 
1545  // This is bad, probably an ERC error
1546  if( !member )
1547  {
1548  wxLogTrace( "CONN", "Could not match bus member %s in %s",
1549  kv.first->Name(), parent->Name() );
1550  continue;
1551  }
1552 
1553  auto neighbor_conn = neighbor->m_driver_connection;
1554  auto neighbor_name = neighbor_conn->Name();
1555 
1556  if( neighbor_name == member->Name() )
1557  continue;
1558 
1559  wxLogTrace( "CONN", "%lu (%s) connected to bus member %s", neighbor->m_code,
1560  neighbor_name, member->Name() );
1561 
1562  neighbor_conn->Clone( *member );
1563  neighbor->UpdateItemConnections();
1564 
1565  recacheSubgraphName( neighbor, neighbor_name );
1566 
1567  // Recurse onto this neighbor in case it needs to re-propagate
1568  neighbor->m_dirty = true;
1569  propagateToNeighbors( neighbor );
1570  }
1571  }
1572  };
1573 
1574  // If we are a bus, we must propagate to local neighbors and then the hierarchy
1575  if( conn->IsBus() )
1576  propagate_bus_neighbors( aSubgraph );
1577 
1578  // If we don't have any hier pins (i.e. no children), nothing to do
1579  if( aSubgraph->m_hier_pins.empty() )
1580  {
1581  // If we also don't have any parents, we'll never be visited again
1582  if( aSubgraph->m_hier_ports.empty() )
1583  aSubgraph->m_dirty = false;
1584 
1585  return;
1586  }
1587 
1588  // If we do have hier ports, skip this subgraph as it will be visited by a parent
1589  // TODO(JE) this will leave the subgraph dirty if there is no matching parent subgraph,
1590  // which should be flagged as an ERC error
1591  if( !aSubgraph->m_hier_ports.empty() )
1592  return;
1593 
1594  visited.insert( aSubgraph );
1595 
1596  wxLogTrace( "CONN", "Propagating %lu (%s) to subsheets",
1597  aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1598 
1599  visit( aSubgraph );
1600 
1601  for( unsigned i = 0; i < search_list.size(); i++ )
1602  {
1603  auto child = search_list[i];
1604 
1605  visited.insert( child );
1606 
1607  visit( child );
1608 
1609  child->m_dirty = false;
1610  }
1611 
1612  // Now, find the best driver for this chain of subgraphs
1613  CONNECTION_SUBGRAPH* driver = aSubgraph;
1616 
1617  // Check if a subsheet has a higher-priority connection to the same net
1619  {
1620  for( CONNECTION_SUBGRAPH* subgraph : visited )
1621  {
1623  CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
1624 
1625  // Upgrade driver to be this subgraph if this subgraph has a power pin or global
1626  // Also upgrade if we found something with a shorter sheet path (higher in hierarchy)
1627  // but with an equivalent priority
1628 
1629  if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY_POWER_PIN ) ||
1630  ( priority >= highest && subgraph->m_sheet.size() < aSubgraph->m_sheet.size() ) )
1631  driver = subgraph;
1632  }
1633  }
1634 
1635  if( driver != aSubgraph )
1636  {
1637  wxLogTrace( "CONN", "%lu (%s) overridden by new driver %lu (%s)",
1638  aSubgraph->m_code, aSubgraph->m_driver_connection->Name(),
1639  driver->m_code, driver->m_driver_connection->Name() );
1640  }
1641 
1642  conn = driver->m_driver_connection;
1643 
1644  for( CONNECTION_SUBGRAPH* subgraph : visited )
1645  {
1646  wxString old_name = subgraph->m_driver_connection->Name();
1647 
1648  subgraph->m_driver_connection->Clone( *conn );
1649  subgraph->UpdateItemConnections();
1650 
1651  recacheSubgraphName( subgraph, old_name );
1652 
1653  if( conn->IsBus() )
1654  propagate_bus_neighbors( subgraph );
1655  }
1656 
1657  aSubgraph->m_dirty = false;
1658 }
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
#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
Class SCH_SHEET_PATH.
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).
size_t i
Definition: json11.cpp:649
virtual wxString GetShownText() const
Returns 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 CONNECTION_SUBGRAPH::GetDriverPriority(), SCH_SHEET_PIN::GetParent(), EDA_TEXT::GetShownText(), i, SCH_CONNECTION::IsBus(), kv, 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::PRIORITY_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 1713 of file connection_graph.cpp.

1715 {
1716  if( m_net_name_to_subgraphs_map.count( aOldName ) )
1717  {
1718  auto& vec = m_net_name_to_subgraphs_map.at( aOldName );
1719  vec.erase( std::remove( vec.begin(), vec.end(), aSubgraph ), vec.end() );
1720  }
1721 
1722  m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
1723 }
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 ( 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 378 of file connection_graph.cpp.

379 {
380  PROF_COUNTER recalc_time;
381  PROF_COUNTER update_items;
382 
383  if( aUnconditional )
384  Reset();
385 
386  for( const auto& sheet : aSheetList )
387  {
388  std::vector<SCH_ITEM*> items;
389 
390  for( auto item = sheet.LastScreen()->GetDrawItems();
391  item; item = item->Next() )
392  {
393  if( item->IsConnectable() &&
394  ( aUnconditional || item->IsConnectivityDirty() ) )
395  {
396  items.push_back( item );
397  }
398  }
399 
400  updateItemConnectivity( sheet, items );
401  }
402 
403  update_items.Stop();
404  wxLogTrace( "CONN_PROFILE", "UpdateItemConnectivity() %0.4f ms", update_items.msecs() );
405 
406  PROF_COUNTER tde;
407 
408  // IsDanglingStateChanged() also adds connected items for things like SCH_TEXT
409  SCH_SCREENS schematic;
410  schematic.TestDanglingEnds();
411 
412  tde.Stop();
413  wxLogTrace( "CONN_PROFILE", "TestDanglingEnds() %0.4f ms", tde.msecs() );
414 
415  PROF_COUNTER build_graph;
416 
418 
419  build_graph.Stop();
420  wxLogTrace( "CONN_PROFILE", "BuildConnectionGraph() %0.4f ms", build_graph.msecs() );
421 
422  recalc_time.Stop();
423  wxLogTrace( "CONN_PROFILE", "Recalculate time %0.4f ms", recalc_time.msecs() );
424 
425 #ifndef DEBUG
426  // Pressure relief valve for release builds
427  const double max_recalc_time_msecs = 250.;
428 
430  recalc_time.msecs() > max_recalc_time_msecs )
431  {
432  m_allowRealTime = false;
433  }
434 #endif
435 }
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
static bool m_allowRealTime
bool m_realTimeConnectivity
Do real-time connectivity.
void TestDanglingEnds()
void updateItemConnectivity(SCH_SHEET_PATH aSheet, 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:491

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().

◆ Reset()

void CONNECTION_GRAPH::Reset ( )

Definition at line 355 of file connection_graph.cpp.

356 {
357  for( auto subgraph : m_subgraphs )
358  delete subgraph;
359 
360  m_items.clear();
361  m_subgraphs.clear();
362  m_driver_subgraphs.clear();
363  m_sheet_to_subgraphs_map.clear();
364  m_invisible_power_pins.clear();
365  m_bus_alias_cache.clear();
366  m_net_name_to_code_map.clear();
367  m_bus_name_to_code_map.clear();
370  m_local_label_cache.clear();
371  m_global_label_cache.clear();
372  m_last_net_code = 1;
373  m_last_bus_code = 1;
375 }
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
std::map< int, std::vector< CONNECTION_SUBGRAPH * > > 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(), and Recalculate().

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

1784 {
1785  int error_count = 0;
1786 
1787  for( auto&& subgraph : m_subgraphs )
1788  {
1789  // Graph is supposed to be up-to-date before calling RunERC()
1790  wxASSERT( !subgraph->m_dirty );
1791 
1803  if( aSettings.check_bus_driver_conflicts &&
1804  !subgraph->ResolveDrivers( aCreateMarkers ) )
1805  error_count++;
1806 
1807  if( aSettings.check_bus_to_net_conflicts &&
1808  !ercCheckBusToNetConflicts( subgraph, aCreateMarkers ) )
1809  error_count++;
1810 
1811  if( aSettings.check_bus_entry_conflicts &&
1812  !ercCheckBusToBusEntryConflicts( subgraph, aCreateMarkers ) )
1813  error_count++;
1814 
1815  if( aSettings.check_bus_to_bus_conflicts &&
1816  !ercCheckBusToBusConflicts( subgraph, aCreateMarkers ) )
1817  error_count++;
1818 
1819  // The following checks are always performed since they don't currently
1820  // have an option exposed to the user
1821 
1822  if( !ercCheckNoConnects( subgraph, aCreateMarkers ) )
1823  error_count++;
1824 
1825  if( !ercCheckLabels( subgraph, aCreateMarkers, aSettings.check_unique_global_labels ) )
1826  error_count++;
1827  }
1828 
1829  return error_count;
1830 }
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,
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 438 of file connection_graph.cpp.

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

References CONNECTION_BUS, CONNECTION_NET, SCH_SCREEN::GetBus(), SCH_COMPONENT::GetPins(), SCH_COMPONENT::GetPosition(), SCH_COMPONENT::GetTransform(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, m_invisible_power_pins, m_items, 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 264 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 268 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 256 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 270 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 262 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 284 of file connection_graph.h.

◆ m_items

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

Definition at line 250 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 280 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 278 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 282 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

std::map<int, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_net_code_to_subgraphs_map

◆ m_net_name_to_code_map

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

Definition at line 266 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 260 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 253 of file connection_graph.h.

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


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