28 #include <unordered_map> 66 std::vector<SCH_ITEM*> candidates;
67 std::vector<SCH_ITEM*> strong_drivers;
83 && !static_cast<SCH_PIN*>( item )->GetParentSymbol()->IsInNetlist() )
87 strong_drivers.push_back( item );
89 if( item_priority > highest_priority )
92 candidates.push_back( item );
93 highest_priority = item_priority;
95 else if( !candidates.empty() && ( item_priority == highest_priority ) )
97 candidates.push_back( item );
107 if( !candidates.empty() )
109 if( candidates.size() > 1 )
130 void* previousDriver =
nullptr;
136 if( mc->GetLastDriver() )
138 previousDriver = mc->GetLastDriver();
145 std::sort( candidates.begin(), candidates.end(),
159 if( a == previousDriver )
161 else if( b == previousDriver )
173 if( strong_drivers.size() > 1 )
200 for(
unsigned i = 1; i < candidates.size(); i++ )
204 second_item = candidates[i];
228 #ifdef CONNECTIVITY_DEBUG 229 wxASSERT_MSG(
false,
"Tried to get the net name of an item with no connection" );
241 std::vector<SCH_ITEM*> labels;
245 switch( item->Type() )
254 labels.push_back( item );
269 switch( aItem->
Type() )
274 SCH_PIN* pin = static_cast<SCH_PIN*>( aItem );
289 wxFAIL_MSG(
"Unhandled item type in GetNameForDriver" );
293 return wxEmptyString;
352 m_hier_pins.push_back( static_cast<SCH_SHEET_PIN*>( aItem ) );
354 m_hier_ports.push_back( static_cast<SCH_HIERLABEL*>( aItem ) );
390 switch( aDriver->
Type() )
398 auto sch_pin = static_cast<SCH_PIN*>( aDriver );
400 if( sch_pin->IsPowerConnection() )
439 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler )
441 PROF_COUNTER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
452 std::vector<SCH_ITEM*> items;
454 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
456 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
457 items.push_back( item );
465 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
485 const double max_recalc_time_msecs = 250.;
488 recalc_time.
msecs() > max_recalc_time_msecs )
497 const std::vector<SCH_ITEM*>& aItemList )
499 std::map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
503 std::vector< wxPoint > points = item->GetConnectionPoints();
504 item->ConnectedItems( aSheet ).clear();
508 for(
SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
510 pin->InitializeConnection( aSheet,
this );
512 pin->ConnectedItems( aSheet ).clear();
514 connection_map[ pin->GetTextPos() ].push_back( pin );
520 SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
524 pin->InitializeConnection( aSheet,
this );
526 wxPoint pos = pin->GetPosition();
529 pin->GetDefaultNetName( aSheet );
530 pin->ConnectedItems( aSheet ).clear();
534 if( pin->IsPowerConnection() && !pin->IsVisible() )
537 connection_map[ pos ].push_back( pin );
544 auto conn = item->InitializeConnection( aSheet,
this );
547 switch( item->Type() )
557 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] =
nullptr;
558 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] =
nullptr;
568 static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item =
nullptr;
575 for(
const wxPoint& point : points )
576 connection_map[ point ].push_back( item );
579 item->SetConnectivityDirty(
false );
582 for(
const auto& it : connection_map )
584 auto connection_vec = it.second;
586 for(
auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ )
588 SCH_ITEM* connected_item = *primary_it;
602 if( connection_vec.size() == 1 )
609 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
610 bus_entry->m_connected_bus_item = bus;
618 if( connection_vec.size() < 2 )
625 auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
627 if( it.first == bus_entry->GetPosition() )
628 bus_entry->m_connected_bus_items[0] = bus;
630 bus_entry->m_connected_bus_items[1] = bus;
647 for(
auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ )
649 auto test_item = *test_it;
651 if( connected_item != test_item &&
653 test_item->ConnectionPropagatesTo( connected_item ) )
656 test_item->ConnectedItems( aSheet ).insert( connected_item );
662 if( test_item->Connection( &aSheet )->IsBus() )
664 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
665 bus_entry->m_connected_bus_item = test_item;
675 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
677 if( !bus_entry->m_connected_bus_item )
680 auto bus = screen->
GetBus( it.first );
683 bus_entry->m_connected_bus_item = bus;
706 wxCHECK_RET(
m_schematic,
"Connection graph cannot be built without schematic pointer" );
710 for(
unsigned i = 0; i < all_sheets.size(); i++ )
712 for(
const auto& alias : all_sheets[i].LastScreen()->GetBusAliases() )
720 for(
const auto& it : item->m_connection_map )
722 const auto sheet = it.first;
723 auto connection = it.second;
725 if( connection->SubgraphCode() == 0 )
734 connection->SetSubgraphCode( subgraph->
m_code );
737 std::list<SCH_ITEM*> members;
745 conn = aItem->InitializeConnection( sheet,
this );
750 std::copy_if( item->ConnectedItems( sheet ).begin(),
751 item->ConnectedItems( sheet ).end(),
752 std::back_inserter( members ), get_items );
754 for(
SCH_ITEM* connected_item : members )
759 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
761 wxASSERT( connected_conn );
763 if( connected_conn->SubgraphCode() == 0 )
765 connected_conn->SetSubgraphCode( subgraph->
m_code );
767 subgraph->
AddItem( connected_item );
769 std::copy_if( connected_item->ConnectedItems( sheet ).begin(),
770 connected_item->ConnectedItems( sheet ).end(),
771 std::back_inserter( members ), get_items );
789 size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
792 std::atomic<size_t> nextSubgraph( 0 );
793 std::vector<std::future<size_t>> returns( parallelThreadCount );
794 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
799 return candidate->m_dirty;
802 auto update_lambda = [&nextSubgraph, &dirty_graphs]() ->
size_t 804 for(
size_t subgraphId = nextSubgraph++; subgraphId < dirty_graphs.size(); subgraphId = nextSubgraph++ )
806 auto subgraph = dirty_graphs[subgraphId];
808 if( !subgraph->m_dirty )
812 for(
auto item : subgraph->m_items )
814 switch( item->Type() )
817 subgraph->m_no_connect = item;
821 subgraph->m_bus_entry = item;
826 auto pin = static_cast<SCH_PIN*>( item );
829 subgraph->m_no_connect = item;
839 subgraph->ResolveDrivers(
true );
840 subgraph->m_dirty =
false;
846 if( parallelThreadCount == 1 )
850 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
851 returns[ii] = std::async( std::launch::async, update_lambda );
854 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
863 return candidate->m_driver;
872 wxString full_name = subgraph->m_driver_connection->Name();
873 wxString
name = subgraph->m_driver_connection->Name(
true );
882 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
886 subgraph->m_dirty =
true;
888 if( subgraph->m_strong_driver )
890 SCH_ITEM* driver = subgraph->m_driver;
893 switch( driver->
Type() )
908 auto pin = static_cast<SCH_PIN*>( driver );
909 wxASSERT( pin->IsPowerConnection() );
914 wxLogTrace(
ConnTrace,
"Unexpected strong driver %s",
924 std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
953 auto jj = invisible_pin_subgraphs.find( code );
955 if( jj != invisible_pin_subgraphs.end() )
957 subgraph = jj->second;
970 auto key = std::make_pair( subgraph->
GetNetName(), code );
975 invisible_pin_subgraphs[code] = subgraph;
988 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
992 if( subgraph->m_absorbed )
1000 unsigned suffix = 1;
1002 auto create_new_name =
1012 wxString prefix = aConn->BusPrefix();
1014 if( prefix.empty() )
1015 prefix = wxT(
"BUS" );
1017 wxString oldName = aConn->Name().AfterFirst(
'{' );
1021 aConn->ConfigureFromLabel( newName );
1033 if( !subgraph->m_strong_driver )
1041 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1045 if( vec->size() > 1 )
1047 wxString new_name = create_new_name( connection );
1050 new_name = create_new_name( connection );
1052 wxLogTrace(
ConnTrace,
"%ld (%s) is weakly driven and not unique. Changing to %s.",
1053 subgraph->m_code,
name, new_name );
1055 vec->erase( std::remove( vec->begin(), vec->end(), subgraph ), vec->end() );
1073 bool conflict =
false;
1074 wxString global_name = connection->
Name(
true );
1081 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1085 if( candidate->m_sheet == sheet )
1093 "%ld (%s) skipped for promotion due to potential conflict",
1094 subgraph->m_code,
name );
1099 "%ld (%s) weakly driven by unique sheet pin %s, promoting",
1100 subgraph->m_code,
name,
1103 subgraph->m_strong_driver =
true;
1111 if( connection->
IsBus() )
1135 subgraph->m_dirty =
true;
1144 if( !subgraph->m_strong_driver )
1152 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1155 std::back_inserter( candidate_subgraphs ),
1158 return ( !candidate->m_absorbed &&
1159 candidate->m_strong_driver &&
1160 candidate != subgraph );
1166 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1169 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1172 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
1174 if( possible_driver == aSubgraph->m_driver )
1181 if( c->Type() != aSubgraph->m_driver_connection->Type() )
1184 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
1187 connections_to_check.push_back( c );
1189 "%lu (%s): Adding secondary driver %s", aSubgraph->m_code,
1190 aSubgraph->m_driver_connection->Name(
true ), c->Name(
true ) );
1198 add_connections_to_check( subgraph );
1200 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
1202 auto member = connections_to_check[i];
1204 if( member->IsBus() )
1206 connections_to_check.insert( connections_to_check.end(),
1207 member->Members().begin(),
1208 member->Members().end() );
1211 wxString test_name = member->Name(
true );
1213 for(
auto candidate : candidate_subgraphs )
1215 if( candidate->m_absorbed )
1220 if( candidate->m_driver_connection->Name(
true ) == test_name )
1226 if( !candidate->m_multiple_drivers )
1229 for(
SCH_ITEM *driver : candidate->m_drivers )
1231 if( driver == candidate->m_driver )
1240 auto pin = static_cast<SCH_PIN*>( driver );
1242 if( pin->IsPowerConnection() && pin->GetName() == test_name )
1254 if( subgraph->GetNameForDriver( driver ) == test_name )
1265 if( connection->
IsBus() && candidate->m_driver_connection->IsNet() )
1267 wxLogTrace(
ConnTrace,
"%lu (%s) has bus child %lu (%s)", subgraph->m_code,
1268 connection->
Name(), candidate->m_code, member->Name() );
1270 subgraph->m_bus_neighbors[member].insert( candidate );
1271 candidate->m_bus_parents[member].insert( subgraph );
1275 wxLogTrace(
ConnTrace,
"%lu (%s) absorbs neighbor %lu (%s)",
1276 subgraph->m_code, connection->
Name(),
1277 candidate->m_code, candidate->m_driver_connection->Name() );
1280 add_connections_to_check( candidate );
1282 subgraph->Absorb( candidate );
1283 invalidated_subgraphs.insert( subgraph );
1293 if( subgraph->m_absorbed )
1296 subgraph->ResolveDrivers();
1298 if( subgraph->m_driver_connection->IsBus() )
1303 wxLogTrace(
ConnTrace,
"Re-resolving drivers for %lu (%s)", subgraph->m_code,
1304 subgraph->m_driver_connection->Name() );
1311 return candidate->m_absorbed;
1316 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1318 std::back_inserter( global_subgraphs ),
1321 return !candidate->m_local_driver;
1331 nextSubgraph.store( 0 );
1333 auto preliminaryUpdateTask =
1336 for(
size_t subgraphId = nextSubgraph++;
1338 subgraphId = nextSubgraph++ )
1346 if( parallelThreadCount == 1 )
1347 preliminaryUpdateTask();
1350 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1351 returns[ii] = std::async( std::launch::async, preliminaryUpdateTask );
1354 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1364 if( !subgraph->m_dirty )
1371 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1373 for(
SCH_ITEM* driver : subgraph->m_drivers )
1375 if( driver == subgraph->m_driver )
1378 wxString secondary_name = subgraph->GetNameForDriver( driver );
1380 if( secondary_name == subgraph->m_driver_connection->Name() )
1388 if( candidate == subgraph )
1391 if( !secondary_is_global && candidate->m_sheet != subgraph->m_sheet )
1396 if( conn->
Name() == secondary_name )
1398 wxLogTrace(
ConnTrace,
"Global %lu (%s) promoted to %s", candidate->m_code,
1399 conn->
Name(), subgraph->m_driver_connection->Name() );
1401 conn->
Clone( *subgraph->m_driver_connection );
1403 candidate->m_dirty =
false;
1425 if( subgraph->m_bus_parents.size() < 2 )
1430 wxLogTrace(
ConnTrace,
"%lu (%s) has multiple bus parents",
1431 subgraph->m_code, conn->
Name() );
1433 wxASSERT( conn->
IsNet() );
1435 for(
const auto& ii : subgraph->m_bus_parents )
1448 wxLogTrace(
ConnTrace,
"Warning: could not match %s inside %lu (%s)",
1453 if( conn->
Name() != match->
Name() )
1455 wxString old_name = match->
Name();
1457 wxLogTrace(
ConnTrace,
"Updating %lu (%s) member %s to %s", parent->
m_code,
1460 match->
Clone( *conn );
1479 nextSubgraph.store( 0 );
1481 auto updateItemConnectionsTask =
1484 for(
size_t subgraphId = nextSubgraph++;
1486 subgraphId = nextSubgraph++ )
1516 wxString pinText = pin->
GetText();
1523 if( label->
GetText() == pinText )
1530 if( parent_conn && parent_conn->
IsBus() )
1546 if( parallelThreadCount == 1 )
1547 updateItemConnectionsTask();
1550 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1551 returns[ii] = std::async( std::launch::async, updateItemConnectionsTask );
1554 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1563 auto key = std::make_pair( subgraph->GetNetName(),
1564 subgraph->m_driver_connection->NetCode() );
1596 auto connections_to_check( aConnection->
Members() );
1598 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
1600 auto member = connections_to_check[i];
1602 if( member->IsBus() )
1604 connections_to_check.insert( connections_to_check.end(),
1605 member->Members().begin(),
1606 member->Members().end() );
1618 std::vector<CONNECTION_SUBGRAPH*> search_list;
1619 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1620 std::vector<SCH_CONNECTION*> stale_bus_members;
1639 || visited.count( candidate ) )
1646 if( candidate->
GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1648 wxLogTrace(
ConnTrace,
"%lu: found child %lu (%s)", aParent->m_code,
1653 search_list.push_back( candidate );
1673 || visited.count( candidate )
1684 if( pin_path != aParent->m_sheet )
1687 if( aParent->GetNameForDriver( label ) == candidate->
GetNameForDriver( pin ) )
1689 wxLogTrace(
ConnTrace,
"%lu: found additional parent %lu (%s)",
1690 aParent->m_code, candidate->
m_code,
1693 search_list.push_back( candidate );
1702 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
1744 wxLogTrace(
ConnTrace,
"Could not match bus member %s in %s",
1745 kv.first->Name(), parent->
Name() );
1750 auto neighbor_name = neighbor_conn->
Name();
1753 if( neighbor_name == member->
Name() )
1757 if( neighbor_conn->Sheet() != neighbor->
m_sheet )
1761 wxASSERT( neighbor_conn->IsNet() );
1763 wxLogTrace(
ConnTrace,
"%lu (%s) connected to bus member %s (local %s)",
1770 member->
Clone( *neighbor_conn );
1771 stale_bus_members.push_back( member );
1775 neighbor_conn->Clone( *member );
1789 propagate_bus_neighbors( aSubgraph );
1807 visited.insert( aSubgraph );
1809 wxLogTrace(
ConnTrace,
"Propagating %lu (%s) to subsheets",
1814 for(
unsigned i = 0; i < search_list.size(); i++ )
1816 auto child = search_list[i];
1818 visited.insert( child );
1822 child->m_dirty =
false;
1837 if( subgraph == original )
1844 wxString candidateName = subgraph->m_driver_connection->Name();
1845 bool shorterPath = subgraph->m_sheet.size() < original->
m_sheet.
size();
1846 bool asGoodPath = subgraph->m_sheet.size() <= original->
m_sheet.
size();
1856 ( !originalStrong && candidateStrong ) ||
1857 ( priority > highest && candidateStrong ) ||
1858 ( priority == highest && candidateStrong && shorterPath ) ||
1859 ( ( originalStrong == candidateStrong ) && asGoodPath &&
1860 ( candidateName < originalName ) ) )
1862 original = subgraph;
1864 originalStrong = candidateStrong;
1870 if( original != aSubgraph )
1872 wxLogTrace(
ConnTrace,
"%lu (%s) overridden by new driver %lu (%s)",
1881 wxString old_name = subgraph->m_driver_connection->
Name();
1883 subgraph->m_driver_connection->Clone( *conn );
1885 if( old_name != conn->
Name() )
1889 propagate_bus_neighbors( subgraph );
1895 if( conn->
IsBus() && !stale_bus_members.empty() )
1897 for(
auto stale_member : stale_bus_members )
1905 wxLogTrace(
ConnTrace,
"Updating %lu (%s) member %s to %s", subgraph->m_code,
1906 subgraph->m_driver_connection->Name(), member->
LocalName(),
1907 stale_member->Name() );
1909 member->
Clone( *stale_member );
1911 propagate_bus_neighbors( subgraph );
1923 auto c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
1925 switch( aItem->
Type() )
1929 auto pin = static_cast<SCH_PIN*>( aItem );
1931 if( pin->IsPowerConnection() )
1932 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
1941 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
1951 c->SetGraph(
this );
1962 wxASSERT( aBusConnection->
IsBus() );
1971 for(
const auto& bus_member : aBusConnection->
Members() )
1973 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
1975 match = bus_member.get();
1983 for(
const auto& c : aBusConnection->
Members() )
1990 for(
const auto& bus_member : c->Members() )
1992 if( bus_member->LocalName() == aSearch->
LocalName() )
1994 match = bus_member.get();
1999 else if( c->LocalName() == aSearch->
LocalName() )
2012 const wxString& aOldName )
2018 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2019 vec.erase( std::remove( vec.begin(), vec.end(), aSubgraph ), vec.end() );
2022 wxLogTrace(
ConnTrace,
"recacheSubgraphName: %s => %s", aOldName,
2039 std::vector<const CONNECTION_SUBGRAPH*> ret;
2044 wxASSERT( !subgraph->m_dirty );
2046 if( !subgraph->m_driver )
2049 auto sheet = subgraph->m_sheet;
2050 auto connection = subgraph->m_driver->Connection( &sheet );
2052 if( !connection->IsBus() )
2055 auto labels = subgraph->GetBusLabels();
2057 if( labels.size() > 1 )
2059 bool different =
false;
2060 wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2062 for(
unsigned i = 1; i < labels.size(); ++i )
2064 if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2074 wxLogTrace(
ConnTrace,
"SG %ld (%s) has multiple bus labels", subgraph->m_code,
2075 connection->Name() );
2077 ret.push_back( subgraph );
2113 wxASSERT( !it->second.empty() );
2115 return it->second[0];
2133 int error_count = 0;
2135 wxCHECK_MSG(
m_schematic,
true,
"Null m_schematic in CONNECTION_GRAPH::RunERC" );
2141 std::set<SCH_ITEM*> seenDriverInstances;
2146 wxASSERT( !subgraph->m_dirty );
2148 if( subgraph->m_absorbed )
2151 if( seenDriverInstances.count( subgraph->m_driver ) )
2154 if( subgraph->m_driver )
2155 seenDriverInstances.insert( subgraph->m_driver );
2173 subgraph->ResolveDrivers(
false );
2230 static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2237 "items; %s will be used in the netlist" ),
2238 primaryName, secondaryName, primaryName );
2241 ercItem->SetItems( primary, secondary );
2242 ercItem->SetErrorMessage( msg );
2253 auto sheet = aSubgraph->
m_sheet;
2262 switch( item->
Type() )
2267 bus_item = ( !bus_item ) ? item : bus_item;
2269 net_item = ( !net_item ) ? item : net_item;
2278 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2282 bus_item = ( !bus_item ) ? item : bus_item;
2284 net_item = ( !net_item ) ? item : net_item;
2293 if( net_item && bus_item )
2296 ercItem->SetItems( net_item, bus_item );
2299 screen->Append( marker );
2311 auto sheet = aSubgraph->
m_sheet;
2317 for(
auto item : aSubgraph->
m_items )
2319 switch( item->Type() )
2350 if(
test != member && member->Name() ==
test->Name() )
2364 ercItem->SetItems( label, port );
2367 screen->Append( marker );
2379 bool conflict =
false;
2380 auto sheet = aSubgraph->
m_sheet;
2393 for(
auto item : aSubgraph->
m_items )
2395 switch( item->Type() )
2400 bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2431 for(
const auto& sub_member : member->Members() )
2433 if( sub_member->Name() == test_name )
2437 else if( member->Name() == test_name )
2454 wxString msg =
wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a" 2455 " member of that bus" ),
2459 ercItem->SetItems( bus_entry, bus_wire );
2460 ercItem->SetErrorMessage( msg );
2463 screen->Append( marker );
2483 bool has_invalid_items =
false;
2484 bool has_other_items =
false;
2486 std::vector<SCH_ITEM*> invalid_items;
2493 for(
auto item : aSubgraph->
m_items )
2495 switch( item->Type() )
2499 SCH_PIN* candidate = static_cast<SCH_PIN*>( item );
2501 .SquaredEuclideanNorm();
2503 if( !pin || dist < minDist )
2509 has_invalid_items |= has_other_items;
2510 has_other_items =
true;
2520 has_invalid_items =
true;
2521 has_other_items =
true;
2522 invalid_items.push_back( item );
2529 ercItem->SetItems( pin );
2532 screen->
Append( marker );
2543 screen->
Append( marker );
2550 bool has_other_connections =
false;
2551 std::vector<SCH_PIN*> pins;
2558 switch( item->
Type() )
2563 has_other_connections =
true;
2565 pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2572 has_other_connections =
true;
2579 SCH_PIN* pin = pins.empty() ? nullptr : pins[0];
2585 if( pin && !has_other_connections
2596 has_other_connections =
true;
2601 if( pin && !has_other_connections
2607 ercItem->SetItems( pin );
2610 screen->
Append( marker );
2618 if( pins.size() > 1 )
2620 for(
SCH_PIN* testPin : pins )
2625 if( testPin->GetLibPin()->GetParent()->IsPower()
2626 && testPin->ConnectedItems( sheet ).empty()
2630 ercItem->SetItems( testPin );
2633 testPin->GetTransformedPosition() );
2634 screen->
Append( marker );
2651 std::vector<SCH_ITEM*> wires;
2659 wires.emplace_back( item );
2661 wires.emplace_back( item );
2664 if( !wires.empty() )
2669 ercItem->SetItems( wires[0],
2670 wires.size() > 1 ? wires[1] :
nullptr,
2671 wires.size() > 2 ? wires[2] :
nullptr,
2672 wires.size() > 3 ? wires[3] : nullptr );
2675 screen->
Append( marker );
2706 bool hasOtherConnections =
false;
2709 for(
auto item : aSubgraph->
m_items )
2711 switch( item->Type() )
2717 text = static_cast<SCH_TEXT*>( item );
2726 ercItem->SetItems( text );
2738 hasOtherConnections =
true;
2753 wxCHECK_MSG(
m_schematic,
true,
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" );
2762 hasOtherConnections = ( pinCount > 1 );
2769 hasOtherConnections =
true;
2781 hasOtherConnections =
true;
2786 auto pair = std::make_pair( aSubgraph->
m_sheet,
name );
2790 hasOtherConnections =
true;
2793 if( !hasOtherConnections && settings.
IsTestEnabled( errCode ) )
2796 ercItem->SetItems( text );
2816 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
2821 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
2823 std::map<wxString, SCH_SHEET_PIN*> pins;
2824 std::map<wxString, SCH_HIERLABEL*> labels;
2828 pins[pin->GetText()] = pin;
2833 ercItem->SetItems( pin );
2836 sheet.LastScreen()->Append( marker );
2842 std::set<wxString> matchedPins;
2848 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
2850 if( !pins.count( label->
GetText() ) )
2851 labels[label->
GetText()] = label;
2853 matchedPins.insert( label->
GetText() );
2857 for(
const wxString& matched : matchedPins )
2858 pins.erase( matched );
2860 for(
const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
2862 wxString msg =
wxString::Format(
_(
"Sheet pin %s has no matching hierarchical " 2863 "label inside the sheet" ),
2867 ercItem->SetItems( unmatched.second );
2868 ercItem->SetErrorMessage( msg );
2869 ercItem->SetIsSheetSpecific();
2872 sheet.LastScreen()->Append( marker );
2877 for(
const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
2880 "sheet pin in the parent sheet" ),
2884 ercItem->SetItems( unmatched.second );
2885 ercItem->SetErrorMessage( msg );
2886 ercItem->SetIsSheetSpecific();
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Returns the subgraph for a given net name on a given sheet.
bool IsDangling() const override
void Stop()
Save the time when this function was called, and set the counter stane to stop.
power input (GND, VCC for ICs). Must be connected to a power output.
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
void SetBusCode(int aCode)
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
Pin not connected and not no connect symbol.
LIB_PIN * GetLibPin() const
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
A connection between bus objects doesn't share at least one net.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
void buildConnectionGraph()
Generates the connection graph (after all item connectivity has been updated)
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
std::shared_ptr< BUS_ALIAS > GetBusAlias(const wxString &aName)
Returns a bus alias pointer for the given name if it exists (from cache)
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_neighbors
If a subgraph is a bus, this map contains links between the bus members and any local sheet neighbors...
double msecs(bool aSinceLast=false)
LIB_PART * GetParent() const
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combines another subgraph on the same sheet into this one.
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
This item represents a bus group.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
virtual bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const
Returns true if this item should propagate connection info to aItem.
bool IsTestEnabled(int aErrorCode) const
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
A bus wire is graphically connected to a net port/pin (or vice versa).
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Returns the priority (higher is more important) of a candidate driver.
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.
std::vector< SCH_SHEET_PIN * > m_hier_pins
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_parents
If this is a net, this vector contains links to any same-sheet buses that contain it.
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
wxString GetDefaultNetName(const SCH_SHEET_PATH &aPath, bool aForceNoConnect=false)
void SetDriver(SCH_ITEM *aItem)
Some wires are not connected to anything else.
void SetName(const wxString &aName)
NET_MAP m_net_code_to_subgraphs_map
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
Updates the connection graph for the given list of sheets.
std::vector< SCH_ITEM * > m_items
Label not connected to anything.
SCHEMATIC * m_schematic
The schematic this graph represents.
virtual wxPoint GetPosition() const
wxString LocalName() const
SCH_SCREEN * GetScreen() const
A small class to help profiling.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
int ercCheckHierSheets()
Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on th...
static const wxChar ConnTrace[]
void pop_back()
Forwarded method from std::vector.
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
not internally connected (may be connected to anything)
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between net and bus labels.
CONNECTION_GRAPH * m_graph
SCH_CONNECTION * InitializeConnection(const SCH_SHEET_PATH &aPath, CONNECTION_GRAPH *aGraph)
Creates a new connection object associated with this object.
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
size_t size() const
Forwarded method from std::vector.
void SetSubgraphCode(int aCode)
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper presence or absence of no-connect symbols.
std::vector< SCH_ITEM * > m_items
void SetLayer(SCH_LAYER_ID aLayer)
Set the layer this item is on.
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
Functions to provide common constants and other functions to assist in making a consistent UI.
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Container for ERC settings.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
A wire connected to a bus doesn't match the bus.
void Clone(SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
wxPoint GetPosition() const override
CONNECTION_SUBGRAPH * FindFirstSubgraphByName(const wxString &aNetName)
Retrieves a subgraph for the given net name, if one exists.
bool IsDriver() const
Checks if the SCH_ITEM this connection is attached to can drive connections Drivers can be labels,...
std::vector< SCH_HIERLABEL * > m_hier_ports
A no connect symbol is not connected to anything.
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensures all members of the bus connection have a valid net code assigned.
This item represents a net.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieves a list of the SCH_PINs for the given sheet path.
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
static const wxChar ConnProfileMask[]
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
std::vector< SCH_SHEET_PIN * > & GetPins()
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
static bool m_allowRealTime
A global label is unique.
A no connect symbol is connected to more than 1 pin.
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
SCH_SCREEN * LastScreen()
Segment description base class to describe items which have 2 end points (track, wire,...
Mismatch between hierarchical labels and pins sheets.
SCH_ITEM_SET & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieves the set of items connected to this item on the given sheet.
void Append(SCH_ITEM *aItem)
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
SCH_SHEET_LIST m_sheetList
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Builds a new default connection for the given item based on its properties.
wxString UnescapeString(const wxString &aSource)
std::vector< SCH_ITEM * > GetBusLabels() const
Returns all the bus labels attached to this subgraph (if any)
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
ELECTRICAL_PINTYPE GetType() const
std::map< wxString, int > m_bus_name_to_code_map
wxString driverName(SCH_ITEM *aItem) const
std::map< wxString, int > m_net_name_to_code_map
CONNECTION_SUBGRAPH * m_hier_parent
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
CONNECTION_SUBGRAPH * GetSubgraphForItem(SCH_ITEM *aItem)
ERC_SETTINGS & ErcSettings() const
void SetType(CONNECTION_TYPE aType)
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
not connected (must be left open)
bool IsSubsetOf(SCH_CONNECTION *aOther) const
Returns true if this connection is contained within aOther (but not the same as aOther)
Conflicting drivers (labels, etc) on a subgraph.
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration()
Determines which subgraphs have more than one conflicting bus label.
CONNECTION_TYPE Type() const
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
Base class for any item which can be embedded within the SCHEMATIC container class,...
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
virtual const wxString & GetText() const
Return the string associated with the text object.
int RunERC()
Runs electrical rule checks on the connectivity graph.
void SetNetCode(int aCode)
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
PRIORITY GetDriverPriority()
This item represents a bus vector.
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
PINSHEETLABEL_SHAPE GetShape() const
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.
KICAD_T Type() const
Returns the type of object.
std::unordered_map< SCH_ITEM *, wxString > m_driver_name_cache
A cache of escaped netnames from schematic items.
wxPoint GetPosition() const override
wxPoint GetTransformedPosition() const
Returns the pin's position in global coordinates.
SCH_LINE * GetBus(const wxPoint &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T)
void UpdateItemConnections()
Updates all items to match the driver connection.