27#include <unordered_map>
108 if( old_conn && new_conn )
110 new_conn->
Clone( *old_conn );
140 std::vector<SCH_ITEM*> candidates;
141 std::set<SCH_ITEM*> strong_drivers;
165 strong_drivers.insert( item );
167 if( item_priority > highest_priority )
170 candidates.push_back( item );
171 highest_priority = item_priority;
173 else if( !candidates.empty() && ( item_priority == highest_priority ) )
175 candidates.push_back( item );
185 if( !candidates.empty() )
219 if( aGlobal != bGlobal )
225 if( aLocal != bLocal )
246 bool a_lowQualityName = a_name.Contains(
"-Pad" );
247 bool b_lowQualityName = b_name.Contains(
"-Pad" );
249 if( a_lowQualityName != b_lowQualityName )
250 return !a_lowQualityName;
252 return a_name < b_name;
255 std::sort( candidates.begin(), candidates.end(), candidate_cmp );
260 if( strong_drivers.size() > 1 )
267 m_drivers.insert( strong_drivers.begin(), strong_drivers.end() );
289 std::set<CONNECTION_SUBGRAPH*>& aSubgraphs )
301 if( aSubgraphs.insert( sg ).second ==
false )
307 aItems.emplace(
m_sheet, item );
321#ifdef CONNECTIVITY_DEBUG
322 wxASSERT_MSG(
false, wxS(
"Tried to get the net name of an item with no connection" ) );
334 std::vector<SCH_ITEM*> labels;
338 switch( item->Type() )
348 labels.push_back( item );
364 std::vector<SCH_ITEM*> labels;
368 switch( item->Type() )
378 labels.push_back( item );
394 switch( aItem->
Type() )
401 return pin->GetDefaultNetName(
m_sheet, forceNoConnect );
428 wxFAIL_MSG( wxS(
"Unhandled item type in GetNameForDriver" ) );
429 return wxEmptyString;
449const std::vector<std::pair<wxString, SCH_ITEM*>>
452 std::vector<std::pair<wxString, SCH_ITEM*>> foundNetclasses;
454 const std::unordered_set<SCH_RULE_AREA*>& ruleAreaCache = aItem->
GetRuleAreaCache();
459 const std::vector<std::pair<wxString, SCH_ITEM*>> ruleAreaNetclasses =
460 ruleArea->GetResolvedNetclasses( &
m_sheet );
462 if( ruleAreaNetclasses.size() > 0 )
464 foundNetclasses.insert( foundNetclasses.end(), ruleAreaNetclasses.begin(),
465 ruleAreaNetclasses.end() );
481 if( netclass != wxEmptyString )
482 foundNetclasses.push_back( { netclass, aItem } );
489 foundNetclasses.begin(), foundNetclasses.end(),
490 [](
const std::pair<wxString, SCH_ITEM*>& i1,
const std::pair<wxString, SCH_ITEM*>& i2 )
492 return i1.first < i2.first;
495 return foundNetclasses;
521 child->m_absorbed_by =
this;
524 set_absorbed_by( subchild );
532 set_absorbed_by( aOther );
585 if(
const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef() )
586 return part->GetReferenceField().GetText();
588 return wxEmptyString;
591 switch( aDriver->
Type() )
622 std::back_inserter(
m_items ) );
677 wxCHECK2( aOldItem->
Type() == aNewItem->
Type(),
return );
712 wxCHECK2( oldPins.size() == newPins.size(),
return );
714 for(
size_t ii = 0; ii < oldPins.size(); ii++ )
716 exchange( oldPins[ii], newPins[ii] );
727 if( subgraph->m_graph ==
this )
751 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler,
755 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
756 monitorTrans.
Start();
761 monitorTrans.
StartSpan(
"updateItemConnectivity",
"" );
762 PROF_TIMER update_items(
"updateItemConnectivity" );
765 std::set<SCH_ITEM*> dirty_items;
767 int count = aSheetList.size() * 2;
772 if( aProgressReporter )
778 std::vector<SCH_ITEM*> items;
781 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
783 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
785 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
787 wxLogTrace(
ConnTrace, wxT(
"Adding item %s to connectivity graph update" ),
788 item->GetTypeDesc() );
789 items.push_back( item );
790 dirty_items.insert( item );
799 if(
pin->IsConnectivityDirty() )
801 dirty_items.insert(
pin );
814 if(
pin->IsConnectivityDirty() )
816 items.push_back(
pin );
817 dirty_items.insert(
pin );
827 if(
pin->IsConnectivityDirty() )
829 items.push_back(
pin );
830 dirty_items.insert(
pin );
843 if( symbol->
GetUnit() != new_unit )
844 symbolsChanged.push_back( { symbol, symbol->
GetUnit() } );
854 if( aProgressReporter )
861 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
864 for(
const auto& [ symbol, originalUnit ] : symbolsChanged )
865 symbol->SetUnit( originalUnit );
876 item->SetConnectivityDirty(
false );
883 PROF_TIMER build_graph(
"buildConnectionGraph" );
884 monitorTrans.
StartSpan(
"BuildConnectionGraph",
"" );
903 const std::set<SCH_ITEM*> &aItems )
905 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> retvals;
906 std::set<CONNECTION_SUBGRAPH*> subgraphs;
911 while( aSubgraph->m_absorbed_by )
914 wxASSERT( aSubgraph->m_graph == aSubgraph->m_absorbed_by->m_graph );
915 aSubgraph = aSubgraph->m_absorbed_by;
919 while( aSubgraph->m_hier_parent )
922 wxASSERT( aSubgraph->m_graph == aSubgraph->m_hier_parent->m_graph );
923 aSubgraph = aSubgraph->m_hier_parent;
927 aSubgraph->getAllConnectedItems( retvals, subgraphs );
930 auto extract_element = [&](
SCH_ITEM* aItem )
936 wxLogTrace(
ConnTrace, wxT(
"Item %s not found in connection graph" ),
937 aItem->GetTypeDesc() );
943 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld (%p) has no driver" ),
944 aItem->GetTypeDesc(), item_sg->
m_code, item_sg );
949 if( sg_to_scan.empty() )
951 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld with net %s has no neighbors" ),
953 sg_to_scan.push_back( item_sg );
957 wxT(
"Removing all item %s connections from subgraph %ld with net %s: Found "
964 traverse_subgraph( sg );
966 for(
auto& bus_it : sg->m_bus_neighbors )
969 traverse_subgraph( bus_sg );
972 for(
auto& bus_it : sg->m_bus_parents )
975 traverse_subgraph( bus_sg );
989 extract_element(
pin );
996 extract_element(
pin );
1000 extract_element( item );
1006 for(
const auto& [
path, item] : retvals )
1033 wxLogTrace(
ConnTrace, wxT(
"Removing %zu subgraphs" ), aSubgraphs.size() );
1036 std::set<int> codes_to_remove;
1040 std::sort( el.second.begin(), el.second.end() );
1045 for(
auto& it : sg->m_bus_neighbors )
1051 for(
auto test = parents.begin();
test != parents.end(); )
1059 if( parents.empty() )
1064 for(
auto& it : sg->m_bus_parents )
1070 for(
auto test = neighbors.begin();
test != neighbors.end(); )
1078 if( neighbors.empty() )
1099 auto it = std::lower_bound( el.second.begin(), el.second.end(), sg );
1101 while( it != el.second.end() && *it == sg )
1102 it = el.second.erase( it );
1105 auto remove_sg = [sg](
auto it ) ->
bool
1118 if( remove_sg( it ) )
1126 if( remove_sg( it ) )
1135 if( remove_sg( it ) )
1137 codes_to_remove.insert( it->first.Netcode );
1149 if( remove_sg( it ) )
1157 if( it->second == sg )
1168 if( codes_to_remove.contains( it->second ) )
1176 if( codes_to_remove.contains( it->second ) )
1185 sg->m_graph =
nullptr;
1192 std::map<
VECTOR2I, std::vector<SCH_ITEM*>>& aConnectionMap )
1203 aConn->SetName(
name );
1208 std::map<wxString, std::vector<SCH_PIN*>> pinNumberMap;
1214 updatePin(
pin, conn );
1215 aConnectionMap[
pin->GetPosition() ].push_back(
pin );
1216 pinNumberMap[
pin->GetNumber()].emplace_back(
pin );
1219 auto linkPinsInVec =
1220 [&](
const std::vector<SCH_PIN*>& aVec )
1222 for(
size_t i = 0; i < aVec.size(); ++i )
1224 for(
size_t j = i + 1; j < aVec.size(); ++j )
1226 aVec[i]->AddConnectionTo( aSheet, aVec[j] );
1227 aVec[j]->AddConnectionTo( aSheet, aVec[i] );
1236 for(
const auto& [number,
group] : pinNumberMap )
1237 linkPinsInVec(
group );
1242 std::vector<SCH_PIN*> pins;
1244 for(
const wxString& pinNumber :
group )
1245 pins.emplace_back( aSymbol->
GetPin( pinNumber ) );
1247 linkPinsInVec( pins );
1270 std::map<
VECTOR2I, std::vector<SCH_ITEM*>>& aConnectionMap )
1275 m_items.emplace_back( aItem );
1278 switch( aItem->
Type() )
1291 if( points.empty() )
1292 points = {
static_cast<SCH_PIN*
>( aItem )->GetPosition() };
1305 for(
const VECTOR2I& point : points )
1306 aConnectionMap[point].push_back( aItem );
1311 const std::vector<SCH_ITEM*>& aItemList )
1313 wxLogTrace( wxT(
"Updating connectivity for sheet %s with %zu items" ),
1315 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
1319 std::vector<VECTOR2I> points = item->GetConnectionPoints();
1320 item->ClearConnectedItems( aSheet );
1326 pin->InitializeConnection( aSheet,
this );
1328 pin->ClearConnectedItems( aSheet );
1330 connection_map[
pin->GetTextPos() ].push_back(
pin );
1347 VECTOR2I point = item->GetPosition();
1350 std::vector<SCH_ITEM*> overlapping_items;
1352 std::copy_if( items.begin(), items.end(), std::back_inserter( overlapping_items ),
1355 return test_item->Type() == SCH_LINE_T
1356 && test_item->HitTest( point, -1 );
1361 if( overlapping_items.size() < 2 )
continue;
1363 for(
SCH_ITEM* test_item : overlapping_items )
1364 connection_map[point].push_back( test_item );
1369 for(
auto& [point, connection_vec] : connection_map )
1371 std::sort( connection_vec.begin(), connection_vec.end() );
1377 for(
SCH_ITEM* connected_item : connection_vec )
1391 if( connection_vec.size() == 1 )
1407 if( point == bus_entry->GetPosition() )
1410 bus_entry->m_connected_bus_items[1] = busLine;
1423 for(
SCH_ITEM* test_item : connection_vec )
1425 bool bus_connection_ok =
true;
1427 if( test_item == connected_item )
1433 if( test_item->GetLayer() ==
LAYER_BUS )
1452 if( connected_item->ConnectionPropagatesTo( test_item )
1453 && test_item->ConnectionPropagatesTo( connected_item )
1454 && bus_connection_ok )
1456 connected_item->AddConnectionTo( aSheet, test_item );
1467 if( !bus_entry->m_connected_bus_item )
1473 bus_entry->m_connected_bus_item = bus;
1484 wxCHECK_RET(
m_schematic, wxS(
"Connection graph cannot be built without schematic pointer" ) );
1488 for(
const std::shared_ptr<BUS_ALIAS>& alias :
m_schematic->GetAllBusAliases() )
1497 for(
const auto& [sheet, connection] : item->m_connection_map )
1499 if( connection->SubgraphCode() == 0 )
1508 connection->SetSubgraphCode( subgraph->
m_code );
1511 std::list<SCH_ITEM*> memberlist;
1516 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet,
this );
1522 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
1525 std::copy_if( item->ConnectedItems( sheet ).begin(),
1526 item->ConnectedItems( sheet ).end(),
1527 std::back_inserter( memberlist ), get_items );
1529 for(
SCH_ITEM* connected_item : memberlist )
1534 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
1536 wxCHECK2( connected_conn,
continue );
1542 subgraph->
AddItem( connected_item );
1543 const SCH_ITEM_VEC& citemset = connected_item->ConnectedItems( sheet );
1550 if( get_items( citem ) )
1551 memberlist.push_back( citem );
1556 for(
SCH_ITEM* connected_item : memberlist )
1570 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
1575 return candidate->m_dirty;
1578 wxLogTrace(
ConnTrace, wxT(
"Resolving drivers for %zu subgraphs" ), dirty_graphs.size() );
1580 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
1582 auto update_lambda =
1585 if( !subgraph->m_dirty )
1589 for(
SCH_ITEM* item : subgraph->m_items )
1591 switch( item->
Type() )
1594 subgraph->m_no_connect = item;
1598 subgraph->m_bus_entry = item;
1606 subgraph->m_no_connect = item;
1616 subgraph->ResolveDrivers(
true );
1617 subgraph->m_dirty =
false;
1624 auto results =
tp.submit_loop( 0, dirty_graphs.size(),
1627 update_lambda( dirty_graphs[ii] );
1636 return candidate->m_driver;
1649 wxString full_name = subgraph->m_driver_connection->Name();
1650 wxString
name = subgraph->m_driver_connection->Name(
true );
1659 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
1663 subgraph->m_dirty =
true;
1665 if( subgraph->m_strong_driver )
1667 SCH_ITEM* driver = subgraph->m_driver;
1670 switch( driver->
Type() )
1686 if(
pin->IsGlobalPower() )
1690 else if(
pin->IsLocalPower() )
1697 wxLogTrace(
ConnTrace, wxS(
"Unexpected normal pin %s" ),
1707 wxLogTrace(
ConnTrace, wxS(
"Unexpected strong driver %s" ),
1719 std::vector<CONNECTION_SUBGRAPH*> new_subgraphs;
1730 dummy.SetGraph(
this );
1733 wxLogTrace(
ConnTrace, wxS(
"new bus label (%s)" ),
1736 for(
const auto& conn :
dummy.Members() )
1739 if( !conn->IsNet() )
1742 wxString
name = conn->FullLocalName();
1753 subgraph->StoreImplicitConnection( new_conn );
1756 wxLogTrace(
ConnTrace, wxS(
"SG(%ld), Adding full local name (%s) with sg (%d) on subsheet %s" ),
1757 subgraph->m_code,
name, code, subgraph->m_sheet.PathHumanReadable() );
1770 new_subgraphs.push_back( new_sg );
1775 std::copy( new_subgraphs.begin(), new_subgraphs.end(),
1787 std::unordered_map<int, CONNECTION_SUBGRAPH*> global_power_pin_subgraphs;
1791 if( !
pin->ConnectedItems( sheet ).empty()
1792 && !
pin->GetLibPin()->GetParentSymbol()->IsGlobalPower() )
1807 if(
pin->GetLibPin()->GetParentSymbol()->IsGlobalPower() )
1808 connection->
SetName(
pin->GetParentSymbol()->GetValue(
true, &sheet,
false ) );
1817 auto jj = global_power_pin_subgraphs.find( code );
1819 if( jj != global_power_pin_subgraphs.end() )
1821 subgraph = jj->second;
1839 global_power_pin_subgraphs[code] = subgraph;
1856 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1860 if( subgraph->m_absorbed )
1865 wxString
name = connection->
Name();
1868 unsigned suffix = 1;
1870 auto create_new_name =
1874 wxString suffixStr = std::to_wstring( suffix );
1881 wxString prefix = aConn->BusPrefix();
1883 if( prefix.empty() )
1884 prefix = wxT(
"BUS" );
1886 wxString oldName = aConn->Name().AfterFirst(
'{' );
1888 newName << prefix << wxT(
"_" ) << suffixStr << wxT(
"{" ) << oldName;
1890 aConn->ConfigureFromLabel( newName );
1894 newName << aConn->Name() << wxT(
"_" ) << suffixStr;
1895 aConn->SetSuffix( wxString( wxT(
"_" ) ) << suffixStr );
1902 if( !subgraph->m_strong_driver )
1904 std::vector<CONNECTION_SUBGRAPH*> vec_empty;
1905 std::vector<CONNECTION_SUBGRAPH*>* vec = &vec_empty;
1914 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1920 if( vec->size() > 1 )
1922 wxString new_name = create_new_name( connection );
1925 new_name = create_new_name( connection );
1927 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
1928 subgraph->m_code,
name, new_name );
1930 std::erase( *vec, subgraph );
1936 else if( subgraph->m_driver )
1948 bool conflict =
false;
1949 wxString global_name = connection->
Name(
true );
1956 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1960 if( candidate->m_sheet == sheet )
1967 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) skipped for promotion due to potential conflict" ),
1968 subgraph->m_code,
name );
1974 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) weakly driven by unique sheet pin %s, promoting" ),
1975 subgraph->m_code,
name,
1976 subgraph->m_driver->GetItemDescription( &unitsProvider,
true ) );
1978 subgraph->m_strong_driver =
true;
1985 if( connection->
IsBus() )
2009 subgraph->m_dirty =
true;
2017 if( !subgraph->m_strong_driver )
2024 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
2027 std::back_inserter( candidate_subgraphs ),
2030 return ( !candidate->m_absorbed &&
2031 candidate->m_strong_driver &&
2032 candidate != subgraph );
2038 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
2041 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
2043 auto add_connections_to_check =
2046 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
2048 if( possible_driver == aSubgraph->m_driver )
2055 if( c->Type() != aSubgraph->m_driver_connection->Type() )
2058 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
2061 connections_to_check.push_back( c );
2062 wxLogTrace(
ConnTrace, wxS(
"%lu (%s): Adding secondary driver %s" ),
2064 aSubgraph->m_driver_connection->Name(
true ),
2073 add_connections_to_check( subgraph );
2075 std::set<SCH_CONNECTION*> checked_connections;
2077 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2079 auto member = connections_to_check[i];
2082 if( !checked_connections.insert( member.get() ).second )
2085 if( member->IsBus() )
2087 connections_to_check.insert( connections_to_check.end(),
2088 member->Members().begin(),
2089 member->Members().end() );
2092 wxString test_name = member->Name(
true );
2096 if( candidate->
m_absorbed || candidate == subgraph )
2112 if( driver == candidate->
m_driver )
2124 &&
pin->GetDefaultNetName( sheet ) == test_name )
2137 if( subgraph->GetNameForDriver( driver ) == test_name )
2150 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has bus child %lu (%s)" ),
2151 subgraph->m_code, connection->
Name(),
2152 candidate->
m_code, member->Name() );
2154 subgraph->m_bus_neighbors[member].insert( candidate );
2157 else if( !connection->
IsBus()
2160 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) absorbs neighbor %lu (%s)" ),
2161 subgraph->m_code, connection->
Name(),
2165 add_connections_to_check( candidate );
2167 subgraph->Absorb( candidate );
2168 invalidated_subgraphs.insert( subgraph );
2178 if( subgraph->m_absorbed )
2181 if( !subgraph->ResolveDrivers() )
2184 if( subgraph->m_driver_connection->IsBus() )
2189 wxLogTrace(
ConnTrace, wxS(
"Re-resolving drivers for %lu (%s)" ),
2190 subgraph->m_code, subgraph->m_driver_connection->Name() );
2209 bool aUnconditional )
2212 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
2216 for(
const std::shared_ptr<BUS_ALIAS>& alias :
m_schematic->GetAllBusAliases() )
2222 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
2241 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
2245 proc_sub_graph.
Show();
2254 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
2256 std::back_inserter( global_subgraphs ),
2259 return !candidate->m_local_driver;
2273 m_driver_subgraphs[ii]->UpdateItemConnections();
2283 if( !subgraph->m_dirty )
2286 wxLogTrace(
ConnTrace, wxS(
"Processing %lu (%s) for propagation" ),
2287 subgraph->m_code, subgraph->m_driver_connection->Name() );
2293 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
2295 for(
SCH_ITEM* driver : subgraph->m_drivers )
2297 if( driver == subgraph->m_driver )
2300 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
2302 if( secondary_name == subgraph->m_driver_connection->Name() )
2310 if( candidate == subgraph )
2313 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
2320 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) promoted to %s" ),
2322 subgraph->m_driver_connection->Name() );
2344 if( subgraph->m_dirty )
2361 wxASSERT_MSG( !subgraph->m_dirty,
2362 wxS(
"Subgraph not processed by propagateToNeighbors!" ) );
2364 if( subgraph->m_bus_parents.size() < 2 )
2369 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has multiple bus parents" ),
2370 subgraph->m_code, conn->
Name() );
2373 wxCHECK2( conn->
IsNet(),
continue );
2375 for(
const auto& ii : subgraph->m_bus_parents )
2388 wxLogTrace(
ConnTrace, wxS(
"Warning: could not match %s inside %lu (%s)" ),
2393 if( conn->
Name() != match->
Name() )
2395 wxString old_name = match->
Name();
2397 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ),
2400 match->
Clone( *conn );
2408 std::vector<CONNECTION_SUBGRAPH*> old_subgraphs = jj->second;
2412 while( old_sg->m_absorbed )
2413 old_sg = old_sg->m_absorbed_by;
2415 wxString old_sg_name = old_sg->m_driver_connection->Name();
2416 old_sg->m_driver_connection->Clone( *conn );
2418 if( old_sg_name != old_sg->m_driver_connection->Name() )
2426 auto updateItemConnectionsTask =
2430 if( !subgraph->m_strong_driver
2431 && subgraph->m_drivers.size() == 1
2432 && subgraph->m_driver->Type() ==
SCH_PIN_T )
2435 wxString
name =
pin->GetDefaultNetName( subgraph->m_sheet,
true );
2437 subgraph->m_driver_connection->ConfigureFromLabel(
name );
2440 subgraph->m_dirty =
false;
2441 subgraph->UpdateItemConnections();
2444 if( subgraph->m_driver_connection->IsBus() )
2449 if( subgraph->m_driver && subgraph->m_driver->Type() ==
SCH_SHEET_PIN_T )
2455 wxString pinText =
pin->GetShownText(
false );
2462 if( label->
GetShownText( &subgraph->m_sheet,
false ) == pinText )
2465 path.push_back( sheet );
2469 if( parent_conn && parent_conn->
IsBus() )
2476 if( subgraph->m_driver_connection->IsBus() )
2487 updateItemConnectionsTask( m_driver_subgraphs[ii] );
2497 subgraph->m_driver_connection->NetCode() };
2503 std::shared_ptr<NET_SETTINGS>& netSettings =
m_schematic->Project().GetProjectFile().m_NetSettings;
2504 std::map<wxString, std::set<wxString>> oldAssignments = netSettings->GetNetclassLabelAssignments();
2505 std::set<wxString> affectedNetclassNetAssignments;
2507 netSettings->ClearNetclassLabelAssignments();
2509 auto dirtySubgraphs =
2510 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2512 if( aChangedItemHandler )
2516 for(
SCH_ITEM* item : subgraph->m_items )
2517 (*aChangedItemHandler)( item );
2522 auto checkNetclassDrivers =
2523 [&](
const wxString& netName,
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2525 wxCHECK_RET( !subgraphs.empty(), wxS(
"Invalid empty subgraph" ) );
2527 std::set<wxString> netclasses;
2532 for(
SCH_ITEM* item : subgraph->m_items )
2534 for(
const auto& [
name, provider] : subgraph->GetNetclassesForDriver( item ) )
2535 netclasses.insert(
name );
2542 if( subgraph->m_driver_connection->IsBus() )
2544 auto processBusMember = [&,
this](
const SCH_CONNECTION* member )
2546 if( !netclasses.empty() )
2548 netSettings->AppendNetclassLabelAssignment( member->Name(), netclasses );
2553 if( oldAssignments.count( member->Name() ) )
2555 if( oldAssignments[member->Name()] != netclasses )
2557 affectedNetclassNetAssignments.insert( member->Name() );
2560 dirtySubgraphs( ii->second );
2563 else if( !netclasses.empty() )
2565 affectedNetclassNetAssignments.insert( member->Name() );
2568 dirtySubgraphs( ii->second );
2572 for(
const std::shared_ptr<SCH_CONNECTION>& member : subgraph->m_driver_connection->Members() )
2576 if( member->IsBus() )
2578 for(
const std::shared_ptr<SCH_CONNECTION>& nestedMember : member->Members() )
2579 processBusMember( nestedMember.get() );
2583 processBusMember( member.get() );
2590 if( !netclasses.empty() )
2592 netSettings->AppendNetclassLabelAssignment( netName, netclasses );
2595 if( oldAssignments.count( netName ) )
2597 if( oldAssignments[netName] != netclasses )
2599 affectedNetclassNetAssignments.insert( netName );
2600 dirtySubgraphs( subgraphs );
2603 else if( !netclasses.empty() )
2605 affectedNetclassNetAssignments.insert( netName );
2606 dirtySubgraphs( subgraphs );
2612 checkNetclassDrivers( netname, subgraphs );
2614 if( !aUnconditional )
2616 for(
auto& [netname, netclasses] : oldAssignments )
2618 if( netSettings->GetNetclassLabelAssignments().count( netname )
2619 || affectedNetclassNetAssignments.count( netname ) )
2624 netSettings->SetNetclassLabelAssignment( netname, netclasses );
2662 std::vector<std::shared_ptr<SCH_CONNECTION>> connections_to_check( aConnection->
Members() );
2664 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2666 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
2668 if( member->IsBus() )
2670 connections_to_check.insert( connections_to_check.end(),
2671 member->Members().begin(),
2672 member->Members().end() );
2684 std::vector<CONNECTION_SUBGRAPH*> search_list;
2685 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
2686 std::unordered_set<SCH_CONNECTION*> stale_bus_members;
2693 path.push_back(
pin->GetParent() );
2704 || visited.contains( candidate ) )
2713 wxLogTrace(
ConnTrace, wxS(
"%lu: found child %lu (%s)" ), aParent->m_code,
2721 wxASSERT( candidate->
m_graph == aParent->m_graph );
2723 search_list.push_back( candidate );
2743 || visited.contains( candidate )
2749 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
2754 if(
pin->GetParent()->m_Uuid != last_parent_uuid )
2760 if( pin_path != aParent->m_sheet )
2765 wxLogTrace(
ConnTrace, wxS(
"%lu: found additional parent %lu (%s)" ),
2768 aParent->m_hier_children.insert( candidate );
2769 search_list.push_back( candidate );
2783 std::vector<std::shared_ptr<SCH_CONNECTION>> sortedMembers;
2785 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
2786 sortedMembers.push_back(
kv.first );
2788 std::sort( sortedMembers.begin(), sortedMembers.end(),
2789 [](
const std::shared_ptr<SCH_CONNECTION>& a,
2790 const std::shared_ptr<SCH_CONNECTION>& b )
2792 return a->Name() < b->Name();
2795 for(
const std::shared_ptr<SCH_CONNECTION>& member_conn : sortedMembers )
2797 const auto& kv_it = aParentGraph->m_bus_neighbors.find( member_conn );
2799 if( kv_it == aParentGraph->m_bus_neighbors.end() )
2842 wxLogTrace(
ConnTrace, wxS(
"Could not match bus member %s in %s" ),
2843 member_conn->Name(), parent->
Name() );
2849 wxCHECK2( neighbor_conn,
continue );
2851 wxString neighbor_name = neighbor_conn->
Name();
2854 if( neighbor_name == member->
Name() )
2864 if( neighbor_conn->
Sheet() != parent->
Sheet() )
2880 wxCHECK2_MSG( neighbor_conn->
IsNet(),
continue,
2881 wxS(
"\"" ) + neighbor_name + wxS(
"\" is not a net." ) );
2883 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) connected to bus member %s (local %s)" ),
2890 member->
Clone( *neighbor_conn );
2891 stale_bus_members.insert( member );
2895 neighbor_conn->
Clone( *member );
2908 if( neighbor_conn->
Name() != member->
Name() )
2910 member->
Clone( *neighbor_conn );
2911 stale_bus_members.insert( member );
2920 propagate_bus_neighbors( aSubgraph );
2927 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has both hier ports and pins; deferring processing" ),
2933 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has no hier pins or ports on sheet %s; marking clean" ),
2939 visited.insert( aSubgraph );
2941 wxLogTrace(
ConnTrace, wxS(
"Propagating %lu (%s) to subsheets" ),
2946 for(
unsigned i = 0; i < search_list.size(); i++ )
2948 auto child = search_list[i];
2950 if( visited.insert( child ).second )
2953 child->m_dirty =
false;
2967 if( subgraph == aSubgraph )
2974 wxString candidateName = subgraph->m_driver_connection->Name();
2975 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
2976 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
2986 ( !bestIsStrong && candidateStrong ) ||
2987 ( priority > highest && candidateStrong ) ||
2988 ( priority == highest && candidateStrong && shorterPath ) ||
2989 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
2990 ( candidateName < bestName ) ) )
2992 bestDriver = subgraph;
2994 bestIsStrong = candidateStrong;
2995 bestName = candidateName;
3000 if( bestDriver != aSubgraph )
3002 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) overridden by new driver %lu (%s)" ),
3011 wxString old_name = subgraph->m_driver_connection->Name();
3013 subgraph->m_driver_connection->Clone( *conn );
3015 if( old_name != conn->
Name() )
3019 propagate_bus_neighbors( subgraph );
3025 if( conn->
IsBus() && !stale_bus_members.empty() )
3027 std::unordered_set<SCH_CONNECTION*> cached_members = stale_bus_members;
3037 wxLogTrace(
ConnTrace, wxS(
"WARNING: failed to match stale member %s in %s." ),
3038 stale_member->Name(), subgraph->m_driver_connection->Name() );
3042 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
3043 subgraph->m_driver_connection->Name(), member->
LocalName(), stale_member->Name() );
3045 member->
Clone( *stale_member );
3047 propagate_bus_neighbors( subgraph );
3059 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
3061 switch( aItem->
Type() )
3064 if(
static_cast<SCH_PIN*
>( aItem )->IsPower() )
3065 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
3072 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
3081 c->SetGraph(
this );
3093 wxASSERT( aBusConnection->
IsBus() );
3102 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
3104 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
3106 match = bus_member.get();
3114 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
3121 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
3123 if( bus_member->LocalName() == aSearch->
LocalName() )
3125 match = bus_member.get();
3130 else if( c->LocalName() == aSearch->
LocalName() )
3148 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
3149 std::erase( vec, aSubgraph );
3152 wxLogTrace(
ConnTrace, wxS(
"recacheSubgraphName: %s => %s" ), aOldName,
3169 std::vector<const CONNECTION_SUBGRAPH*> ret;
3175 wxASSERT( !subgraph->m_dirty );
3177 if( !subgraph->m_driver )
3183 if( !connection->
IsBus() )
3186 auto labels = subgraph->GetVectorBusLabels();
3188 if( labels.size() > 1 )
3190 bool different =
false;
3193 for(
unsigned i = 1; i < labels.size(); ++i )
3205 wxLogTrace(
ConnTrace, wxS(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
3206 connection->
Name() );
3208 ret.push_back( subgraph );
3229 if( graph == aSubGraph )
3272 wxASSERT( !it->second.empty() );
3274 return it->second[0];
3290const std::vector<CONNECTION_SUBGRAPH*>&
3293 static const std::vector<CONNECTION_SUBGRAPH*> subgraphs;
3306 int error_count = 0;
3308 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
3314 std::set<SCH_ITEM*> seenDriverInstances;
3319 wxCHECK2( subgraph,
continue );
3323 wxASSERT( !subgraph->m_dirty );
3325 if( subgraph->m_absorbed )
3328 if( seenDriverInstances.count( subgraph->m_driver ) )
3331 if( subgraph->m_driver )
3332 seenDriverInstances.insert( subgraph->m_driver );
3350 subgraph->ResolveDrivers(
false );
3421 wxCHECK( aSubgraph,
false );
3427 if( driver == aSubgraph->
m_driver )
3438 if( primaryName == secondaryName )
3441 wxString msg = wxString::Format(
_(
"Both %s and %s are attached to the same "
3442 "items; %s will be used in the netlist" ),
3443 primaryName, secondaryName, primaryName );
3446 ercItem->SetItems( aSubgraph->
m_driver, driver );
3447 ercItem->SetSheetSpecificPath( aSubgraph->
GetSheet() );
3448 ercItem->SetItemsSheetPaths( aSubgraph->
GetSheet(), aSubgraph->
m_sheet );
3449 ercItem->SetErrorMessage( msg );
3474 switch( item->
Type() )
3479 bus_item = ( !bus_item ) ? item : bus_item;
3481 net_item = ( !net_item ) ? item : net_item;
3495 bus_item = ( !bus_item ) ? item : bus_item;
3497 net_item = ( !net_item ) ? item : net_item;
3507 if( net_item && bus_item )
3510 ercItem->SetSheetSpecificPath( sheet );
3511 ercItem->SetItems( net_item, bus_item );
3514 screen->
Append( marker );
3533 switch( item->
Type() )
3560 if(
test != member && member->Name() ==
test->Name() )
3574 ercItem->SetSheetSpecificPath( sheet );
3575 ercItem->SetItems( label, port );
3578 screen->
Append( marker );
3590 bool conflict =
false;
3606 switch( item->
Type() )
3636 std::set<wxString> test_names;
3648 for(
const auto& sub_member : member->Members() )
3650 if( test_names.count( sub_member->FullLocalName() ) )
3654 else if( test_names.count( member->FullLocalName() ) )
3673 wxString msg = wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
3674 " member of that bus" ),
3678 ercItem->SetSheetSpecificPath( sheet );
3679 ercItem->SetItems( bus_entry, bus_wire );
3680 ercItem->SetErrorMessage( msg );
3683 screen->
Append( marker );
3700 std::set<SCH_PIN*> unique_pins;
3701 std::set<SCH_LABEL_BASE*> unique_labels;
3709 for(
SCH_ITEM* item : aProcessGraph->m_items )
3711 switch( item->
Type() )
3718 if( aProcessGraph == aSubgraph )
3721 if( std::none_of( unique_pins.begin(), unique_pins.end(),
3724 return test_pin->IsStacked( aPin );
3728 unique_pins.insert( test_pin );
3751 process_subgraph( subgraph );
3756 process_subgraph( aSubgraph );
3791 ercItem->SetSheetSpecificPath( sheet );
3792 ercItem->SetItemsSheetPaths( sheet );
3799 pos =
pin->GetPosition();
3808 screen->
Append( marker );
3813 if( unique_pins.empty() && unique_labels.empty() &&
3818 ercItem->SetSheetSpecificPath( sheet );
3819 ercItem->SetItemsSheetPaths( sheet );
3822 screen->
Append( marker );
3829 bool has_other_connections =
false;
3830 std::vector<SCH_PIN*> pins;
3837 switch( item->
Type() )
3844 if( !has_other_connections && !pins.empty()
3847 for(
SCH_PIN* other_pin : pins )
3851 has_other_connections =
true;
3857 pins.emplace_back(
static_cast<SCH_PIN*
>( item ) );
3864 has_other_connections =
true;
3871 pin = pins.empty() ? nullptr : pins[0];
3874 for(
SCH_PIN* test_pin : pins )
3890 if(
pin && !has_other_connections
3892 && !
pin->GetLibPin()->GetParentSymbol()->IsPower() )
3894 wxString
name =
pin->Connection( &sheet )->Name();
3895 wxString local_name =
pin->Connection( &sheet )->Name(
true );
3900 has_other_connections =
true;
3905 if(
pin && !has_other_connections
3911 ercItem->SetSheetSpecificPath( sheet );
3912 ercItem->SetItemsSheetPaths( sheet );
3913 ercItem->SetItems(
pin );
3916 screen->
Append( marker );
3924 if( pins.size() > 1 )
3926 for(
SCH_PIN* testPin : pins )
3931 if( testPin->GetLibPin()->GetParentSymbol()->IsPower()
3932 && testPin->ConnectedItems( sheet ).empty()
3936 ercItem->SetSheetSpecificPath( sheet );
3937 ercItem->SetItemsSheetPaths( sheet );
3938 ercItem->SetItems( testPin );
3941 screen->
Append( marker );
3974 ercItem->SetItems( line );
3975 ercItem->SetSheetSpecificPath( sheet );
3976 ercItem->SetErrorMessage(
_(
"Unconnected wire endpoint" ) );
3998 ercItem->SetItems( entry );
3999 ercItem->SetSheetSpecificPath( sheet );
4000 ercItem->SetErrorMessage(
_(
"Unconnected wire to bus entry" ) );
4017 return err_count > 0;
4027 std::vector<SCH_ITEM*> wires;
4034 wires.emplace_back( item );
4036 wires.emplace_back( item );
4039 if( !wires.empty() )
4044 ercItem->SetSheetSpecificPath( sheet );
4045 ercItem->SetItems( wires[0],
4046 wires.size() > 1 ? wires[1] :
nullptr,
4047 wires.size() > 2 ? wires[2] :
nullptr,
4048 wires.size() > 3 ? wires[3] :
nullptr );
4051 screen->
Append( marker );
4079 size_t pinCount = 0;
4082 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
4088 return std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(),
4091 return item->Type() == SCH_PIN_T;
4096 [&](
SCH_TEXT* aText,
int errCode )
4101 ercItem->SetSheetSpecificPath( sheet );
4102 ercItem->SetItems( aText );
4109 pinCount =
hasPins( aSubgraph );
4113 switch( item->
Type() )
4121 label_map[item->
Type()].push_back(
text );
4126 if(
text->IsDangling() )
4140 if( label_map.empty() )
4145 for(
auto& [ connection, subgraphs ] : aSubgraph->
m_bus_parents )
4149 if( busParent->m_no_connect )
4172 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
4179 for(
auto& [type, label_vec] : label_map )
4183 size_t allPins = pinCount;
4191 if( neighbor == aSubgraph )
4197 allPins +=
hasPins( neighbor );
4201 if( allPins == 1 && !has_nc )
4223 std::map<wxString, std::tuple<int, const SCH_ITEM*, SCH_SHEET_PATH>> labelData;
4230 wxString resolvedLabelText =
4233 if( labelData.find( resolvedLabelText ) == labelData.end() )
4235 labelData[resolvedLabelText] = { 1, item, sheet };
4239 std::get<0>( labelData[resolvedLabelText] ) += 1;
4240 std::get<1>( labelData[resolvedLabelText] ) =
nullptr;
4241 std::get<2>( labelData[resolvedLabelText] ) = sheet;
4246 for(
const auto& label : labelData )
4248 if( std::get<0>( label.second ) == 1 )
4251 const SCH_ITEM* item = std::get<1>( label.second );
4254 ercItem->SetItems( std::get<1>( label.second ) );
4255 ercItem->SetSheetSpecificPath( sheet );
4256 ercItem->SetItemsSheetPaths( sheet );
4271 int error_count = 0;
4283 ercItem->SetSheetSpecificPath( sheet );
4284 ercItem->SetItems(
text );
4287 sheet.LastScreen()->Append( marker );
4307 if( sheet.Last()->IsTopLevelSheet() )
4313 wxCHECK2( label,
continue );
4315 msg.Printf(
_(
"Hierarchical label '%s' in root sheet cannot be connected to non-existent "
4319 ercItem->SetItems( item );
4320 ercItem->SetErrorMessage( msg );
4323 sheet.LastScreen()->Append( marker );
4334 parentSheetPath.
push_back( parentSheet );
4336 std::map<wxString, SCH_SHEET_PIN*> pins;
4337 std::map<wxString, SCH_HIERLABEL*> labels;
4342 pins[
pin->GetShownText( &parentSheetPath,
false ) ] =
pin;
4347 ercItem->SetItems(
pin );
4348 ercItem->SetSheetSpecificPath( sheet );
4349 ercItem->SetItemsSheetPaths( sheet );
4352 sheet.LastScreen()->Append( marker );
4360 std::set<wxString> matchedPins;
4367 wxString labelText = label->
GetShownText( &parentSheetPath,
false );
4369 if( !pins.contains( labelText ) )
4370 labels[ labelText ] = label;
4372 matchedPins.insert( labelText );
4376 for(
const wxString& matched : matchedPins )
4377 pins.erase( matched );
4379 for(
const auto& [
name,
pin] : pins )
4381 msg.Printf(
_(
"Sheet pin %s has no matching hierarchical label inside the sheet" ),
4385 ercItem->SetItems(
pin );
4386 ercItem->SetErrorMessage( msg );
4387 ercItem->SetSheetSpecificPath( sheet );
4388 ercItem->SetItemsSheetPaths( sheet );
4391 sheet.LastScreen()->Append( marker );
4396 for(
const auto& [
name, label] : labels )
4398 msg.Printf(
_(
"Hierarchical label %s has no matching sheet pin in the parent sheet" ),
4402 ercItem->SetItems( label );
4403 ercItem->SetErrorMessage( msg );
4404 ercItem->SetSheetSpecificPath( parentSheetPath );
4405 ercItem->SetItemsSheetPaths( parentSheetPath );
constexpr EDA_IU_SCALE schIUScale
This represents a sentry transaction which is used for time-performance metrics You start a transacti...
void StartSpan(const std::string &aOperation, const std::string &aDescription)
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 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.
int ercCheckDirectiveLabels()
Check directive labels should be connected to something.
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.
void updateGenericItemConnectivity(const SCH_SHEET_PATH &aSheet, SCH_ITEM *aItem, std::map< VECTOR2I, std::vector< SCH_ITEM * > > &aConnectionMap)
Update the connectivity of items that are not pins or symbols.
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.
void updateSymbolConnectivity(const SCH_SHEET_PATH &aSheet, SCH_SYMBOL *aSymbol, std::map< VECTOR2I, std::vector< SCH_ITEM * > > &aConnectionMap)
Update the connectivity of a symbol and its pins.
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.
const std::vector< CONNECTION_SUBGRAPH * > & GetAllSubgraphs(const wxString &aNetName) const
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.
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 hierarchy.
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.
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
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)
bool ercCheckDanglingWireEndpoints(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for dangling wire endpoints.
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
CONNECTION_GRAPH(SCHEMATIC *aSchematic=nullptr)
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 updatePinConnectivity(const SCH_SHEET_PATH &aSheet, SCH_PIN *aPin, SCH_CONNECTION *aConnection)
Update the connectivity of a pin and its connections.
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 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.
std::mutex m_driver_name_cache_mutex
A cache of escaped netnames from schematic items.
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
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.
const std::vector< std::pair< wxString, SCH_ITEM * > > GetNetclassesForDriver(SCH_ITEM *aItem) const
Return the resolved netclasses for the item, and the source item providing the netclass.
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).
CONNECTION_SUBGRAPH(CONNECTION_GRAPH *aGraph)
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)
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 Overlapping(const BOX2I &aRect) const
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
bool GetDuplicatePinNumbersAreJumpers() const
std::vector< std::set< wxString > > & JumperPinGroups()
Each jumper pin group is a set of pin numbers that should be treated as internally connected.
A small class to help profiling.
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
void Stop()
Save the time when this function was called, and set the counter stane to stop.
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
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...
bool IsStartDangling() const
VECTOR2I GetPosition() const override
bool IsEndDangling() const
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
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)
SCH_SHEET_PATH Sheet() const
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
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) 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.
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
const SYMBOL * GetParentSymbol() const
virtual const wxString & GetCachedDriverName() const
const std::unordered_set< SCH_RULE_AREA * > & GetRuleAreaCache() const
Get the cache of rule areas enclosing this item.
SCH_CONNECTION * InitializeConnection(const SCH_SHEET_PATH &aPath, CONNECTION_GRAPH *aGraph)
Create a new connection object associated with this object.
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.
void SetConnectionGraph(CONNECTION_GRAPH *aGraph)
Update the connection graph for all connections in this item.
virtual void SetUnit(int aUnit)
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.
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
bool IsDangling() const override
LABEL_FLAG_SHAPE GetShape() const
Segment description base class to describe items which have 2 end points (track, wire,...
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
bool IsStartDangling() const
bool IsEndDangling() const
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
bool IsGlobalPower() const
Return whether this pin forms a global power connection: i.e., is part of a power symbol and of type ...
bool IsLocalPower() const
Local power pin is the same except that it is sheet-local and it does not support the legacy hidden p...
SCH_PIN * GetLibPin() const
bool IsStacked(const SCH_PIN *aPin) const
wxString GetDefaultNetName(const SCH_SHEET_PATH &aPath, bool aForceNoConnect=false)
bool IsPower() const
Check if the pin is either a global or local power pin.
ELECTRICAL_PINTYPE GetType() const
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr, std::function< void(SCH_ITEM *)> *aChangedHandler=nullptr) const
Test all of the connectable objects in the schematic for unused connection points.
EE_RTREE & Items()
Get 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) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
VECTOR2I GetPosition() const override
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
virtual bool IsGlobalPower() const =0
virtual bool IsLocalPower() const =0
virtual bool IsPower() const =0
#define CONNECTIVITY_CANDIDATE
flag indicating that the structure is connected for connectivity
@ ERCE_DRIVER_CONFLICT
Conflicting drivers (labels, etc) on a subgraph.
@ ERCE_UNCONNECTED_WIRE_ENDPOINT
A label is connected to more than one wire.
@ ERCE_LABEL_NOT_CONNECTED
Label not connected to any pins.
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
@ ERCE_LABEL_SINGLE_PIN
A label is connected only to a single pin.
@ ERCE_BUS_ENTRY_CONFLICT
A wire connected to a bus doesn't match the bus.
@ 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 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 remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
@ PT_NC
not connected (must be left open)
@ PT_NIC
not internally connected (may be connected to anything)
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ BUS
This item represents a bus vector.
@ NET
This item represents a net.
@ BUS_GROUP
This item represents a bus group.
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:...
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< int32_t > VECTOR2I