26#include <unordered_map>
106 if( old_conn && new_conn )
108 new_conn->
Clone( *old_conn );
157 if( aPower && !bPower )
159 else if( bPower && !aPower )
165 bool a_lowQualityName = a_name.Contains(
"-Pad" );
166 bool b_lowQualityName = b_name.Contains(
"-Pad" );
168 if( a_lowQualityName && !b_lowQualityName )
170 else if( b_lowQualityName && !a_lowQualityName )
173 return a_name < b_name;
177 std::set<
SCH_ITEM*,
decltype( candidate_cmp )> candidates( candidate_cmp );
178 std::set<SCH_ITEM*> strong_drivers;
202 strong_drivers.insert( item );
204 if( item_priority > highest_priority )
207 candidates.insert( item );
208 highest_priority = item_priority;
210 else if( !candidates.empty() && ( item_priority == highest_priority ) )
212 candidates.insert( item );
222 if( !candidates.empty() )
224 if( candidates.size() > 1 )
235 if( p->
GetShape() == LABEL_FLAG_SHAPE::L_OUTPUT )
248 if( strong_drivers.size() > 1 )
255 m_drivers.insert( strong_drivers.begin(), strong_drivers.end() );
277 std::set<CONNECTION_SUBGRAPH*>& aSubgraphs )
289 if( aSubgraphs.insert( sg ).second ==
false )
295 aItems.emplace(
m_sheet, item );
309#ifdef CONNECTIVITY_DEBUG
310 wxASSERT_MSG(
false, wxS(
"Tried to get the net name of an item with no connection" ) );
322 std::vector<SCH_ITEM*> labels;
326 switch( item->Type() )
334 if( type == CONNECTION_TYPE::BUS || type == CONNECTION_TYPE::BUS_GROUP )
335 labels.push_back( item );
351 std::vector<SCH_ITEM*> labels;
355 switch( item->Type() )
363 if( label_conn->
Type() == CONNECTION_TYPE::BUS )
364 labels.push_back( item );
380 switch( aItem->
Type() )
387 return pin->GetDefaultNetName(
m_sheet, forceNoConnect );
414 wxFAIL_MSG( wxS(
"Unhandled item type in GetNameForDriver" ) );
415 return wxEmptyString;
434const std::vector<std::pair<wxString, SCH_ITEM*>>
437 std::vector<std::pair<wxString, SCH_ITEM*>> foundNetclasses;
439 const std::unordered_set<SCH_RULE_AREA*>& ruleAreaCache = aItem->
GetRuleAreaCache();
444 const std::vector<std::pair<wxString, SCH_ITEM*>> ruleNetclasses =
445 ruleArea->GetResolvedNetclasses();
447 if( ruleNetclasses.size() > 0 )
451 foundNetclasses.insert( foundNetclasses.end(), ruleNetclasses.begin(),
452 ruleNetclasses.end() );
456 foundNetclasses.push_back( ruleNetclasses[0] );
457 return foundNetclasses;
468 SCH_FIELD* field = static_cast<SCH_FIELD*>( aChild );
470 if( field->GetCanonicalName() == wxT(
"Netclass" ) )
472 wxString netclass = field->GetShownText( &m_sheet, false );
474 if( netclass != wxEmptyString )
475 foundNetclasses.push_back( { netclass, aItem } );
484 return foundNetclasses;
510 child->m_absorbed_by =
this;
513 set_absorbed_by( subchild );
521 set_absorbed_by( aOther );
571 switch( aDriver->
Type() )
585 || sym->
GetLibSymbolRef()->GetReferenceField().GetText().StartsWith(
'#' ) )
599 std::back_inserter(
m_items ) );
656 wxCHECK2( aOldItem->
Type() == aNewItem->
Type(),
return );
691 wxCHECK2( oldPins.size() == newPins.size(),
return );
693 for(
size_t ii = 0; ii < oldPins.size(); ii++ )
695 exchange( oldPins[ii], newPins[ii] );
706 if( subgraph->m_graph ==
this )
730 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler )
732 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
737 PROF_TIMER update_items(
"updateItemConnectivity" );
740 std::set<SCH_ITEM*> dirty_items;
744 std::vector<SCH_ITEM*> items;
747 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
749 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
751 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
753 wxLogTrace(
ConnTrace, wxT(
"Adding item %s to connectivity graph update" ),
754 item->GetTypeDesc() );
755 items.push_back( item );
756 dirty_items.insert( item );
765 if(
pin->IsConnectivityDirty() )
767 dirty_items.insert(
pin );
780 if(
pin->IsConnectivityDirty() )
782 items.push_back(
pin );
783 dirty_items.insert(
pin );
793 if(
pin->IsConnectivityDirty() )
795 items.push_back(
pin );
796 dirty_items.insert(
pin );
809 if( symbol->
GetUnit() != new_unit )
810 symbolsChanged.push_back( { symbol, symbol->
GetUnit() } );
812 symbol->SetUnit( new_unit );
821 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
824 for(
const auto& [ symbol, originalUnit ] : symbolsChanged )
825 symbol->SetUnit( originalUnit );
830 m_schematic->CurrentSheet().LastScreen()->TestDanglingEnds( &m_schematic->CurrentSheet(),
831 aChangedItemHandler );
834 item->SetConnectivityDirty(
false );
839 PROF_TIMER build_graph(
"buildConnectionGraph" );
841 buildConnectionGraph( aChangedItemHandler, aUnconditional );
854 const std::set<SCH_ITEM*> &aItems )
856 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> retvals;
857 std::set<CONNECTION_SUBGRAPH*> subgraphs;
862 while( aSubgraph->m_absorbed_by )
864 wxASSERT( aSubgraph->m_graph == aSubgraph->m_absorbed_by->m_graph );
865 aSubgraph = aSubgraph->m_absorbed_by;
869 while( aSubgraph->m_hier_parent )
871 wxASSERT( aSubgraph->m_graph == aSubgraph->m_hier_parent->m_graph );
872 aSubgraph = aSubgraph->m_hier_parent;
876 aSubgraph->getAllConnectedItems( retvals, subgraphs );
879 auto extract_element = [&](
SCH_ITEM* aItem )
885 wxLogTrace(
ConnTrace, wxT(
"Item %s not found in connection graph" ), aItem->GetTypeDesc() );
890 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld (%p) has no driver" ),
891 aItem->GetTypeDesc(), item_sg->
m_code, item_sg );
896 if( sg_to_scan.empty() )
898 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld with net %s has no neighbors" ),
900 sg_to_scan.push_back( item_sg );
904 wxT(
"Removing all item %s connections from subgraph %ld with net %s: Found "
912 traverse_subgraph( sg );
914 for(
auto& bus_it : sg->m_bus_neighbors )
917 traverse_subgraph( bus_sg );
920 for(
auto& bus_it : sg->m_bus_parents )
923 traverse_subgraph( bus_sg );
937 extract_element(
pin );
944 extract_element(
pin );
948 extract_element( item );
954 for(
const auto& [
path, item] : retvals )
981 wxLogTrace(
ConnTrace, wxT(
"Removing %zu subgraphs" ), aSubgraphs.size() );
984 std::set<int> codes_to_remove;
988 std::sort( el.second.begin(), el.second.end() );
993 for(
auto& it : sg->m_bus_neighbors )
999 for(
auto test = parents.begin();
test != parents.end(); )
1007 if( parents.empty() )
1012 for(
auto& it : sg->m_bus_parents )
1018 for(
auto test = neighbors.begin();
test != neighbors.end(); )
1026 if( neighbors.empty() )
1047 auto it = std::lower_bound( el.second.begin(), el.second.end(), sg );
1049 while( it != el.second.end() && *it == sg )
1050 it = el.second.erase( it );
1053 auto remove_sg = [sg](
auto it ) ->
bool
1066 if( remove_sg( it ) )
1074 if( remove_sg( it ) )
1083 if( remove_sg( it ) )
1085 codes_to_remove.insert( it->first.Netcode );
1095 if( remove_sg( it ) )
1103 if( it->second == sg )
1114 if( codes_to_remove.contains( it->second ) )
1122 if( codes_to_remove.contains( it->second ) )
1131 sg->m_graph =
nullptr;
1138 const std::vector<SCH_ITEM*>& aItemList )
1140 wxLogTrace( wxT(
"Updating connectivity for sheet %s with %zu items" ),
1142 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
1146 aConn->SetType( CONNECTION_TYPE::NET );
1155 aConn->SetName(
name );
1162 std::vector<VECTOR2I> points = item->GetConnectionPoints();
1163 item->ClearConnectedItems( aSheet );
1169 pin->InitializeConnection( aSheet,
this );
1171 pin->ClearConnectedItems( aSheet );
1173 connection_map[
pin->GetTextPos() ].push_back(
pin );
1185 updatePin(
pin, conn );
1186 connection_map[
pin->GetPosition() ].push_back(
pin );
1192 SCH_CONNECTION* conn = item->InitializeConnection( aSheet,
this );
1195 switch( item->Type() )
1199 CONNECTION_TYPE::NET );
1203 conn->
SetType( CONNECTION_TYPE::BUS );
1211 if( points.empty() )
1212 points = {
static_cast<SCH_PIN*
>( item )->GetPosition() };
1214 updatePin(
static_cast<SCH_PIN*
>( item ), conn );
1218 conn->
SetType( CONNECTION_TYPE::NET );
1228 for(
const VECTOR2I& point : points )
1229 connection_map[ point ].push_back( item );
1233 for(
const auto& it : connection_map )
1235 std::vector<SCH_ITEM*> connection_vec = it.second;
1236 std::sort( connection_vec.begin(), connection_vec.end() );
1242 std::mutex update_mutex;
1244 auto update_lambda = [&](
SCH_ITEM* connected_item ) ->
size_t
1258 if( connection_vec.size() == 1 )
1271 if( connection_vec.size() < 2 )
1277 if( it.first == bus_entry->GetPosition() )
1280 bus_entry->m_connected_bus_items[1] = busLine;
1282 std::lock_guard<std::mutex> lock( update_mutex );
1295 for(
SCH_ITEM* test_item : connection_vec )
1297 bool bus_connection_ok =
true;
1299 if( test_item == connected_item )
1305 if( test_item->GetLayer() ==
LAYER_BUS )
1324 if( connected_item->ConnectionPropagatesTo( test_item ) &&
1325 test_item->ConnectionPropagatesTo( connected_item ) &&
1328 connected_item->AddConnectionTo( aSheet, test_item );
1339 if( !bus_entry->m_connected_bus_item )
1345 bus_entry->m_connected_bus_item = bus;
1354 tp.push_loop( connection_vec.size(),
1355 [&](
const int a,
const int b)
1357 for( int ii = a; ii < b; ++ii )
1358 update_lambda( connection_vec[ii] );
1360 tp.wait_for_tasks();
1368 wxCHECK_RET(
m_schematic, wxS(
"Connection graph cannot be built without schematic pointer" ) );
1374 for(
const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
1381 for(
const auto& it : item->m_connection_map )
1398 std::list<SCH_ITEM*> memberlist;
1403 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet,
this );
1404 bool unique = !( aItem->GetFlags() &
CANDIDATE );
1409 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
1412 std::copy_if( item->ConnectedItems( sheet ).begin(),
1413 item->ConnectedItems( sheet ).end(),
1414 std::back_inserter( memberlist ), get_items );
1416 for(
SCH_ITEM* connected_item : memberlist )
1421 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
1423 wxASSERT( connected_conn );
1429 subgraph->
AddItem( connected_item );
1430 const SCH_ITEM_VEC& citemset = connected_item->ConnectedItems( sheet );
1437 if( get_items( citem ) )
1438 memberlist.push_back( citem );
1443 for(
SCH_ITEM* connected_item : memberlist )
1444 connected_item->ClearFlags(
CANDIDATE );
1457 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
1462 return candidate->m_dirty;
1465 wxLogTrace(
ConnTrace, wxT(
"Resolving drivers for %zu subgraphs" ), dirty_graphs.size() );
1467 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
1471 if( !subgraph->m_dirty )
1475 for(
SCH_ITEM* item : subgraph->m_items )
1477 switch( item->
Type() )
1480 subgraph->m_no_connect = item;
1484 subgraph->m_bus_entry = item;
1491 if(
pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
1492 subgraph->m_no_connect = item;
1502 subgraph->ResolveDrivers(
true );
1503 subgraph->m_dirty =
false;
1510 tp.push_loop( dirty_graphs.size(),
1511 [&](
const int a,
const int b)
1513 for( int ii = a; ii < b; ++ii )
1514 update_lambda( dirty_graphs[ii] );
1516 tp.wait_for_tasks();
1523 return candidate->m_driver;
1536 wxString full_name = subgraph->m_driver_connection->Name();
1537 wxString
name = subgraph->m_driver_connection->Name(
true );
1544 if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1546 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
1550 subgraph->m_dirty =
true;
1552 if( subgraph->m_strong_driver )
1554 SCH_ITEM* driver = subgraph->m_driver;
1557 switch( driver->
Type() )
1573 wxASSERT(
pin->IsGlobalPower() );
1581 wxLogTrace(
ConnTrace, wxS(
"Unexpected strong driver %s" ),
1593 std::vector<CONNECTION_SUBGRAPH*> new_subgraphs;
1604 dummy.SetGraph(
this );
1607 wxLogTrace(
ConnTrace, wxS(
"new bus label (%s)" ),
1610 for(
const auto& conn :
dummy.Members() )
1612 wxString
name = conn->FullLocalName();
1622 new_conn->
SetType( CONNECTION_TYPE::NET );
1623 subgraph->StoreImplicitConnection( new_conn );
1626 wxLogTrace(
ConnTrace, wxS(
"SG(%ld), Adding full local name (%s) with sg (%d) "
1628 subgraph->m_code,
name, code, subgraph->m_sheet.PathHumanReadable() );
1641 new_subgraphs.push_back( new_sg );
1646 std::copy( new_subgraphs.begin(), new_subgraphs.end(),
1657 std::unordered_map<int, CONNECTION_SUBGRAPH*> global_power_pin_subgraphs;
1664 if( !
pin->ConnectedItems( sheet ).empty() && !
pin->GetLibPin()->GetParentSymbol()->IsPower() )
1679 if(
pin->GetLibPin()->GetParentSymbol()->IsPower() )
1680 connection->
SetName(
pin->GetParentSymbol()->GetValue(
true, &sheet,
false ) );
1689 auto jj = global_power_pin_subgraphs.find( code );
1691 if( jj != global_power_pin_subgraphs.end() )
1693 subgraph = jj->second;
1711 global_power_pin_subgraphs[code] = subgraph;
1728 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1732 if( subgraph->m_absorbed )
1737 wxString
name = connection->
Name();
1740 unsigned suffix = 1;
1742 auto create_new_name =
1746 wxString suffixStr = std::to_wstring( suffix );
1751 if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1753 wxString prefix = aConn->BusPrefix();
1755 if( prefix.empty() )
1756 prefix = wxT(
"BUS" );
1758 wxString oldName = aConn->Name().AfterFirst(
'{' );
1760 newName << prefix << wxT(
"_" ) << suffixStr << wxT(
"{" ) << oldName;
1762 aConn->ConfigureFromLabel( newName );
1766 newName << aConn->Name() << wxT(
"_" ) << suffixStr;
1767 aConn->SetSuffix( wxString( wxT(
"_" ) ) << suffixStr );
1774 if( !subgraph->m_strong_driver )
1776 std::vector<CONNECTION_SUBGRAPH*> vec_empty;
1777 std::vector<CONNECTION_SUBGRAPH*>* vec = &vec_empty;
1784 if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1786 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1792 if( vec->size() > 1 )
1794 wxString new_name = create_new_name( connection );
1797 new_name = create_new_name( connection );
1800 wxS(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
1801 subgraph->m_code,
name, new_name );
1809 else if( subgraph->m_driver )
1821 bool conflict =
false;
1822 wxString global_name = connection->
Name(
true );
1829 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1833 if( candidate->m_sheet == sheet )
1841 wxS(
"%ld (%s) skipped for promotion due to potential "
1843 subgraph->m_code,
name );
1850 wxS(
"%ld (%s) weakly driven by unique sheet pin %s, "
1852 subgraph->m_code,
name,
1853 subgraph->m_driver->GetItemDescription( &unitsProvider,
true ) );
1855 subgraph->m_strong_driver =
true;
1862 if( connection->
IsBus() )
1886 subgraph->m_dirty =
true;
1894 if( !subgraph->m_strong_driver )
1901 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1904 std::back_inserter( candidate_subgraphs ),
1907 return ( !candidate->m_absorbed &&
1908 candidate->m_strong_driver &&
1909 candidate != subgraph );
1915 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1918 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1920 auto add_connections_to_check =
1923 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
1925 if( possible_driver == aSubgraph->m_driver )
1932 if( c->Type() != aSubgraph->m_driver_connection->Type() )
1935 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
1938 connections_to_check.push_back( c );
1940 wxS(
"%lu (%s): Adding secondary driver %s" ),
1942 aSubgraph->m_driver_connection->Name(
true ),
1951 add_connections_to_check( subgraph );
1953 std::set<SCH_CONNECTION*> checked_connections;
1955 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
1957 auto member = connections_to_check[i];
1960 if( !checked_connections.insert( member.get() ).second )
1963 if( member->IsBus() )
1965 connections_to_check.insert( connections_to_check.end(),
1966 member->Members().begin(),
1967 member->Members().end() );
1970 wxString test_name = member->Name(
true );
1974 if( candidate->
m_absorbed || candidate == subgraph )
1990 if( driver == candidate->
m_driver )
2001 if(
pin->IsGlobalPower()
2002 &&
pin->GetDefaultNetName( sheet ) == test_name )
2014 if( subgraph->GetNameForDriver( driver ) == test_name )
2027 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has bus child %lu (%s)" ),
2028 subgraph->m_code, connection->
Name(),
2029 candidate->
m_code, member->Name() );
2031 subgraph->m_bus_neighbors[member].insert( candidate );
2036 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) absorbs neighbor %lu (%s)" ),
2037 subgraph->m_code, connection->
Name(),
2041 add_connections_to_check( candidate );
2043 subgraph->Absorb( candidate );
2044 invalidated_subgraphs.insert( subgraph );
2054 if( subgraph->m_absorbed )
2057 if( !subgraph->ResolveDrivers() )
2060 if( subgraph->m_driver_connection->IsBus() )
2065 wxLogTrace(
ConnTrace, wxS(
"Re-resolving drivers for %lu (%s)" ), subgraph->m_code,
2066 subgraph->m_driver_connection->Name() );
2087 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
2093 for(
const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
2097 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
2117 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
2121 proc_sub_graph.
Show();
2130 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
2132 std::back_inserter( global_subgraphs ),
2135 return !candidate->m_local_driver;
2147 [&](
const int a,
const int b)
2149 for( int ii = a; ii < b; ++ii )
2150 m_driver_subgraphs[ii]->UpdateItemConnections();
2152 tp.wait_for_tasks();
2159 if( !subgraph->m_dirty )
2162 wxLogTrace(
ConnTrace, wxS(
"Processing %lu (%s) for propagation" ), subgraph->m_code,
2163 subgraph->m_driver_connection->Name() );
2169 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
2171 for(
SCH_ITEM* driver : subgraph->m_drivers )
2173 if( driver == subgraph->m_driver )
2176 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
2178 if( secondary_name == subgraph->m_driver_connection->Name() )
2186 if( candidate == subgraph )
2189 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
2194 if( conn->
Name() == secondary_name )
2196 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) promoted to %s" ),
2198 subgraph->m_driver_connection->Name() );
2200 conn->
Clone( *subgraph->m_driver_connection );
2219 if( subgraph->m_dirty )
2235 wxASSERT_MSG( !subgraph->m_dirty,
2236 wxS(
"Subgraph not processed by propagateToNeighbors!" ) );
2238 if( subgraph->m_bus_parents.size() < 2 )
2243 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has multiple bus parents" ),
2244 subgraph->m_code, conn->
Name() );
2246 wxASSERT( conn->
IsNet() );
2248 for(
const auto& ii : subgraph->m_bus_parents )
2261 wxLogTrace(
ConnTrace, wxS(
"Warning: could not match %s inside %lu (%s)" ),
2266 if( conn->
Name() != match->
Name() )
2268 wxString old_name = match->
Name();
2270 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ),
2272 old_name, conn->
Name() );
2274 match->
Clone( *conn );
2293 auto updateItemConnectionsTask =
2297 if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
2298 subgraph->m_driver->Type() ==
SCH_PIN_T )
2301 wxString
name =
pin->GetDefaultNetName( subgraph->m_sheet,
true );
2303 subgraph->m_driver_connection->ConfigureFromLabel(
name );
2306 subgraph->m_dirty =
false;
2307 subgraph->UpdateItemConnections();
2310 if( subgraph->m_driver_connection->IsBus() )
2315 if( subgraph->m_driver && subgraph->m_driver->Type() ==
SCH_SHEET_PIN_T )
2321 wxString pinText =
pin->GetShownText(
false );
2328 if( label->
GetShownText( &subgraph->m_sheet,
false ) == pinText )
2331 path.push_back( sheet );
2335 if( parent_conn && parent_conn->
IsBus() )
2336 subgraph->m_driver_connection->
SetType( CONNECTION_TYPE::BUS );
2342 if( subgraph->m_driver_connection->IsBus() )
2351 [&](
const int a,
const int b)
2353 for(
int ii = a; ii < b; ++ii )
2356 tp.wait_for_tasks();
2364 subgraph->m_driver_connection->NetCode() };
2371 std::map<wxString, wxString> oldAssignments = netSettings->m_NetClassLabelAssignments;
2372 std::set<wxString> affectedNetclassNetAssignments;
2374 netSettings->m_NetClassLabelAssignments.clear();
2380 std::unordered_set<wxString> netclassAssignedFromBus;
2382 auto dirtySubgraphs =
2383 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2385 if( aChangedItemHandler )
2389 for(
SCH_ITEM* item : subgraph->m_items )
2390 (*aChangedItemHandler)( item );
2395 auto checkNetclassDrivers =
2396 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2401 wxCHECK_RET( !subgraphs.empty(), wxS(
"Invalid empty subgraph" ) );
2405 for(
SCH_ITEM* item : subgraph->m_items )
2407 const std::vector<std::pair<wxString, SCH_ITEM*>> netclassesWithProviders =
2408 subgraph->GetNetclassesForDriver( item,
false );
2410 if( netclassesWithProviders.size() > 0 )
2412 netclass = netclassesWithProviders[0].first;
2417 if( !netclass.IsEmpty() )
2419 driverSubgraph = subgraph;
2424 if( !driverSubgraph )
2425 driverSubgraph = subgraphs.front();
2427 const wxString netname = driverSubgraph->
GetNetName();
2432 auto processBusMember = [&,
this](
const SCH_CONNECTION* member )
2434 if( !netclass.IsEmpty() )
2436 netSettings->m_NetClassLabelAssignments[member->Name()] = netclass;
2437 netclassAssignedFromBus.insert( member->Name() );
2442 if( oldAssignments.count( member->Name() ) )
2444 if( oldAssignments[member->Name()] != netclass )
2446 affectedNetclassNetAssignments.insert( member->Name() );
2449 dirtySubgraphs( ii->second );
2452 else if( !netclass.IsEmpty() )
2454 affectedNetclassNetAssignments.insert( member->Name() );
2457 dirtySubgraphs( ii->second );
2461 for(
const std::shared_ptr<SCH_CONNECTION>& member :
2467 if( member->IsBus() )
2469 for(
const std::shared_ptr<SCH_CONNECTION>& nestedMember :
2472 processBusMember( nestedMember.get() );
2477 processBusMember( member.get() );
2485 if( !netclassAssignedFromBus.count( netname ) )
2487 if( !netclass.IsEmpty() )
2489 netSettings->m_NetClassLabelAssignments[netname] = netclass;
2492 if( oldAssignments.count( netname ) )
2494 if( oldAssignments[netname] != netclass )
2496 affectedNetclassNetAssignments.insert( netname );
2497 dirtySubgraphs( subgraphs );
2500 else if( !netclass.IsEmpty() )
2502 affectedNetclassNetAssignments.insert( netname );
2503 dirtySubgraphs( subgraphs );
2509 checkNetclassDrivers( subgraphs );
2511 if( !aUnconditional )
2513 for(
auto& [ netname, netclass ] : oldAssignments )
2515 if( netSettings->m_NetClassLabelAssignments.count( netname )
2516 || affectedNetclassNetAssignments.count( netname ) )
2521 netSettings->m_NetClassLabelAssignments[ netname ] = netclass;
2559 std::vector<std::shared_ptr<SCH_CONNECTION>> connections_to_check( aConnection->
Members() );
2561 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2563 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
2565 if( member->IsBus() )
2567 connections_to_check.insert( connections_to_check.end(),
2568 member->Members().begin(),
2569 member->Members().end() );
2581 std::vector<CONNECTION_SUBGRAPH*> search_list;
2582 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
2583 std::unordered_set<SCH_CONNECTION*> stale_bus_members;
2590 path.push_back(
pin->GetParent() );
2601 || visited.contains( candidate ) )
2610 wxLogTrace(
ConnTrace, wxS(
"%lu: found child %lu (%s)" ), aParent->m_code,
2616 wxASSERT( candidate->
m_graph == aParent->m_graph );
2618 search_list.push_back( candidate );
2638 || visited.contains( candidate )
2644 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
2649 if(
pin->GetParent()->m_Uuid != last_parent_uuid )
2655 if( pin_path != aParent->m_sheet )
2660 wxLogTrace(
ConnTrace, wxS(
"%lu: found additional parent %lu (%s)" ),
2661 aParent->m_code, candidate->
m_code,
2664 aParent->m_hier_children.insert( candidate );
2665 search_list.push_back( candidate );
2675 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
2717 wxLogTrace(
ConnTrace, wxS(
"Could not match bus member %s in %s" ),
2718 kv.first->Name(), parent->
Name() );
2723 auto neighbor_name = neighbor_conn->
Name();
2726 if( neighbor_name == member->
Name() )
2730 if( neighbor_conn->Sheet() != neighbor->
m_sheet )
2734 wxASSERT( neighbor_conn->IsNet() );
2736 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) connected to bus member %s (local %s)" ),
2743 member->
Clone( *neighbor_conn );
2744 stale_bus_members.insert( member );
2748 neighbor_conn->Clone( *member );
2762 propagate_bus_neighbors( aSubgraph );
2769 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has both hier ports and pins; deferring processing" ),
2776 wxS(
"%lu (%s) has no hier pins or ports on sheet %s; marking clean" ),
2782 visited.insert( aSubgraph );
2784 wxLogTrace(
ConnTrace, wxS(
"Propagating %lu (%s) to subsheets" ),
2789 for(
unsigned i = 0; i < search_list.size(); i++ )
2791 auto child = search_list[i];
2793 if( visited.insert( child ).second )
2796 child->m_dirty =
false;
2811 if( subgraph == aSubgraph )
2818 wxString candidateName = subgraph->m_driver_connection->Name();
2819 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
2820 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
2830 ( !bestIsStrong && candidateStrong ) ||
2831 ( priority > highest && candidateStrong ) ||
2832 ( priority == highest && candidateStrong && shorterPath ) ||
2833 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
2834 ( candidateName < bestName ) ) )
2836 bestDriver = subgraph;
2838 bestIsStrong = candidateStrong;
2839 bestName = candidateName;
2844 if( bestDriver != aSubgraph )
2846 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) overridden by new driver %lu (%s)" ),
2855 wxString old_name = subgraph->m_driver_connection->
Name();
2857 subgraph->m_driver_connection->Clone( *conn );
2859 if( old_name != conn->
Name() )
2863 propagate_bus_neighbors( subgraph );
2869 if( conn->
IsBus() && !stale_bus_members.empty() )
2871 std::unordered_set<SCH_CONNECTION*> cached_members = stale_bus_members;
2882 wxLogTrace(
ConnTrace, wxS(
"WARNING: failed to match stale member %s in %s." ),
2883 stale_member->Name(), subgraph->m_driver_connection->Name() );
2887 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
2888 subgraph->m_driver_connection->Name(), member->
LocalName(),
2889 stale_member->Name() );
2891 member->
Clone( *stale_member );
2893 propagate_bus_neighbors( subgraph );
2905 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
2907 switch( aItem->
Type() )
2913 if(
pin->IsGlobalPower() )
2914 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2923 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2933 c->SetGraph(
this );
2944 wxASSERT( aBusConnection->
IsBus() );
2948 if( aBusConnection->
Type() == CONNECTION_TYPE::BUS )
2953 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
2955 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
2957 match = bus_member.get();
2965 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
2970 if( c->Type() == CONNECTION_TYPE::BUS )
2972 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
2974 if( bus_member->LocalName() == aSearch->
LocalName() )
2976 match = bus_member.get();
2981 else if( c->LocalName() == aSearch->
LocalName() )
2994 const wxString& aOldName )
3000 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
3004 wxLogTrace(
ConnTrace, wxS(
"recacheSubgraphName: %s => %s" ), aOldName,
3021 std::vector<const CONNECTION_SUBGRAPH*> ret;
3026 wxASSERT( !subgraph->m_dirty );
3028 if( !subgraph->m_driver )
3034 if( !connection->
IsBus() )
3037 auto labels = subgraph->GetVectorBusLabels();
3039 if( labels.size() > 1 )
3041 bool different =
false;
3042 wxString first =
static_cast<SCH_TEXT*
>( labels.at( 0 ) )->GetShownText( sheet,
false );
3044 for(
unsigned i = 1; i < labels.size(); ++i )
3056 wxLogTrace(
ConnTrace, wxS(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
3057 connection->
Name() );
3059 ret.push_back( subgraph );
3080 if( graph == aSubGraph )
3121 wxASSERT( !it->second.empty() );
3123 return it->second[0];
3139const std::vector<CONNECTION_SUBGRAPH*>
3142 std::vector<CONNECTION_SUBGRAPH*> subgraphs;
3155 int error_count = 0;
3157 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
3163 std::set<SCH_ITEM*> seenDriverInstances;
3168 wxCHECK2( subgraph,
continue );
3171 wxASSERT( !subgraph->m_dirty );
3173 if( subgraph->m_absorbed )
3176 if( seenDriverInstances.count( subgraph->m_driver ) )
3179 if( subgraph->m_driver )
3180 seenDriverInstances.insert( subgraph->m_driver );
3198 subgraph->ResolveDrivers(
false );
3267 wxCHECK( aSubgraph,
false );
3273 if( driver == aSubgraph->
m_driver )
3285 if( primaryName == secondaryName )
3288 wxString msg = wxString::Format(
_(
"Both %s and %s are attached to the same "
3289 "items; %s will be used in the netlist" ),
3290 primaryName, secondaryName, primaryName );
3293 ercItem->SetItems( aSubgraph->
m_driver, driver );
3294 ercItem->SetSheetSpecificPath( aSubgraph->
GetSheet() );
3295 ercItem->SetItemsSheetPaths( aSubgraph->
GetSheet(), aSubgraph->
m_sheet );
3296 ercItem->SetErrorMessage( msg );
3312 wxString firstNetclass;
3313 SCH_ITEM* firstNetclassDriver =
nullptr;
3315 bool conflictFound =
false;
3319 for(
SCH_ITEM* item : subgraph->m_items )
3321 const std::vector<std::pair<wxString, SCH_ITEM*>> netclassesWithProvider =
3322 subgraph->GetNetclassesForDriver( item,
true );
3324 if( netclassesWithProvider.size() == 0 )
3327 auto checkNetclass = [&](
const std::pair<wxString, SCH_ITEM*>& netclass )
3329 if( netclass.first != firstNetclass )
3331 if( !firstNetclassDriver )
3333 firstNetclass = netclass.first;
3334 firstNetclassDriver = netclass.second;
3335 firstNetclassDriverSheet = &subgraph->
GetSheet();
3339 conflictFound =
true;
3341 std::shared_ptr<ERC_ITEM> ercItem =
3343 ercItem->SetItems( firstNetclassDriver, netclass.second );
3344 ercItem->SetSheetSpecificPath( subgraph->GetSheet() );
3345 ercItem->SetItemsSheetPaths( *firstNetclassDriverSheet,
3349 new SCH_MARKER( ercItem, netclass.second->GetPosition() );
3350 subgraph->m_sheet.LastScreen()->Append( marker );
3355 for(
const std::pair<wxString, SCH_ITEM*>& netclass : netclassesWithProvider )
3356 checkNetclass( netclass );
3360 return conflictFound;
3375 switch( item->
Type() )
3380 bus_item = ( !bus_item ) ? item : bus_item;
3382 net_item = ( !net_item ) ? item : net_item;
3397 bus_item = ( !bus_item ) ? item : bus_item;
3399 net_item = ( !net_item ) ? item : net_item;
3409 if( net_item && bus_item )
3412 ercItem->SetSheetSpecificPath( sheet );
3413 ercItem->SetItems( net_item, bus_item );
3416 screen->
Append( marker );
3435 switch( item->
Type() )
3466 if(
test != member && member->Name() ==
test->Name() )
3480 ercItem->SetSheetSpecificPath( sheet );
3481 ercItem->SetItems( label, port );
3484 screen->
Append( marker );
3496 bool conflict =
false;
3512 switch( item->
Type() )
3542 std::set<wxString> test_names;
3552 if( member->Type() == CONNECTION_TYPE::BUS )
3554 for(
const auto& sub_member : member->Members() )
3556 if( test_names.count( sub_member->FullLocalName() ) )
3560 else if( test_names.count( member->FullLocalName() ) )
3579 wxString msg = wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
3580 " member of that bus" ),
3584 ercItem->SetSheetSpecificPath( sheet );
3585 ercItem->SetItems( bus_entry, bus_wire );
3586 ercItem->SetErrorMessage( msg );
3589 screen->
Append( marker );
3606 std::set<SCH_PIN*> unique_pins;
3607 std::set<SCH_LABEL_BASE*> unique_labels;
3615 for(
SCH_ITEM* item : aProcessGraph->m_items )
3617 switch( item->
Type() )
3624 if( aProcessGraph == aSubgraph )
3627 if( std::none_of( unique_pins.begin(), unique_pins.end(),
3634 unique_pins.insert( test_pin );
3657 process_subgraph( subgraph );
3662 process_subgraph( aSubgraph );
3687 ercItem->SetSheetSpecificPath( sheet );
3688 ercItem->SetItemsSheetPaths( sheet );
3695 pos =
pin->GetPosition();
3704 screen->
Append( marker );
3709 if( unique_pins.empty() && unique_labels.empty() &&
3714 ercItem->SetSheetSpecificPath( sheet );
3715 ercItem->SetItemsSheetPaths( sheet );
3718 screen->
Append( marker );
3725 bool has_other_connections =
false;
3726 std::vector<SCH_PIN*> pins;
3733 switch( item->
Type() )
3742 for(
SCH_PIN* other_pin : pins )
3746 has_other_connections =
true;
3752 pins.emplace_back(
static_cast<SCH_PIN*
>( item ) );
3759 has_other_connections =
true;
3766 pin = pins.empty() ? nullptr : pins[0];
3769 for(
SCH_PIN* test_pin : pins )
3774 if( test_pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
3775 && !test_pin->IsGlobalPower() )
3786 if(
pin && !has_other_connections
3787 && !
pin->IsGlobalPower()
3788 && !
pin->GetLibPin()->GetParentSymbol()->IsPower() )
3790 wxString
name =
pin->Connection( &sheet )->Name();
3791 wxString local_name =
pin->Connection( &sheet )->Name(
true );
3796 has_other_connections =
true;
3801 if(
pin && !has_other_connections
3802 &&
pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
3803 &&
pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
3807 ercItem->SetSheetSpecificPath( sheet );
3808 ercItem->SetItemsSheetPaths( sheet );
3809 ercItem->SetItems(
pin );
3812 screen->
Append( marker );
3820 if( pins.size() > 1 )
3822 for(
SCH_PIN* testPin : pins )
3827 if( testPin->GetLibPin()->GetParentSymbol()->IsPower()
3828 && testPin->ConnectedItems( sheet ).empty()
3832 ercItem->SetSheetSpecificPath( sheet );
3833 ercItem->SetItemsSheetPaths( sheet );
3834 ercItem->SetItems( testPin );
3837 screen->
Append( marker );
3855 std::vector<SCH_ITEM*> wires;
3862 wires.emplace_back( item );
3864 wires.emplace_back( item );
3867 if( !wires.empty() )
3872 ercItem->SetSheetSpecificPath( sheet );
3873 ercItem->SetItems( wires[0],
3874 wires.size() > 1 ? wires[1] :
nullptr,
3875 wires.size() > 2 ? wires[2] :
nullptr,
3876 wires.size() > 3 ? wires[3] :
nullptr );
3879 screen->
Append( marker );
3907 size_t pinCount = 0;
3910 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
3916 return std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(),
3919 return item->Type() == SCH_PIN_T;
3924 [&](
SCH_TEXT* aText,
int errCode )
3929 ercItem->SetSheetSpecificPath( sheet );
3930 ercItem->SetItems( aText );
3937 pinCount =
hasPins( aSubgraph );
3941 switch( item->
Type() )
3949 label_map[item->
Type()].push_back(
text );
3954 if(
text->IsDangling() )
3968 if( label_map.empty() )
3973 for(
auto& [ connection, subgraphs ] : aSubgraph->
m_bus_parents )
3977 if( busParent->m_no_connect )
4000 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
4007 for(
auto& [type, label_vec] : label_map )
4025 size_t allPins = pinCount;
4033 if( neighbor == aSubgraph )
4039 allPins +=
hasPins( neighbor );
4043 if( allPins == 1 && !has_nc )
4067 std::map<wxString, std::tuple<int, const SCH_ITEM*, SCH_SHEET_PATH>> labelData;
4074 wxString resolvedLabelText =
4077 if( labelData.find( resolvedLabelText ) == labelData.end() )
4079 labelData[resolvedLabelText] = { 1, item, sheet };
4083 std::get<0>( labelData[resolvedLabelText] ) += 1;
4084 std::get<1>( labelData[resolvedLabelText] ) =
nullptr;
4085 std::get<2>( labelData[resolvedLabelText] ) = sheet;
4090 for(
const auto& label : labelData )
4092 if( std::get<0>( label.second ) == 1 )
4095 const SCH_ITEM* item = std::get<1>( label.second );
4098 ercItem->SetItems( std::get<1>( label.second ) );
4099 ercItem->SetSheetSpecificPath( sheet );
4100 ercItem->SetItemsSheetPaths( sheet );
4126 parentSheetPath.
push_back( parentSheet );
4128 std::map<wxString, SCH_SHEET_PIN*> pins;
4129 std::map<wxString, SCH_HIERLABEL*> labels;
4134 pins[
pin->GetShownText( &parentSheetPath,
false ) ] =
pin;
4139 ercItem->SetItems(
pin );
4140 ercItem->SetSheetSpecificPath( sheet );
4141 ercItem->SetItemsSheetPaths( sheet );
4144 sheet.LastScreen()->Append( marker );
4152 std::set<wxString> matchedPins;
4159 wxString labelText = label->
GetShownText( &parentSheetPath,
false );
4161 if( !pins.count( labelText ) )
4162 labels[ labelText ] = label;
4164 matchedPins.insert( labelText );
4168 for(
const wxString& matched : matchedPins )
4169 pins.erase( matched );
4171 for(
const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
4173 wxString msg = wxString::Format(
_(
"Sheet pin %s has no matching hierarchical "
4174 "label inside the sheet" ),
4178 ercItem->SetItems( unmatched.second );
4179 ercItem->SetErrorMessage( msg );
4180 ercItem->SetSheetSpecificPath( sheet );
4181 ercItem->SetItemsSheetPaths( sheet );
4184 sheet.LastScreen()->Append( marker );
4189 for(
const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
4191 wxString msg = wxString::Format(
_(
"Hierarchical label %s has no matching "
4192 "sheet pin in the parent sheet" ),
4196 ercItem->SetItems( unmatched.second );
4197 ercItem->SetErrorMessage( msg );
4198 ercItem->SetSheetSpecificPath( parentSheetPath );
4199 ercItem->SetItemsSheetPaths( parentSheetPath );
constexpr EDA_IU_SCALE schIUScale
Calculate the connectivity of a schematic and generates netlists.
int RunERC()
Run electrical rule checks on the connectivity graph.
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for conflicting connections between two bus items.
void processSubGraphs()
Process all subgraphs to assign netcodes and merge subgraphs based on labels.
bool ercCheckNetclassConflicts(const std::vector< CONNECTION_SUBGRAPH * > &subgraphs)
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for proper connection of labels.
void RemoveItem(SCH_ITEM *aItem)
void collectAllDriverValues()
Map the driver values for each subgraph.
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Return the subgraph for a given net name on a given sheet.
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
Cache to lookup subgraphs in m_driver_subgraphs by sheet path.
CONNECTION_SUBGRAPH * FindFirstSubgraphByName(const wxString &aNetName)
Retrieve a subgraph for the given net name, if one exists.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph, bool aForce)
Update all neighbors of a subgraph with this one's connectivity info.
void buildItemSubGraphs()
Generate individual item subgraphs on a per-sheet basis.
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
SCH_SHEET_LIST m_sheetList
All the sheets in the schematic (as long as we don't have partial updates).
void generateGlobalPowerPinSubGraphs()
Iterate through the global power pins to collect the global labels as drivers.
const std::vector< CONNECTION_SUBGRAPH * > GetAllSubgraphs(const wxString &aNetName) const
std::unordered_map< wxString, int > m_net_name_to_code_map
int ercCheckSingleGlobalLabel()
Check that a global label is instantiated more that once across the schematic heirarchy.
int ercCheckHierSheets()
Check that a hierarchical sheet has at least one matching label inside the sheet for each port on the...
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for conflicting connections between net and bus labels.
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Build a new default connection for the given item based on its properties.
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration()
Determine which subgraphs have more than one conflicting bus label.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
int getOrCreateNetCode(const wxString &aNetName)
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensure all members of the bus connection have a valid net code assigned.
std::unordered_map< wxString, int > m_bus_name_to_code_map
std::unordered_map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
The owner of all CONNECTION_SUBGRAPH objects.
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_global_power_pins
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for proper presence or absence of no-connect symbols.
size_t hasPins(const CONNECTION_SUBGRAPH *aLocSubgraph)
Get the number of pins in a given subgraph.
std::vector< SCH_ITEM * > m_items
All connectable items in the schematic.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::shared_ptr< BUS_ALIAS > GetBusAlias(const wxString &aName)
Return a bus alias pointer for the given name if it exists (from cache)
void removeSubgraphs(std::set< CONNECTION_SUBGRAPH * > &aSubgraphs)
Remove references to the given subgraphs from all structures in the connection graph.
std::unordered_map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
std::set< std::pair< SCH_SHEET_PATH, SCH_ITEM * > > ExtractAffectedItems(const std::set< SCH_ITEM * > &aItems)
For a set of items, this will remove the connected items and their associated data including subgraph...
wxString GetResolvedSubgraphName(const CONNECTION_SUBGRAPH *aSubGraph) const
Return the fully-resolved netname for a given subgraph.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for conflicting bus entry to bus connections.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
Cache of a subset of m_subgraphs.
void ExchangeItem(SCH_ITEM *aOldItem, SCH_ITEM *aNewItem)
Replace all references to #aOldItem with #aNewItem in the graph.
NET_MAP m_net_code_to_subgraphs_map
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for floating wires.
void buildConnectionGraph(std::function< void(SCH_ITEM *)> *aChangedItemHandler, bool aUnconditional)
Generate the connection graph (after all item connectivity has been updated).
void Merge(CONNECTION_GRAPH &aGraph)
Combine the input graph contents into the current graph.
void resolveAllDrivers()
Find all subgraphs in the connection graph and calls ResolveDrivers() in parallel.
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Update the graphical connectivity between items (i.e.
CONNECTION_SUBGRAPH * GetSubgraphForItem(SCH_ITEM *aItem) const
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
Update the connection graph for the given list of sheets.
void generateBusAliasMembers()
Iterate through labels to create placeholders for bus elements.
A subgraph is a set of items that are electrically connected on a single sheet.
wxString driverName(SCH_ITEM *aItem) const
PRIORITY GetDriverPriority()
bool m_strong_driver
True if the driver is "strong": a label or power object.
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::set< CONNECTION_SUBGRAPH * > m_absorbed_subgraphs
Set of subgraphs that have been absorbed by this subgraph.
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
SCH_SHEET_PATH m_sheet
On which logical sheet is the subgraph contained.
void UpdateItemConnections()
Update all items to match the driver connection.
std::set< SCH_SHEET_PIN * > m_hier_pins
Cache for lookup of any hierarchical (sheet) pins on this subgraph (for referring down).
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...
CONNECTION_GRAPH * m_graph
std::vector< SCH_ITEM * > GetAllBusLabels() const
Return all the all bus labels attached to this subgraph (if any).
std::unordered_map< SCH_ITEM *, wxString > m_driver_name_cache
A cache of escaped netnames from schematic items.
const wxString & GetNameForDriver(SCH_ITEM *aItem) const
Return the candidate net name for a driver.
wxString GetNetName() const
Return the fully-qualified net name for this subgraph (if one exists)
std::vector< SCH_ITEM * > GetVectorBusLabels() const
Return all the vector-based bus labels attached to this subgraph (if any).
const SCH_SHEET_PATH & GetSheet() const
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determine which potential driver should drive the subgraph.
std::set< SCH_ITEM * > m_drivers
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
std::unordered_set< CONNECTION_SUBGRAPH * > m_hier_children
If not null, this indicates the subgraph(s) on a lower level sheet that are linked to this one.
void AddItem(SCH_ITEM *aItem)
Add a new item to the subgraph.
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combine another subgraph on the same sheet into this one.
std::set< SCH_ITEM * > m_items
Contents of the subgraph.
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.
SCH_ITEM * m_driver
Fully-resolved driver for the subgraph (might not exist in this subgraph).
std::mutex m_driver_mutex
bool m_is_bus_member
True if the subgraph is not actually part of a net.
void ExchangeItem(SCH_ITEM *aOldItem, SCH_ITEM *aNewItem)
Replaces all references to #aOldItem with #aNewItem in the subgraph.
CONNECTION_SUBGRAPH * m_hier_parent
If not null, this indicates the subgraph on a higher level sheet that is linked to this one.
void RemoveItem(SCH_ITEM *aItem)
const std::vector< std::pair< wxString, SCH_ITEM * > > GetNetclassesForDriver(SCH_ITEM *aItem, bool returnAll) const
Return the resolved netclasses for the item, and the source item providing the netclass.
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::set< SCH_HIERLABEL * > m_hier_ports
Cache for lookup of any hierarchical ports on this subgraph (for referring up).
void getAllConnectedItems(std::set< std::pair< SCH_SHEET_PATH, SCH_ITEM * > > &aItems, std::set< CONNECTION_SUBGRAPH * > &aSubgraphs)
Find all items in the subgraph as well as child subgraphs recursively.
virtual VECTOR2I GetPosition() const
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
KICAD_T Type() const
Returns the type of object.
EE_TYPE OfType(KICAD_T aType) const
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Container for ERC settings.
bool IsTestEnabled(int aErrorCode) const
A small class to help profiling.
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
virtual PROJECT_FILE & GetProjectFile() const
SCH_SHEET_PATH & CurrentSheet() const override
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
ERC_SETTINGS & ErcSettings() const
Class for a bus to bus entry.
SCH_ITEM * m_connected_bus_items[2]
Pointer to the bus items (usually bus wires) connected to this bus-bus entry (either or both may be n...
VECTOR2I GetPosition() const override
Class for a wire to bus entry.
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 ...
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString FullLocalName() const
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
void SetSubgraphCode(int aCode)
void SetBusCode(int aCode)
void SetName(const wxString &aName)
CONNECTION_TYPE Type() const
void SetNetCode(int aCode)
SCH_ITEM * m_driver
The SCH_ITEM that drives this connection's net.
bool IsDriver() const
Checks if the SCH_ITEM this connection is attached to can drive connections Drivers can be labels,...
void SetType(CONNECTION_TYPE aType)
wxString LocalName() const
wxString Name(bool aIgnoreSheet=false) const
bool IsSubsetOf(SCH_CONNECTION *aOther) const
Returns true if this connection is contained within aOther (but not the same as aOther)
void SetDriver(SCH_ITEM *aItem)
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
void SetGraph(CONNECTION_GRAPH *aGraph)
const std::vector< std::shared_ptr< SCH_CONNECTION > > & Members() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
void ClearConnectedItems(const SCH_SHEET_PATH &aPath)
Clear all connections to this item.
const SYMBOL * GetParentSymbol() const
virtual const wxString & GetCachedDriverName() const
const std::unordered_set< SCH_RULE_AREA * > & GetRuleAreaCache() const
Gets the cache of rule areas enclosing this item.
void AddConnectionTo(const SCH_SHEET_PATH &aPath, SCH_ITEM *aItem)
Add a connection link between this item and another.
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction)
void SetConnectionGraph(CONNECTION_GRAPH *aGraph)
Updates the connection graph for all connections in this item.
virtual bool HasCachedDriverName() const
SCH_CONNECTION * GetOrInitConnection(const SCH_SHEET_PATH &aPath, CONNECTION_GRAPH *aGraph)
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
LABEL_FLAG_SHAPE GetShape() const
Segment description base class to describe items which have 2 end points (track, wire,...
bool IsGlobalPower() const
Return whether this pin forms a global power connection: i.e., is part of a power symbol and of type ...
SCH_PIN * GetLibPin() const
bool IsStacked(const SCH_PIN *aPin) const
wxString GetDefaultNetName(const SCH_SHEET_PATH &aPath, bool aForceNoConnect=false)
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
const SCH_SHEET * GetSheet(unsigned aIndex) const
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
SCH_SCREEN * LastScreen()
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
wxString GetFileName() const
Return the filename corresponding to this sheet.
SCH_SCREEN * GetScreen() const
std::vector< SCH_SHEET_PIN * > & GetPins()
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
VECTOR2I GetPosition() const override
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
bool GetExcludedFromBoard() const
virtual bool IsPower() const =0
#define CANDIDATE
flag indicating that the structure is connected
@ ERCE_DRIVER_CONFLICT
Conflicting drivers (labels, etc) on a subgraph.
@ ERCE_LABEL_NOT_CONNECTED
Label not connected to anything.
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
@ ERCE_BUS_ENTRY_CONFLICT
A wire connected to a bus doesn't match the bus.
@ ERCE_NETCLASS_CONFLICT
Multiple labels assign different netclasses to same net.
@ ERCE_GLOBLABEL
A global label is unique.
@ ERCE_BUS_TO_NET_CONFLICT
A bus wire is graphically connected to a net port/pin (or vice versa).
@ ERCE_NOCONNECT_NOT_CONNECTED
A no connect symbol is not connected to anything.
@ ERCE_PIN_NOT_CONNECTED
Pin not connected and not no connect symbol.
@ ERCE_NOCONNECT_CONNECTED
A no connect symbol is connected to more than 1 pin.
@ ERCE_HIERACHICAL_LABEL
Mismatch between hierarchical labels and pins sheets.
@ ERCE_WIRE_DANGLING
Some wires are not connected to anything else.
@ ERCE_SINGLE_GLOBAL_LABEL
A global label only exists once in the schematic.
static const wxChar DanglingProfileMask[]
Flag to enable connectivity profiling.
static const wxChar ConnTrace[]
Flag to enable connectivity tracing.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
std::vector< SCH_ITEM * > SCH_ITEM_VEC
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
BS::thread_pool thread_pool
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Functions to provide common constants and other functions to assist in making a consistent UI.