27 #include <unordered_map> 68 std::vector<SCH_ITEM*> candidates;
69 std::vector<SCH_ITEM*> strong_drivers;
85 && !static_cast<SCH_PIN*>( item )->GetParentSymbol()->IsInNetlist() )
89 strong_drivers.push_back( item );
91 if( item_priority > highest_priority )
94 candidates.push_back( item );
95 highest_priority = item_priority;
97 else if( !candidates.empty() && ( item_priority == highest_priority ) )
99 candidates.push_back( item );
109 if( !candidates.empty() )
111 if( candidates.size() > 1 )
132 void* previousDriver =
nullptr;
138 if( mc->GetLastDriver() )
140 previousDriver = mc->GetLastDriver();
147 std::sort( candidates.begin(), candidates.end(),
161 if( a == previousDriver )
163 else if( b == previousDriver )
175 if( strong_drivers.size() > 1 )
202 for(
unsigned i = 1; i < candidates.size(); i++ )
206 second_item = candidates[i];
230 #ifdef CONNECTIVITY_DEBUG 231 wxASSERT_MSG(
false, wxT(
"Tried to get the net name of an item with no connection" ) );
243 std::vector<SCH_ITEM*> labels;
247 switch( item->Type() )
256 labels.push_back( item );
271 switch( aItem->
Type() )
276 SCH_PIN*
pin = static_cast<SCH_PIN*>( aItem );
277 return pin->GetDefaultNetName(
m_sheet, forceNoConnect );
291 wxFAIL_MSG( wxT(
"Unhandled item type in GetNameForDriver" ) );
295 return wxEmptyString;
354 m_hier_pins.push_back( static_cast<SCH_SHEET_PIN*>( aItem ) );
356 m_hier_ports.push_back( static_cast<SCH_HIERLABEL*>( aItem ) );
392 switch( aDriver->
Type() )
400 SCH_PIN* sch_pin = static_cast<SCH_PIN*>( aDriver );
441 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler )
443 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
448 PROF_TIMER update_items(
"updateItemConnectivity" );
454 std::vector<SCH_ITEM*> items;
456 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
458 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
459 items.push_back( item );
467 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
473 PROF_TIMER build_graph(
"buildConnectionGraph" );
487 const double max_recalc_time_msecs = 250.;
490 recalc_time.
msecs() > max_recalc_time_msecs )
499 const std::vector<SCH_ITEM*>& aItemList )
501 std::map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
505 std::vector< wxPoint > points = item->GetConnectionPoints();
506 item->ConnectedItems( aSheet ).clear();
512 pin->InitializeConnection( aSheet,
this );
514 pin->ConnectedItems( aSheet ).clear();
516 connection_map[
pin->GetTextPos() ].push_back(
pin );
522 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
526 pin->InitializeConnection( aSheet,
this );
528 wxPoint pos =
pin->GetPosition();
531 pin->GetDefaultNetName( aSheet );
532 pin->ConnectedItems( aSheet ).clear();
536 if(
pin->IsPowerConnection() && !
pin->IsVisible() )
539 connection_map[ pos ].push_back(
pin );
546 SCH_CONNECTION* conn = item->InitializeConnection( aSheet,
this );
549 switch( item->Type() )
559 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] =
nullptr;
560 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] =
nullptr;
570 static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item =
nullptr;
577 for(
const wxPoint& point : points )
578 connection_map[ point ].push_back( item );
581 item->SetConnectivityDirty(
false );
584 for(
const auto& it : connection_map )
586 const std::vector<SCH_ITEM*>& connection_vec = it.second;
592 size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
593 ( connection_vec.size() + 3 ) / 4 );
595 std::atomic<size_t> nextItem( 0 );
596 std::mutex update_mutex;
597 std::vector<std::future<size_t>> returns( parallelThreadCount );
599 auto update_lambda = [&]() ->
size_t 601 for(
size_t ii = nextItem++; ii < connection_vec.size(); ii = nextItem++ )
603 SCH_ITEM* connected_item = connection_vec[ii];
616 if( connection_vec.size() == 1 )
620 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
621 bus_entry->m_connected_bus_item = busLine;
629 if( connection_vec.size() < 2 )
633 auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
635 if( it.first == bus_entry->GetPosition() )
636 bus_entry->m_connected_bus_items[0] = busLine;
638 bus_entry->m_connected_bus_items[1] = busLine;
640 std::lock_guard<std::mutex> lock( update_mutex );
654 connected_set.reserve( connection_vec.size() );
656 for(
SCH_ITEM* test_item : connection_vec )
658 bool bus_connection_ok =
true;
660 if( test_item == connected_item )
668 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
669 bus_entry->m_connected_bus_item = test_item;
686 test_item->ConnectionPropagatesTo( connected_item ) &&
689 connected_set.push_back( test_item );
698 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
700 if( !bus_entry->m_connected_bus_item )
706 bus_entry->m_connected_bus_item = bus;
715 if( parallelThreadCount == 1 )
719 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
720 returns[ii] = std::async( std::launch::async, update_lambda );
723 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
736 for(
const auto& it : item->m_connection_map )
753 std::list<SCH_ITEM*> memberlist;
759 bool unique = !( aItem->GetFlags() &
CANDIDATE );
764 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
767 std::copy_if( item->ConnectedItems( sheet ).begin(),
768 item->ConnectedItems( sheet ).end(),
769 std::back_inserter( memberlist ), get_items );
771 for(
SCH_ITEM* connected_item : memberlist )
776 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
778 wxASSERT( connected_conn );
780 if( connected_conn->SubgraphCode() == 0 )
782 connected_conn->SetSubgraphCode( subgraph->
m_code );
784 subgraph->
AddItem( connected_item );
785 SCH_ITEM_SET& citemset = connected_item->ConnectedItems( sheet );
792 if( get_items( citem ) )
793 memberlist.push_back( citem );
798 for(
SCH_ITEM* connected_item : memberlist )
814 size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
817 std::atomic<size_t> nextSubgraph( 0 );
818 std::vector<std::future<size_t>> returns( parallelThreadCount );
819 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
824 return candidate->m_dirty;
827 auto update_lambda = [&nextSubgraph, &dirty_graphs]() ->
size_t 829 for(
size_t subgraphId = nextSubgraph++; subgraphId < dirty_graphs.size(); subgraphId = nextSubgraph++ )
831 auto subgraph = dirty_graphs[subgraphId];
833 if( !subgraph->m_dirty )
837 for(
auto item : subgraph->m_items )
839 switch( item->Type() )
842 subgraph->m_no_connect = item;
846 subgraph->m_bus_entry = item;
851 auto pin = static_cast<SCH_PIN*>( item );
854 subgraph->m_no_connect = item;
864 subgraph->ResolveDrivers(
true );
865 subgraph->m_dirty =
false;
871 if( parallelThreadCount == 1 )
875 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
876 returns[ii] = std::async( std::launch::async, update_lambda );
879 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
888 return candidate->m_driver;
901 wxString full_name = subgraph->m_driver_connection->Name();
902 wxString
name = subgraph->m_driver_connection->Name(
true );
911 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
915 subgraph->m_dirty =
true;
917 if( subgraph->m_strong_driver )
919 SCH_ITEM* driver = subgraph->m_driver;
922 switch( driver->
Type() )
937 SCH_PIN*
pin = static_cast<SCH_PIN*>( driver );
938 wxASSERT(
pin->IsPowerConnection() );
943 wxLogTrace(
ConnTrace, wxT(
"Unexpected strong driver %s" ),
957 std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
964 if( !
pin->ConnectedItems( sheet ).empty() && !
pin->GetLibPin()->GetParent()->IsPower() )
983 auto jj = invisible_pin_subgraphs.find( code );
985 if( jj != invisible_pin_subgraphs.end() )
987 subgraph = jj->second;
1000 auto key = std::make_pair( subgraph->
GetNetName(), code );
1005 invisible_pin_subgraphs[code] = subgraph;
1022 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1026 if( subgraph->m_absorbed )
1031 wxString
name = connection->
Name();
1034 unsigned suffix = 1;
1036 auto create_new_name =
1046 wxString prefix = aConn->BusPrefix();
1048 if( prefix.empty() )
1049 prefix = wxT(
"BUS" );
1051 wxString oldName = aConn->Name().AfterFirst(
'{' );
1055 aConn->ConfigureFromLabel( newName );
1067 if( !subgraph->m_strong_driver )
1075 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1079 if( vec->size() > 1 )
1081 wxString new_name = create_new_name( connection );
1084 new_name = create_new_name( connection );
1086 wxLogTrace(
ConnTrace, wxT(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
1087 subgraph->m_code,
name, new_name );
1107 bool conflict =
false;
1108 wxString global_name = connection->
Name(
true );
1115 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1119 if( candidate->m_sheet == sheet )
1127 wxT(
"%ld (%s) skipped for promotion due to potential conflict" ),
1128 subgraph->m_code,
name );
1133 wxT(
"%ld (%s) weakly driven by unique sheet pin %s, promoting" ),
1134 subgraph->m_code,
name,
1137 subgraph->m_strong_driver =
true;
1145 if( connection->
IsBus() )
1169 subgraph->m_dirty =
true;
1178 if( !subgraph->m_strong_driver )
1186 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1189 std::back_inserter( candidate_subgraphs ),
1192 return ( !candidate->m_absorbed &&
1193 candidate->m_strong_driver &&
1194 candidate != subgraph );
1200 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1203 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1206 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
1208 if( possible_driver == aSubgraph->m_driver )
1215 if( c->Type() != aSubgraph->m_driver_connection->Type() )
1218 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
1221 connections_to_check.push_back( c );
1223 wxT(
"%lu (%s): Adding secondary driver %s" ), aSubgraph->m_code,
1224 aSubgraph->m_driver_connection->Name(
true ), c->Name(
true ) );
1232 add_connections_to_check( subgraph );
1234 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
1236 auto member = connections_to_check[i];
1238 if( member->IsBus() )
1240 connections_to_check.insert( connections_to_check.end(),
1241 member->Members().begin(),
1242 member->Members().end() );
1245 wxString test_name = member->Name(
true );
1247 for(
auto candidate : candidate_subgraphs )
1249 if( candidate->m_absorbed )
1254 if( candidate->m_driver_connection->Name(
true ) == test_name )
1260 if( !candidate->m_multiple_drivers )
1263 for(
SCH_ITEM *driver : candidate->m_drivers )
1265 if( driver == candidate->m_driver )
1274 auto pin = static_cast<SCH_PIN*>( driver );
1276 if(
pin->IsPowerConnection() &&
pin->GetShownName() == test_name )
1288 if( subgraph->GetNameForDriver( driver ) == test_name )
1299 if( connection->
IsBus() && candidate->m_driver_connection->IsNet() )
1301 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) has bus child %lu (%s)" ), subgraph->m_code,
1302 connection->
Name(), candidate->m_code, member->Name() );
1304 subgraph->m_bus_neighbors[member].insert( candidate );
1305 candidate->m_bus_parents[member].insert( subgraph );
1309 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) absorbs neighbor %lu (%s)" ),
1310 subgraph->m_code, connection->
Name(),
1311 candidate->m_code, candidate->m_driver_connection->Name() );
1314 add_connections_to_check( candidate );
1316 subgraph->Absorb( candidate );
1317 invalidated_subgraphs.insert( subgraph );
1327 if( subgraph->m_absorbed )
1330 subgraph->ResolveDrivers();
1332 if( subgraph->m_driver_connection->IsBus() )
1337 wxLogTrace(
ConnTrace, wxT(
"Re-resolving drivers for %lu (%s)" ), subgraph->m_code,
1338 subgraph->m_driver_connection->Name() );
1359 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
1363 for(
unsigned i = 0; i < all_sheets.size(); i++ )
1365 for(
const auto& alias : all_sheets[i].LastScreen()->GetBusAliases() )
1369 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
1387 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
1391 proc_sub_graph.
Show();
1400 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1402 std::back_inserter( global_subgraphs ),
1415 std::atomic<size_t> nextSubgraph( 0 );
1418 size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
1421 std::vector<std::future<size_t>> returns( parallelThreadCount );
1423 auto preliminaryUpdateTask =
1426 for(
size_t subgraphId = nextSubgraph++;
1428 subgraphId = nextSubgraph++ )
1436 if( parallelThreadCount == 1 )
1437 preliminaryUpdateTask();
1440 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1441 returns[ii] = std::async( std::launch::async, preliminaryUpdateTask );
1444 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1454 if( !subgraph->m_dirty )
1457 wxLogTrace(
ConnTrace, wxT(
"Processing %lu (%s) for propagation" ), subgraph->m_code,
1458 subgraph->m_driver_connection->Name() );
1464 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1466 for(
SCH_ITEM* driver : subgraph->m_drivers )
1468 if( driver == subgraph->m_driver )
1471 wxString secondary_name = subgraph->GetNameForDriver( driver );
1473 if( secondary_name == subgraph->m_driver_connection->Name() )
1481 if( candidate == subgraph )
1484 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
1489 if( conn->
Name() == secondary_name )
1491 wxLogTrace(
ConnTrace, wxT(
"Global %lu (%s) promoted to %s" ), candidate->
m_code,
1492 conn->
Name(), subgraph->m_driver_connection->Name() );
1494 conn->
Clone( *subgraph->m_driver_connection );
1519 wxASSERT_MSG( !subgraph->m_dirty, wxT(
"Subgraph not processed by propagateToNeighbors!" ) );
1521 if( subgraph->m_bus_parents.size() < 2 )
1526 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) has multiple bus parents" ),
1527 subgraph->m_code, conn->
Name() );
1529 wxASSERT( conn->
IsNet() );
1531 for(
const auto& ii : subgraph->m_bus_parents )
1544 wxLogTrace(
ConnTrace, wxT(
"Warning: could not match %s inside %lu (%s)" ),
1549 if( conn->
Name() != match->
Name() )
1551 wxString old_name = match->
Name();
1553 wxLogTrace(
ConnTrace, wxT(
"Updating %lu (%s) member %s to %s" ), parent->
m_code,
1556 match->
Clone( *conn );
1575 nextSubgraph.store( 0 );
1577 auto updateItemConnectionsTask =
1580 for(
size_t subgraphId = nextSubgraph++;
1582 subgraphId = nextSubgraph++ )
1591 wxString
name =
pin->GetDefaultNetName( subgraph->
m_sheet,
true );
1612 wxString pinText =
pin->GetText();
1619 if( label->
GetText() == pinText )
1622 path.push_back( sheet );
1626 if( parent_conn && parent_conn->
IsBus() )
1642 if( parallelThreadCount == 1 )
1643 updateItemConnectionsTask();
1646 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1647 returns[ii] = std::async( std::launch::async, updateItemConnectionsTask );
1650 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1659 auto key = std::make_pair( subgraph->GetNetName(),
1660 subgraph->m_driver_connection->NetCode() );
1692 auto connections_to_check( aConnection->
Members() );
1694 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
1696 auto member = connections_to_check[i];
1698 if( member->IsBus() )
1700 connections_to_check.insert( connections_to_check.end(),
1701 member->Members().begin(),
1702 member->Members().end() );
1714 std::vector<CONNECTION_SUBGRAPH*> search_list;
1715 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1716 std::vector<SCH_CONNECTION*> stale_bus_members;
1724 path.push_back(
pin->GetParent() );
1735 || visited.count( candidate ) )
1744 wxLogTrace(
ConnTrace, wxT(
"%lu: found child %lu (%s)" ), aParent->m_code,
1749 search_list.push_back( candidate );
1769 || visited.count( candidate )
1780 if( pin_path != aParent->m_sheet )
1785 wxLogTrace(
ConnTrace, wxT(
"%lu: found additional parent %lu (%s)" ),
1786 aParent->m_code, candidate->
m_code,
1789 search_list.push_back( candidate );
1798 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
1840 wxLogTrace(
ConnTrace, wxT(
"Could not match bus member %s in %s" ),
1841 kv.first->Name(), parent->
Name() );
1846 auto neighbor_name = neighbor_conn->
Name();
1849 if( neighbor_name == member->
Name() )
1853 if( neighbor_conn->Sheet() != neighbor->
m_sheet )
1857 wxASSERT( neighbor_conn->IsNet() );
1859 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) connected to bus member %s (local %s)" ),
1866 member->
Clone( *neighbor_conn );
1867 stale_bus_members.push_back( member );
1871 neighbor_conn->Clone( *member );
1885 propagate_bus_neighbors( aSubgraph );
1892 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) has both hier ports and pins; deferring processing" ),
1898 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) has no hier pins or ports; marking clean" ),
1904 visited.insert( aSubgraph );
1906 wxLogTrace(
ConnTrace, wxT(
"Propagating %lu (%s) to subsheets" ),
1911 for(
unsigned i = 0; i < search_list.size(); i++ )
1913 auto child = search_list[i];
1915 visited.insert( child );
1919 child->m_dirty =
false;
1934 if( subgraph == aSubgraph )
1941 wxString candidateName = subgraph->m_driver_connection->Name();
1942 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
1943 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
1953 ( !bestIsStrong && candidateStrong ) ||
1954 ( priority > highest && candidateStrong ) ||
1955 ( priority == highest && candidateStrong && shorterPath ) ||
1956 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
1957 ( candidateName < bestName ) ) )
1959 bestDriver = subgraph;
1961 bestIsStrong = candidateStrong;
1962 bestName = candidateName;
1967 if( bestDriver != aSubgraph )
1969 wxLogTrace(
ConnTrace, wxT(
"%lu (%s) overridden by new driver %lu (%s)" ),
1978 wxString old_name = subgraph->m_driver_connection->
Name();
1980 subgraph->m_driver_connection->Clone( *conn );
1982 if( old_name != conn->
Name() )
1986 propagate_bus_neighbors( subgraph );
1992 if( conn->
IsBus() && !stale_bus_members.empty() )
2003 wxLogTrace(
ConnTrace, wxT(
"WARNING: failed to match stale member %s in %s." ),
2004 stale_member->Name(), subgraph->m_driver_connection->Name() );
2008 wxLogTrace(
ConnTrace, wxT(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
2009 subgraph->m_driver_connection->Name(), member->
LocalName(),
2010 stale_member->Name() );
2012 member->
Clone( *stale_member );
2014 propagate_bus_neighbors( subgraph );
2026 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
2028 switch( aItem->
Type() )
2032 SCH_PIN*
pin = static_cast<SCH_PIN*>( aItem );
2034 if(
pin->IsPowerConnection() )
2035 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2044 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2054 c->SetGraph(
this );
2065 wxASSERT( aBusConnection->
IsBus() );
2074 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
2076 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
2078 match = bus_member.get();
2086 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
2093 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
2095 if( bus_member->LocalName() == aSearch->
LocalName() )
2097 match = bus_member.get();
2102 else if( c->LocalName() == aSearch->
LocalName() )
2115 const wxString& aOldName )
2121 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2125 wxLogTrace(
ConnTrace, wxT(
"recacheSubgraphName: %s => %s" ), aOldName,
2142 std::vector<const CONNECTION_SUBGRAPH*> ret;
2147 wxASSERT( !subgraph->m_dirty );
2149 if( !subgraph->m_driver )
2154 if( !connection->
IsBus() )
2157 auto labels = subgraph->GetBusLabels();
2159 if( labels.size() > 1 )
2161 bool different =
false;
2162 wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2164 for(
unsigned i = 1; i < labels.size(); ++i )
2166 if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2176 wxLogTrace(
ConnTrace, wxT(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
2177 connection->
Name() );
2179 ret.push_back( subgraph );
2215 wxASSERT( !it->second.empty() );
2217 return it->second[0];
2235 int error_count = 0;
2237 wxCHECK_MSG(
m_schematic,
true, wxT(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
2243 std::set<SCH_ITEM*> seenDriverInstances;
2248 wxCHECK2( subgraph,
continue );
2251 wxASSERT( !subgraph->m_dirty );
2253 if( subgraph->m_absorbed )
2256 if( seenDriverInstances.count( subgraph->m_driver ) )
2259 if( subgraph->m_driver )
2260 seenDriverInstances.insert( subgraph->m_driver );
2278 subgraph->ResolveDrivers(
false );
2333 wxCHECK( aSubgraph,
false );
2346 static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2353 "items; %s will be used in the netlist" ),
2354 primaryName, secondaryName, primaryName );
2357 ercItem->SetItems( primary, secondary );
2358 ercItem->SetErrorMessage( msg );
2370 if( driver == aSubgraph->
m_driver )
2380 if( primaryName == secondaryName )
2384 "items; %s will be used in the netlist" ),
2385 primaryName, secondaryName, primaryName );
2388 ercItem->SetItems( aSubgraph->
m_driver, driver );
2389 ercItem->SetErrorMessage( msg );
2415 switch( item->
Type() )
2420 bus_item = ( !bus_item ) ? item : bus_item;
2422 net_item = ( !net_item ) ? item : net_item;
2435 bus_item = ( !bus_item ) ? item : bus_item;
2437 net_item = ( !net_item ) ? item : net_item;
2446 if( net_item && bus_item )
2449 ercItem->SetItems( net_item, bus_item );
2452 screen->
Append( marker );
2470 for(
auto item : aSubgraph->
m_items )
2472 switch( item->Type() )
2503 if(
test != member && member->Name() ==
test->Name() )
2517 ercItem->SetItems( label, port );
2520 screen->
Append( marker );
2532 bool conflict =
false;
2548 switch( item->
Type() )
2553 bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2584 for(
const auto& sub_member : member->Members() )
2586 if( sub_member->Name() == test_name )
2590 else if( member->Name() == test_name )
2609 wxString msg =
wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a" 2610 " member of that bus" ),
2614 ercItem->SetItems( bus_entry, bus_wire );
2615 ercItem->SetErrorMessage( msg );
2618 screen->
Append( marker );
2638 bool has_invalid_items =
false;
2639 bool has_other_items =
false;
2641 std::vector<SCH_ITEM*> invalid_items;
2650 switch( item->
Type() )
2654 SCH_PIN* candidate = static_cast<SCH_PIN*>( item );
2656 .SquaredEuclideanNorm();
2658 if( !
pin || dist < minDist )
2664 has_invalid_items |= has_other_items;
2665 has_other_items =
true;
2675 has_invalid_items =
true;
2676 has_other_items =
true;
2677 invalid_items.push_back( item );
2684 ercItem->SetItems(
pin );
2687 screen->
Append( marker );
2698 screen->
Append( marker );
2705 bool has_other_connections =
false;
2706 std::vector<SCH_PIN*> pins;
2713 switch( item->
Type() )
2718 has_other_connections =
true;
2720 pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2727 has_other_connections =
true;
2734 SCH_PIN*
pin = pins.empty() ? nullptr : pins[0];
2740 if(
pin && !has_other_connections
2742 && !
pin->IsVisible()
2743 && !
pin->GetLibPin()->GetParent()->IsPower() )
2745 wxString
name =
pin->Connection( &sheet )->Name();
2746 wxString local_name =
pin->Connection( &sheet )->Name(
true );
2751 has_other_connections =
true;
2756 if(
pin && !has_other_connections
2762 ercItem->SetItems(
pin );
2765 screen->
Append( marker );
2773 if( pins.size() > 1 )
2775 for(
SCH_PIN* testPin : pins )
2780 if( testPin->GetLibPin()->GetParent()->IsPower()
2781 && testPin->ConnectedItems( sheet ).empty()
2785 ercItem->SetItems( testPin );
2788 testPin->GetTransformedPosition() );
2789 screen->
Append( marker );
2806 std::vector<SCH_ITEM*> wires;
2814 wires.emplace_back( item );
2816 wires.emplace_back( item );
2819 if( !wires.empty() )
2824 ercItem->SetItems( wires[0],
2825 wires.size() > 1 ? wires[1] :
nullptr,
2826 wires.size() > 2 ? wires[2] :
nullptr,
2827 wires.size() > 3 ? wires[3] : nullptr );
2830 screen->
Append( marker );
2861 bool hasOtherConnections =
false;
2867 for(
const SCH_ITEM* item : aLocSubgraph->m_items )
2869 switch( item->
Type() )
2884 switch( item->
Type() )
2890 text = static_cast<SCH_TEXT*>( item );
2899 ercItem->SetItems(
text );
2911 hasOtherConnections =
true;
2926 wxCHECK_MSG(
m_schematic,
true, wxT(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
2935 hasOtherConnections = ( pinCount > 1 );
2942 hasOtherConnections =
true;
2954 hasOtherConnections =
true;
2959 auto pair = std::make_pair( aSubgraph->
m_sheet,
name );
2966 if( neighbor == aSubgraph )
2969 if( hasPins( neighbor ) )
2971 hasOtherConnections =
true;
2978 if( !hasOtherConnections && settings.
IsTestEnabled( errCode ) )
2981 ercItem->SetItems(
text );
3001 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
3006 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
3008 std::map<wxString, SCH_SHEET_PIN*> pins;
3009 std::map<wxString, SCH_HIERLABEL*> labels;
3014 pins[
pin->GetText()] =
pin;
3019 ercItem->SetItems(
pin );
3022 sheet.LastScreen()->Append( marker );
3030 std::set<wxString> matchedPins;
3036 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
3038 if( !pins.count( label->
GetText() ) )
3039 labels[label->
GetText()] = label;
3041 matchedPins.insert( label->
GetText() );
3045 for(
const wxString& matched : matchedPins )
3046 pins.erase( matched );
3048 for(
const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
3050 wxString msg =
wxString::Format(
_(
"Sheet pin %s has no matching hierarchical " 3051 "label inside the sheet" ),
3055 ercItem->SetItems( unmatched.second );
3056 ercItem->SetErrorMessage( msg );
3057 ercItem->SetIsSheetSpecific();
3060 sheet.LastScreen()->Append( marker );
3065 for(
const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
3068 "sheet pin in the parent sheet" ),
3072 ercItem->SetItems( unmatched.second );
3073 ercItem->SetErrorMessage( msg );
3074 ercItem->SetIsSheetSpecific();
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Returns the subgraph for a given net name on a given sheet.
power input (GND, VCC for ICs). Must be connected to a power output.
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
void SetBusCode(int aCode)
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
Pin not connected and not no connect symbol.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
A connection between bus objects doesn't share at least one net.
void resolveAllDrivers()
Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel.
void buildConnectionGraph()
Generates the connection graph (after all item connectivity has been updated)
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
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 ...
std::shared_ptr< BUS_ALIAS > GetBusAlias(const wxString &aName)
Returns a bus alias pointer for the given name if it exists (from cache)
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_neighbors
If a subgraph is a bus, this map contains links between the bus members and any local sheet neighbors...
void AddConnectionTo(const SCH_SHEET_PATH &aPath, SCH_ITEM *aItem)
Add a connection link between this item and another.
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combines another subgraph on the same sheet into this one.
SCH_ITEM * m_driver
The SCH_ITEM that drives this connection's net.
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
This item represents a bus group.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
virtual bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const
Return true if this item should propagate connection info to aItem.
bool IsTestEnabled(int aErrorCode) const
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
A bus wire is graphically connected to a net port/pin (or vice versa).
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.
std::vector< SCH_SHEET_PIN * > m_hier_pins
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_parents
If this is a net, this vector contains links to any same-sheet buses that contain it.
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
void SetDriver(SCH_ITEM *aItem)
Some wires are not connected to anything else.
void SetName(const wxString &aName)
NET_MAP m_net_code_to_subgraphs_map
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
Updates the connection graph for the given list of sheets.
std::vector< SCH_ITEM * > m_items
Label not connected to anything.
SCHEMATIC * m_schematic
The schematic this graph represents.
virtual wxPoint GetPosition() const
wxString LocalName() const
void buildItemSubGraphs()
Generates individual item subgraphs on a per-sheet basis.
SCH_SCREEN * GetScreen() const
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.
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
int ercCheckHierSheets()
Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on th...
static const wxChar ConnTrace[]
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
#define CANDIDATE
flag indicating that the structure is connected
std::vector< SCH_ITEM * > SCH_ITEM_SET
not internally connected (may be connected to anything)
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between net and bus labels.
CONNECTION_GRAPH * m_graph
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
size_t size() const
Forwarded method from std::vector.
void SetSubgraphCode(int aCode)
SCH_LINE * GetBus(const wxPoint &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper presence or absence of no-connect symbols.
std::vector< SCH_ITEM * > m_items
double msecs(bool aSinceLast=false)
void SetLayer(SCH_LAYER_ID aLayer)
Set the layer this item is on.
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
Functions to provide common constants and other functions to assist in making a consistent UI.
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Container for ERC settings.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void generateInvisiblePinSubGraphs()
Iterate through the invisible power pins to collect the global labels as drivers.
A wire connected to a bus doesn't match the bus.
CONNECTION_SUBGRAPH * FindFirstSubgraphByName(const wxString &aNetName)
Retrieves a subgraph for the given net name, if one exists.
bool IsDriver() const
Checks if the SCH_ITEM this connection is attached to can drive connections Drivers can be labels,...
std::vector< SCH_HIERLABEL * > m_hier_ports
A small class to help profiling.
A no connect symbol is not connected to anything.
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.
wxString UnescapeString(const wxString &aSource)
void Stop()
Save the time when this function was called, and set the counter stane to stop.
This item represents a net.
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
static const wxChar ConnProfileMask[]
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
std::vector< SCH_SHEET_PIN * > & GetPins()
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
static bool m_allowRealTime
A global label is unique.
A no connect symbol is connected to more than 1 pin.
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
void processSubGraphs()
Process all subgraphs to assign netcodes and merge subgraphs based on labels.
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
SCH_SCREEN * LastScreen()
Segment description base class to describe items which have 2 end points (track, wire,...
Mismatch between hierarchical labels and pins sheets.
SCH_ITEM_SET & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieve the set of items connected to this item on the given sheet.
void Append(SCH_ITEM *aItem)
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
SCH_SHEET_LIST m_sheetList
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Builds a new default connection for the given item based on its properties.
std::vector< SCH_ITEM * > GetBusLabels() const
Returns all the bus labels attached to this subgraph (if any)
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
std::map< wxString, int > m_bus_name_to_code_map
wxString driverName(SCH_ITEM *aItem) const
std::map< wxString, int > m_net_name_to_code_map
CONNECTION_SUBGRAPH * m_hier_parent
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void collectAllDriverValues()
Maps the driver values for each subgraph.
CONNECTION_SUBGRAPH * GetSubgraphForItem(SCH_ITEM *aItem)
bool IsPowerConnection() const
ERC_SETTINGS & ErcSettings() const
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
void SetType(CONNECTION_TYPE aType)
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
not connected (must be left open)
bool IsSubsetOf(SCH_CONNECTION *aOther) const
Returns true if this connection is contained within aOther (but not the same as aOther)
Conflicting drivers (labels, etc) on a subgraph.
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration()
Determines which subgraphs have more than one conflicting bus label.
CONNECTION_TYPE Type() const
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
Base class for any item which can be embedded within the SCHEMATIC container class,...
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
virtual const wxString & GetText() const
Return the string associated with the text object.
int RunERC()
Runs electrical rule checks on the connectivity graph.
void SetNetCode(int aCode)
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
PRIORITY GetDriverPriority()
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
This item represents a bus vector.
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
PINSHEETLABEL_SHAPE GetShape() const
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.
KICAD_T Type() const
Returns the type of object.
std::unordered_map< SCH_ITEM *, wxString > m_driver_name_cache
A cache of escaped netnames from schematic items.
wxPoint GetPosition() const override
wxPoint GetTransformedPosition() const
void UpdateItemConnections()
Updates all items to match the driver connection.