KiCad PCB EDA Suite
CONNECTION_GRAPH Class Reference

Calculates the connectivity of a schematic and generates netlists. More...

#include <connection_graph.h>

Public Member Functions

 CONNECTION_GRAPH (SCHEMATIC *aSchematic=nullptr)
 
 ~CONNECTION_GRAPH ()
 
void Reset ()
 
void SetSchematic (SCHEMATIC *aSchematic)
 
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. More...
 
std::shared_ptr< BUS_ALIASGetBusAlias (const wxString &aName)
 Returns a bus alias pointer for the given name if it exists (from cache) More...
 
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration ()
 Determines which subgraphs have more than one conflicting bus label. More...
 
int RunERC ()
 Runs electrical rule checks on the connectivity graph. More...
 
const NET_MAPGetNetMap () const
 
CONNECTION_SUBGRAPHFindSubgraphByName (const wxString &aNetName, const SCH_SHEET_PATH &aPath)
 Returns the subgraph for a given net name on a given sheet. More...
 
CONNECTION_SUBGRAPHFindFirstSubgraphByName (const wxString &aNetName)
 Retrieves a subgraph for the given net name, if one exists. More...
 
CONNECTION_SUBGRAPHGetSubgraphForItem (SCH_ITEM *aItem)
 
wxString GetResolvedSubgraphName (const CONNECTION_SUBGRAPH *aSubGraph) const
 Returns the fully-resolved netname for a given subgraph. More...
 

Private Member Functions

void updateItemConnectivity (const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
 Updates the graphical connectivity between items (i.e. More...
 
void buildConnectionGraph (std::function< void(SCH_ITEM *)> *aChangedItemHandler)
 Generates the connection graph (after all item connectivity has been updated) More...
 
void buildItemSubGraphs ()
 Generates individual item subgraphs on a per-sheet basis. More...
 
void resolveAllDrivers ()
 Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel. More...
 
void collectAllDriverValues ()
 Maps the driver values for each subgraph. More...
 
void generateInvisiblePinSubGraphs ()
 Iterate through the invisible power pins to collect the global labels as drivers. More...
 
void processSubGraphs ()
 Process all subgraphs to assign netcodes and merge subgraphs based on labels. More...
 
int assignNewNetCode (SCH_CONNECTION &aConnection)
 Helper to assign a new net code to a connection. More...
 
void assignNetCodesToBus (SCH_CONNECTION *aConnection)
 Ensures all members of the bus connection have a valid net code assigned. More...
 
void propagateToNeighbors (CONNECTION_SUBGRAPH *aSubgraph, bool aForce)
 Updates all neighbors of a subgraph with this one's connectivity info. More...
 
std::shared_ptr< SCH_CONNECTIONgetDefaultConnection (SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
 Builds a new default connection for the given item based on its properties. More...
 
void recacheSubgraphName (CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
 
bool ercCheckMultipleDrivers (const CONNECTION_SUBGRAPH *aSubgraph)
 If the subgraph has multiple drivers of equal priority that are graphically connected, ResolveDrivers() will have stored the second driver for use by this function, which actually creates the markers. More...
 
bool ercCheckNetclassConflicts (const std::vector< CONNECTION_SUBGRAPH * > &subgraphs)
 
bool ercCheckBusToNetConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting connections between net and bus labels. More...
 
bool ercCheckBusToBusConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting connections between two bus items. More...
 
bool ercCheckBusToBusEntryConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting bus entry to bus connections. More...
 
bool ercCheckNoConnects (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for proper presence or absence of no-connect symbols. More...
 
bool ercCheckFloatingWires (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for floating wires. More...
 
bool ercCheckLabels (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for proper connection of labels. More...
 
int ercCheckHierSheets ()
 Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on the parent sheet object. More...
 
size_t hasPins (const CONNECTION_SUBGRAPH *aLocSubgraph)
 Get the number of pins in a given subgraph. More...
 

Static Private Member Functions

static SCH_CONNECTIONmatchBusMember (SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
 Search for a matching bus member inside a bus connection. More...
 

Private Attributes

SCH_SHEET_LIST m_sheetList
 
std::vector< SCH_ITEM * > m_items
 
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
 
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
 
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
 
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
 
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
 
std::unordered_map< wxString, int > m_net_name_to_code_map
 
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::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
 
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
 
std::unordered_map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
 
NET_MAP m_net_code_to_subgraphs_map
 
int m_last_net_code
 
int m_last_bus_code
 
int m_last_subgraph_code
 
SCHEMATICm_schematic
 The schematic this graph represents. More...
 

Detailed Description

Calculates the connectivity of a schematic and generates netlists.

Definition at line 270 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCHEMATIC aSchematic = nullptr)
inline

Definition at line 273 of file connection_graph.h.

273 :
274 m_last_net_code( 1 ),
275 m_last_bus_code( 1 ),
277 m_schematic( aSchematic )
278 {}
SCHEMATIC * m_schematic
The schematic this graph represents.

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 280 of file connection_graph.h.

281 {
282 Reset();
283 }

References Reset().

Member Function Documentation

◆ assignNetCodesToBus()

void CONNECTION_GRAPH::assignNetCodesToBus ( SCH_CONNECTION aConnection)
private

Ensures all members of the bus connection have a valid net code assigned.

Parameters
aConnectionis a bus connection

Definition at line 1760 of file connection_graph.cpp.

1761{
1762 std::vector< std::shared_ptr<SCH_CONNECTION>>& connections_to_check( aConnection->Members() );
1763
1764 for( unsigned i = 0; i < connections_to_check.size(); i++ )
1765 {
1766 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
1767
1768 if( member->IsBus() )
1769 {
1770 connections_to_check.insert( connections_to_check.end(),
1771 member->Members().begin(),
1772 member->Members().end() );
1773 continue;
1774 }
1775
1776 assignNewNetCode( *member );
1777 }
1778}
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()

References assignNewNetCode(), and SCH_CONNECTION::Members().

Referenced by processSubGraphs().

◆ assignNewNetCode()

int CONNECTION_GRAPH::assignNewNetCode ( SCH_CONNECTION aConnection)
private

Helper to assign a new net code to a connection.

Returns
the assigned code

Definition at line 1738 of file connection_graph.cpp.

1739{
1740 int code;
1741
1742 auto it = m_net_name_to_code_map.find( aConnection.Name() );
1743
1744 if( it == m_net_name_to_code_map.end() )
1745 {
1746 code = m_last_net_code++;
1747 m_net_name_to_code_map[ aConnection.Name() ] = code;
1748 }
1749 else
1750 {
1751 code = it->second;
1752 }
1753
1754 aConnection.SetNetCode( code );
1755
1756 return code;
1757}
std::unordered_map< wxString, int > m_net_name_to_code_map
void SetNetCode(int aCode)
wxString Name(bool aIgnoreSheet=false) const

References m_last_net_code, m_net_name_to_code_map, SCH_CONNECTION::Name(), and SCH_CONNECTION::SetNetCode().

Referenced by assignNetCodesToBus(), generateInvisiblePinSubGraphs(), and processSubGraphs().

◆ buildConnectionGraph()

void CONNECTION_GRAPH::buildConnectionGraph ( std::function< void(SCH_ITEM *)> *  aChangedItemHandler)
private

Generates the connection graph (after all item connectivity has been updated)

In the first phase, the algorithm iterates over all items, and then over all items that are connected (graphically) to each item, placing them into CONNECTION_SUBGRAPHs. Items that can potentially drive connectivity (i.e. labels, pins, etc.) are added to the m_drivers vector of the subgraph.

In the second phase, each subgraph is resolved. To resolve a subgraph, the driver is first selected by CONNECTION_SUBGRAPH::ResolveDrivers(), and then the connection for the chosen driver is propagated to all the other items in the subgraph.

TODO(JE): Net codes are non-deterministic. Fortunately, they are also not really used for anything. We should consider removing them entirely and just using net names everywhere.

Definition at line 1384 of file connection_graph.cpp.

1385{
1386 // Recache all bus aliases for later use
1387 wxCHECK_RET( m_schematic, wxT( "Connection graph cannot be built without schematic pointer" ) );
1388
1389 SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
1390
1391 for( unsigned i = 0; i < all_sheets.size(); i++ )
1392 {
1393 for( const std::shared_ptr<BUS_ALIAS>& alias : all_sheets[i].LastScreen()->GetBusAliases() )
1394 m_bus_alias_cache[ alias->GetName() ] = alias;
1395 }
1396
1397 PROF_TIMER sub_graph( "buildItemSubGraphs" );
1399
1400 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
1401 sub_graph.Show();
1402
1403
1410
1412
1414
1415 PROF_TIMER proc_sub_graph( "ProcessSubGraphs" );
1417
1418 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
1419 proc_sub_graph.Show();
1420
1421 // Absorbed subgraphs should no longer be considered
1422 alg::delete_if( m_driver_subgraphs, [&]( const CONNECTION_SUBGRAPH* candidate ) -> bool
1423 {
1424 return candidate->m_absorbed;
1425 } );
1426
1427 // Store global subgraphs for later reference
1428 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1429 std::copy_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1430 std::back_inserter( global_subgraphs ),
1431 [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1432 {
1433 return !candidate->m_local_driver;
1434 } );
1435
1436 // Recache remaining valid subgraphs by sheet path
1438
1439 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1440 m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1441
1443
1444 tp.push_loop( m_driver_subgraphs.size(),
1445 [&]( const int a, const int b)
1446 {
1447 for( int ii = a; ii < b; ++ii )
1448 m_driver_subgraphs[ii]->UpdateItemConnections();
1449 });
1450 tp.wait_for_tasks();
1451
1452 // Next time through the subgraphs, we do some post-processing to handle things like
1453 // connecting bus members to their neighboring subgraphs, and then propagate connections
1454 // through the hierarchy
1455
1456 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1457 {
1458 if( !subgraph->m_dirty )
1459 continue;
1460
1461 wxLogTrace( ConnTrace, wxS( "Processing %lu (%s) for propagation" ), subgraph->m_code,
1462 subgraph->m_driver_connection->Name() );
1463
1464 // For subgraphs that are driven by a global (power port or label) and have more
1465 // than one global driver, we need to seek out other subgraphs driven by the
1466 // same name as the non-chosen driver and update them to match the chosen one.
1467
1468 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1469 {
1470 for( SCH_ITEM* driver : subgraph->m_drivers )
1471 {
1472 if( driver == subgraph->m_driver )
1473 continue;
1474
1475 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
1476
1477 if( secondary_name == subgraph->m_driver_connection->Name() )
1478 continue;
1479
1480 bool secondary_is_global = CONNECTION_SUBGRAPH::GetDriverPriority( driver )
1482
1483 for( CONNECTION_SUBGRAPH* candidate : global_subgraphs )
1484 {
1485 if( candidate == subgraph )
1486 continue;
1487
1488 if( !secondary_is_global && candidate->m_sheet != subgraph->m_sheet )
1489 continue;
1490
1491 SCH_CONNECTION* conn = candidate->m_driver_connection;
1492
1493 if( conn->Name() == secondary_name )
1494 {
1495 wxLogTrace( ConnTrace, wxS( "Global %lu (%s) promoted to %s" ), candidate->m_code,
1496 conn->Name(), subgraph->m_driver_connection->Name() );
1497
1498 conn->Clone( *subgraph->m_driver_connection );
1499
1500 candidate->m_dirty = false;
1501 }
1502 }
1503 }
1504 }
1505
1506 // This call will handle descending the hierarchy and updating child subgraphs
1507 propagateToNeighbors( subgraph, false );
1508 }
1509
1510 // After processing and allowing some to be skipped if they have hierarchical
1511 // pins connecting both up and down the hierarchy, we check to see if any of them
1512 // have not been processed. This would indicate that they do not have off-sheet connections
1513 // but we still need to handle the subgraph
1514 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1515 {
1516 if( subgraph->m_dirty )
1517 propagateToNeighbors( subgraph, true );
1518 }
1519
1520 // Handle buses that have been linked together somewhere by member (net) connections.
1521 // This feels a bit hacky, perhaps this algorithm should be revisited in the future.
1522
1523 // For net subgraphs that have more than one bus parent, we need to ensure that those
1524 // buses are linked together in the final netlist. The final name of each bus might not
1525 // match the local name that was used to establish the parent-child relationship, because
1526 // the bus may have been renamed by a hierarchical connection. So, for each of these cases,
1527 // we need to identify the appropriate bus members to link together (and their final names),
1528 // and then update all instances of the old name in the hierarchy.
1529
1530 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1531 {
1532 // All SGs should have been processed by propagateToNeighbors above
1533 wxASSERT_MSG( !subgraph->m_dirty, wxS( "Subgraph not processed by propagateToNeighbors!" ) );
1534
1535 if( subgraph->m_bus_parents.size() < 2 )
1536 continue;
1537
1538 SCH_CONNECTION* conn = subgraph->m_driver_connection;
1539
1540 wxLogTrace( ConnTrace, wxS( "%lu (%s) has multiple bus parents" ),
1541 subgraph->m_code, conn->Name() );
1542
1543 wxASSERT( conn->IsNet() );
1544
1545 for( const auto& ii : subgraph->m_bus_parents )
1546 {
1547 SCH_CONNECTION* link_member = ii.first.get();
1548
1549 for( CONNECTION_SUBGRAPH* parent : ii.second )
1550 {
1551 while( parent->m_absorbed )
1552 parent = parent->m_absorbed_by;
1553
1554 SCH_CONNECTION* match = matchBusMember( parent->m_driver_connection, link_member );
1555
1556 if( !match )
1557 {
1558 wxLogTrace( ConnTrace, wxS( "Warning: could not match %s inside %lu (%s)" ),
1559 conn->Name(), parent->m_code, parent->m_driver_connection->Name() );
1560 continue;
1561 }
1562
1563 if( conn->Name() != match->Name() )
1564 {
1565 wxString old_name = match->Name();
1566
1567 wxLogTrace( ConnTrace, wxS( "Updating %lu (%s) member %s to %s" ), parent->m_code,
1568 parent->m_driver_connection->Name(), old_name, conn->Name() );
1569
1570 match->Clone( *conn );
1571
1572 auto jj = m_net_name_to_subgraphs_map.find( old_name );
1573
1574 if( jj == m_net_name_to_subgraphs_map.end() )
1575 continue;
1576
1577 for( CONNECTION_SUBGRAPH* old_sg : jj->second )
1578 {
1579 while( old_sg->m_absorbed )
1580 old_sg = old_sg->m_absorbed_by;
1581
1582 old_sg->m_driver_connection->Clone( *conn );
1583 }
1584 }
1585 }
1586 }
1587 }
1588
1589
1590 auto updateItemConnectionsTask =
1591 [&]( CONNECTION_SUBGRAPH* subgraph ) -> size_t
1592 {
1593 // Make sure weakly-driven single-pin nets get the unconnected_ prefix
1594 if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
1595 subgraph->m_driver->Type() == SCH_PIN_T )
1596 {
1597 SCH_PIN* pin = static_cast<SCH_PIN*>( subgraph->m_driver );
1598 wxString name = pin->GetDefaultNetName( subgraph->m_sheet, true );
1599
1600 subgraph->m_driver_connection->ConfigureFromLabel( name );
1601 }
1602
1603 subgraph->m_dirty = false;
1604 subgraph->UpdateItemConnections();
1605
1606 // No other processing to do on buses
1607 if( subgraph->m_driver_connection->IsBus() )
1608 return 0;
1609
1610 // As a visual aid, we can check sheet pins that are driven by themselves to see
1611 // if they should be promoted to buses
1612
1613 if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1614 {
1615 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( subgraph->m_driver );
1616
1617 if( SCH_SHEET* sheet = pin->GetParent() )
1618 {
1619 wxString pinText = pin->GetText();
1620 SCH_SCREEN* screen = sheet->GetScreen();
1621
1622 for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
1623 {
1624 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
1625
1626 if( label->GetText() == pinText )
1627 {
1628 SCH_SHEET_PATH path = subgraph->m_sheet;
1629 path.push_back( sheet );
1630
1631 SCH_CONNECTION* parent_conn = label->Connection( &path );
1632
1633 if( parent_conn && parent_conn->IsBus() )
1634 subgraph->m_driver_connection->SetType( CONNECTION_TYPE::BUS );
1635
1636 break;
1637 }
1638 }
1639
1640 if( subgraph->m_driver_connection->IsBus() )
1641 return 0;
1642 }
1643 }
1644
1645 return 1;
1646 };
1647
1648 tp.push_loop( m_driver_subgraphs.size(),
1649 [&]( const int a, const int b)
1650 {
1651 for( int ii = a; ii < b; ++ii )
1652 updateItemConnectionsTask( m_driver_subgraphs[ii] );
1653 });
1654 tp.wait_for_tasks();
1655
1658
1659 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1660 {
1661 NET_NAME_CODE_CACHE_KEY key = { subgraph->GetNetName(),
1662 subgraph->m_driver_connection->NetCode() };
1663 m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1664
1665 m_net_name_to_subgraphs_map[subgraph->m_driver_connection->Name()].push_back( subgraph );
1666 }
1667
1668 std::shared_ptr<NET_SETTINGS>& netSettings = m_schematic->Prj().GetProjectFile().m_NetSettings;
1669 std::map<wxString, wxString> oldAssignments = netSettings->m_NetClassLabelAssignments;
1670
1671 netSettings->m_NetClassLabelAssignments.clear();
1672
1673 auto dirtySubgraphs =
1674 [&]( const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
1675 {
1676 if( aChangedItemHandler )
1677 {
1678 for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
1679 {
1680 for( SCH_ITEM* item : subgraph->m_items )
1681 (*aChangedItemHandler)( item );
1682 }
1683 }
1684 };
1685
1686 auto checkNetclassDrivers =
1687 [&]( const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
1688 {
1689 const CONNECTION_SUBGRAPH* driverSubgraph = nullptr;
1690 wxString netclass;
1691
1692 for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
1693 {
1694 for( SCH_ITEM* item : subgraph->m_items )
1695 {
1696 netclass = subgraph->GetNetclassForDriver( item );
1697
1698 if( !netclass.IsEmpty() )
1699 break;
1700 }
1701
1702 if( !netclass.IsEmpty() || !driverSubgraph )
1703 {
1704 driverSubgraph = subgraph;
1705 break;
1706 }
1707 }
1708
1709 if( netclass.IsEmpty() )
1710 return;
1711
1712 const wxString netname = driverSubgraph->GetNetName();
1713
1714 if( driverSubgraph->m_driver_connection->IsBus() )
1715 {
1716 for( const auto& member : driverSubgraph->m_driver_connection->Members() )
1717 {
1718 netSettings->m_NetClassLabelAssignments[ member->Name() ] = netclass;
1719
1720 auto ii = m_net_name_to_subgraphs_map.find( member->Name() );
1721
1722 if( ii != m_net_name_to_subgraphs_map.end() )
1723 dirtySubgraphs( ii->second );
1724 }
1725 }
1726
1727 netSettings->m_NetClassLabelAssignments[ netname ] = netclass;
1728
1729 if( oldAssignments[ netname ] != netclass )
1730 dirtySubgraphs( subgraphs );
1731 };
1732
1733 for( const auto& [ netname, subgraphs ] : m_net_name_to_subgraphs_map )
1734 checkNetclassDrivers( subgraphs );
1735}
const char * name
Definition: DXF_plotter.cpp:56
void processSubGraphs()
Process all subgraphs to assign netcodes and merge subgraphs based on labels.
void collectAllDriverValues()
Maps the driver values for each subgraph.
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
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph, bool aForce)
Updates all neighbors of a subgraph with this one's connectivity info.
void buildItemSubGraphs()
Generates individual item subgraphs on a per-sheet basis.
void generateInvisiblePinSubGraphs()
Iterate through the invisible power pins to collect the global labels as drivers.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
NET_MAP m_net_code_to_subgraphs_map
void resolveAllDrivers()
Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel.
A subgraph is a set of items that are electrically connected on a single sheet.
PRIORITY GetDriverPriority()
SCH_SHEET_PATH m_sheet
const wxString GetNetclassForDriver(SCH_ITEM *aItem) const
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
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.
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
A small class to help profiling.
Definition: profile.h:47
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
Definition: project_file.h:168
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:149
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:86
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:76
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsNet() const
void SetType(CONNECTION_TYPE aType)
bool IsBus() const
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:146
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
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...
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
static const wxChar ConnProfileMask[]
static const wxChar ConnTrace[]
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
Definition: kicad_algo.h:173
@ BUS
This item represents a bus vector.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:32
static thread_pool * tp
Definition: thread_pool.cpp:30
BS::thread_pool thread_pool
Definition: thread_pool.h:30
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:153
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:157
@ SCH_PIN_T
Definition: typeinfo.h:159

References buildItemSubGraphs(), BUS, SCH_CONNECTION::Clone(), collectAllDriverValues(), SCH_ITEM::Connection(), ConnProfileMask, ConnTrace, alg::delete_if(), generateInvisiblePinSubGraphs(), CONNECTION_SUBGRAPH::GetDriverPriority(), GetKiCadThreadPool(), CONNECTION_SUBGRAPH::GetNetclassForDriver(), CONNECTION_SUBGRAPH::GetNetName(), PROJECT::GetProjectFile(), SCHEMATIC::GetSheets(), EDA_TEXT::GetText(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::IsNet(), SCH_SCREEN::Items(), CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, m_bus_alias_cache, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver_connection, m_driver_subgraphs, m_net_code_to_subgraphs_map, m_net_name_to_subgraphs_map, PROJECT_FILE::m_NetSettings, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, matchBusMember(), SCH_CONNECTION::Members(), name, SCH_CONNECTION::Name(), EE_RTREE::OfType(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, SCHEMATIC::Prj(), processSubGraphs(), propagateToNeighbors(), resolveAllDrivers(), SCH_HIER_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, SCH_CONNECTION::SetType(), PROF_TIMER::Show(), and tp.

◆ buildItemSubGraphs()

void CONNECTION_GRAPH::buildItemSubGraphs ( )
private

Generates individual item subgraphs on a per-sheet basis.

Definition at line 749 of file connection_graph.cpp.

750{
751 // Recache all bus aliases for later use
752 wxCHECK_RET( m_schematic, wxS( "Connection graph cannot be built without schematic pointer" ) );
753
754 SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
755
756 for( unsigned i = 0; i < all_sheets.size(); i++ )
757 {
758 for( const std::shared_ptr<BUS_ALIAS>& alias : all_sheets[i].LastScreen()->GetBusAliases() )
759 m_bus_alias_cache[ alias->GetName() ] = alias;
760 }
761
762 // Build subgraphs from items (on a per-sheet basis)
763
764 for( SCH_ITEM* item : m_items )
765 {
766 for( const auto& it : item->m_connection_map )
767 {
768 const SCH_SHEET_PATH& sheet = it.first;
769 SCH_CONNECTION* connection = it.second;
770
771 if( connection->SubgraphCode() == 0 )
772 {
773 CONNECTION_SUBGRAPH* subgraph = new CONNECTION_SUBGRAPH( this );
774
775 subgraph->m_code = m_last_subgraph_code++;
776 subgraph->m_sheet = sheet;
777
778 subgraph->AddItem( item );
779
780 connection->SetSubgraphCode( subgraph->m_code );
781 m_item_to_subgraph_map[item] = subgraph;
782
783 std::list<SCH_ITEM*> memberlist;
784
785 auto get_items =
786 [&]( SCH_ITEM* aItem ) -> bool
787 {
788 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet, this );
789 bool unique = !( aItem->GetFlags() & CANDIDATE );
790
791 if( conn && !conn->SubgraphCode() )
792 aItem->SetFlags( CANDIDATE );
793
794 return ( unique && conn && ( conn->SubgraphCode() == 0 ) );
795 };
796
797 std::copy_if( item->ConnectedItems( sheet ).begin(),
798 item->ConnectedItems( sheet ).end(),
799 std::back_inserter( memberlist ), get_items );
800
801 for( SCH_ITEM* connected_item : memberlist )
802 {
803 if( connected_item->Type() == SCH_NO_CONNECT_T )
804 subgraph->m_no_connect = connected_item;
805
806 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
807
808 wxASSERT( connected_conn );
809
810 if( connected_conn->SubgraphCode() == 0 )
811 {
812 connected_conn->SetSubgraphCode( subgraph->m_code );
813 m_item_to_subgraph_map[connected_item] = subgraph;
814 subgraph->AddItem( connected_item );
815 SCH_ITEM_SET& citemset = connected_item->ConnectedItems( sheet );
816
817 for( SCH_ITEM* citem : citemset )
818 {
819 if( citem->HasFlag( CANDIDATE ) )
820 continue;
821
822 if( get_items( citem ) )
823 memberlist.push_back( citem );
824 }
825 }
826 }
827
828 for( SCH_ITEM* connected_item : memberlist )
829 connected_item->ClearFlags( CANDIDATE );
830
831 subgraph->m_dirty = true;
832 m_subgraphs.push_back( subgraph );
833 }
834 }
835 }
836
837}
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
std::vector< SCH_ITEM * > m_items
std::unordered_map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
void SetSubgraphCode(int aCode)
int SubgraphCode() const
#define CANDIDATE
flag indicating that the structure is connected
std::vector< SCH_ITEM * > SCH_ITEM_SET
Definition: sch_item.h:136
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:143

References CONNECTION_SUBGRAPH::AddItem(), CANDIDATE, SCHEMATIC::GetSheets(), m_bus_alias_cache, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, m_item_to_subgraph_map, m_items, m_last_subgraph_code, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_subgraphs, SCH_NO_CONNECT_T, SCH_CONNECTION::SetSubgraphCode(), and SCH_CONNECTION::SubgraphCode().

Referenced by buildConnectionGraph().

◆ collectAllDriverValues()

void CONNECTION_GRAPH::collectAllDriverValues ( )
private

Maps the driver values for each subgraph.

Definition at line 911 of file connection_graph.cpp.

912{
913 // Check for subgraphs with the same net name but only weak drivers.
914 // For example, two wires that are both connected to hierarchical
915 // sheet pins that happen to have the same name, but are not the same.
916
917 for( auto&& subgraph : m_driver_subgraphs )
918 {
919 wxString full_name = subgraph->m_driver_connection->Name();
920 wxString name = subgraph->m_driver_connection->Name( true );
921 m_net_name_to_subgraphs_map[full_name].emplace_back( subgraph );
922
923 // For vector buses, we need to cache the prefix also, as two different instances of the
924 // weakly driven pin may have the same prefix but different vector start and end. We need
925 // to treat those as needing renaming also, because otherwise if they end up on a sheet with
926 // common usage, they will be incorrectly merged.
927 if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
928 {
929 wxString prefixOnly = full_name.BeforeFirst( '[' ) + wxT( "[]" );
930 m_net_name_to_subgraphs_map[prefixOnly].emplace_back( subgraph );
931 }
932
933 subgraph->m_dirty = true;
934
935 if( subgraph->m_strong_driver )
936 {
937 SCH_ITEM* driver = subgraph->m_driver;
938 SCH_SHEET_PATH sheet = subgraph->m_sheet;
939
940 switch( driver->Type() )
941 {
942 case SCH_LABEL_T:
943 case SCH_HIER_LABEL_T:
944 {
945 m_local_label_cache[std::make_pair( sheet, name )].push_back( subgraph );
946 break;
947 }
949 {
950 m_global_label_cache[name].push_back( subgraph );
951 break;
952 }
953 case SCH_PIN_T:
954 {
955 SCH_PIN* pin = static_cast<SCH_PIN*>( driver );
956 wxASSERT( pin->IsPowerConnection() );
957 m_global_label_cache[name].push_back( subgraph );
958 break;
959 }
960 default:
961 {
963
964 wxLogTrace( ConnTrace, wxS( "Unexpected strong driver %s" ),
965 driver->GetItemDescription( &unitsProvider ) );
966 break;
967 }
968 }
969 }
970 }
971}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
std::unordered_map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const
Return a user-visible description string of this item.
Definition: eda_item.cpp:108
@ SCH_LABEL_T
Definition: typeinfo.h:151
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:152

References BUS, ConnTrace, EDA_ITEM::GetItemDescription(), m_driver_subgraphs, m_global_label_cache, m_local_label_cache, m_net_name_to_subgraphs_map, MILLIMETRES, name, pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, schIUScale, and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ ercCheckBusToBusConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting connections between two bus items.

For example, a labeled bus wire connected to a hierarchical sheet pin where the labeled bus doesn't contain any of the same bus members as the sheet pin

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2611 of file connection_graph.cpp.

2612{
2613 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2614 SCH_SCREEN* screen = sheet.LastScreen();
2615
2616 SCH_ITEM* label = nullptr;
2617 SCH_ITEM* port = nullptr;
2618
2619 for( SCH_ITEM* item : aSubgraph->m_items )
2620 {
2621 switch( item->Type() )
2622 {
2623 case SCH_TEXT_T:
2624 case SCH_GLOBAL_LABEL_T:
2625 {
2626 if( !label && item->Connection( &sheet )->IsBus() )
2627 label = item;
2628 break;
2629 }
2630
2631 case SCH_SHEET_PIN_T:
2632 case SCH_HIER_LABEL_T:
2633 {
2634 if( !port && item->Connection( &sheet )->IsBus() )
2635 port = item;
2636 break;
2637 }
2638
2639 default:
2640 break;
2641 }
2642 }
2643
2644 if( label && port )
2645 {
2646 bool match = false;
2647
2648 for( const auto& member : label->Connection( &sheet )->Members() )
2649 {
2650 for( const auto& test : port->Connection( &sheet )->Members() )
2651 {
2652 if( test != member && member->Name() == test->Name() )
2653 {
2654 match = true;
2655 break;
2656 }
2657 }
2658
2659 if( match )
2660 break;
2661 }
2662
2663 if( !match )
2664 {
2665 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
2666 ercItem->SetItems( label, port );
2667
2668 SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
2669 screen->Append( marker );
2670
2671 return false;
2672 }
2673 }
2674
2675 return true;
2676}
std::vector< SCH_ITEM * > m_items
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:249
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:232
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:145
SCH_SCREEN * LastScreen()
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:64
@ SCH_TEXT_T
Definition: typeinfo.h:150

References SCH_SCREEN::Append(), SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_TO_BUS_CONFLICT, EDA_ITEM::GetPosition(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_SHEET_PIN_T, SCH_TEXT_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckBusToBusEntryConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting bus entry to bus connections.

For example, a wire with label "A0" is connected to a bus labeled "D[8..0]"

Will also check for mistakes related to bus group names, for example: A bus group named "USB{DP DM}" should have bus entry connections like "USB.DP" but someone might accidentally just enter "DP"

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2679 of file connection_graph.cpp.

2680{
2681 bool conflict = false;
2682 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2683 SCH_SCREEN* screen = sheet.LastScreen();
2684
2685 SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2686 SCH_ITEM* bus_wire = nullptr;
2687 wxString bus_name;
2688
2689 if( !aSubgraph->m_driver_connection )
2690 {
2691 // Incomplete bus entry. Let the unconnected tests handle it.
2692 return true;
2693 }
2694
2695 for( SCH_ITEM* item : aSubgraph->m_items )
2696 {
2697 switch( item->Type() )
2698 {
2700 {
2701 if( !bus_entry )
2702 bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2703 break;
2704 }
2705
2706 default:
2707 break;
2708 }
2709 }
2710
2711 if( bus_entry && bus_entry->m_connected_bus_item )
2712 {
2713 bus_wire = bus_entry->m_connected_bus_item;
2714
2715 wxASSERT( bus_wire->Type() == SCH_LINE_T );
2716
2717 // In some cases, the connection list (SCH_CONNECTION*) can be null.
2718 // Skip null connections.
2719 if( bus_entry->Connection( &sheet )
2720 && bus_wire->Type() == SCH_LINE_T
2721 && bus_wire->Connection( &sheet ) )
2722 {
2723 conflict = true; // Assume a conflict; we'll reset if we find it's OK
2724
2725 bus_name = bus_wire->Connection( &sheet )->Name();
2726
2727 std::set<wxString> test_names;
2728 test_names.insert( bus_entry->Connection( &sheet )->Name() );
2729
2730 wxString baseName = sheet.PathHumanReadable();
2731
2732 for( SCH_ITEM* driver : aSubgraph->m_drivers )
2733 test_names.insert( baseName + aSubgraph->GetNameForDriver( driver ) );
2734
2735 for( const auto& member : bus_wire->Connection( &sheet )->Members() )
2736 {
2737 if( member->Type() == CONNECTION_TYPE::BUS )
2738 {
2739 for( const auto& sub_member : member->Members() )
2740 {
2741 if( test_names.count( sub_member->Name() ) )
2742 conflict = false;
2743 }
2744 }
2745 else if( test_names.count( member->Name() ) )
2746 {
2747 conflict = false;
2748 }
2749 }
2750 }
2751 }
2752
2753 // Don't report warnings if this bus member has been overridden by a higher priority power pin
2754 // or global label
2755 if( conflict && CONNECTION_SUBGRAPH::GetDriverPriority( aSubgraph->m_driver )
2757 {
2758 conflict = false;
2759 }
2760
2761 if( conflict )
2762 {
2763 wxString netName = aSubgraph->m_driver_connection->Name();
2764 wxString msg = wxString::Format( _( "Net %s is graphically connected to bus %s but is not a"
2765 " member of that bus" ),
2766 UnescapeString( netName ),
2767 UnescapeString( bus_name ) );
2768 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
2769 ercItem->SetItems( bus_entry, bus_wire );
2770 ercItem->SetErrorMessage( msg );
2771
2772 SCH_MARKER* marker = new SCH_MARKER( ercItem, bus_entry->GetPosition() );
2773 screen->Append( marker );
2774
2775 return false;
2776 }
2777
2778 return true;
2779}
std::vector< SCH_ITEM * > m_drivers
const wxString & GetNameForDriver(SCH_ITEM *aItem) const
Returns the candidate net name for a driver.
VECTOR2I GetPosition() const override
Class for a wire to bus entry.
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
#define _(s)
@ ERCE_BUS_ENTRY_CONFLICT
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:62
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxString UnescapeString(const wxString &aSource)
@ SCH_LINE_T
Definition: typeinfo.h:146
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:144

References _, SCH_SCREEN::Append(), BUS, SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_ENTRY_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetDriverPriority(), CONNECTION_SUBGRAPH::GetNameForDriver(), SCH_BUS_ENTRY_BASE::GetPosition(), SCH_SHEET_PATH::LastScreen(), SCH_BUS_WIRE_ENTRY::m_connected_bus_item, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_CONNECTION::Name(), SCH_SHEET_PATH::PathHumanReadable(), CONNECTION_SUBGRAPH::POWER_PIN, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, EDA_ITEM::Type(), and UnescapeString().

Referenced by RunERC().

◆ ercCheckBusToNetConflicts()

bool CONNECTION_GRAPH::ercCheckBusToNetConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting connections between net and bus labels.

For example, a net wire connected to a bus port/pin, or vice versa

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2554 of file connection_graph.cpp.

2555{
2556 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2557 SCH_SCREEN* screen = sheet.LastScreen();
2558
2559 SCH_ITEM* net_item = nullptr;
2560 SCH_ITEM* bus_item = nullptr;
2561 SCH_CONNECTION conn( this );
2562
2563 for( SCH_ITEM* item : aSubgraph->m_items )
2564 {
2565 switch( item->Type() )
2566 {
2567 case SCH_LINE_T:
2568 {
2569 if( item->GetLayer() == LAYER_BUS )
2570 bus_item = ( !bus_item ) ? item : bus_item;
2571 else
2572 net_item = ( !net_item ) ? item : net_item;
2573 break;
2574 }
2575
2576 case SCH_LABEL_T:
2577 case SCH_GLOBAL_LABEL_T:
2578 case SCH_SHEET_PIN_T:
2579 case SCH_HIER_LABEL_T:
2580 {
2581 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2582 conn.ConfigureFromLabel( EscapeString( text->GetShownText(), CTX_NETNAME ) );
2583
2584 if( conn.IsBus() )
2585 bus_item = ( !bus_item ) ? item : bus_item;
2586 else
2587 net_item = ( !net_item ) ? item : net_item;
2588 break;
2589 }
2590
2591 default:
2592 break;
2593 }
2594 }
2595
2596 if( net_item && bus_item )
2597 {
2598 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
2599 ercItem->SetItems( net_item, bus_item );
2600
2601 SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
2602 screen->Append( marker );
2603
2604 return false;
2605 }
2606
2607 return true;
2608}
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:246
@ ERCE_BUS_TO_NET_CONFLICT
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:66
@ LAYER_BUS
Definition: layer_ids.h:345
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
Definition: string_utils.h:54

References SCH_SCREEN::Append(), SCH_CONNECTION::ConfigureFromLabel(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_BUS_TO_NET_CONFLICT, EscapeString(), SCH_ITEM::GetLayer(), EDA_ITEM::GetPosition(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_LINE_T, SCH_SHEET_PIN_T, text, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckFloatingWires()

bool CONNECTION_GRAPH::ercCheckFloatingWires ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for floating wires.

Will throw an error for any subgraph that consists of just wires with no driver

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 3006 of file connection_graph.cpp.

3007{
3008 if( aSubgraph->m_driver )
3009 return true;
3010
3011 std::vector<SCH_ITEM*> wires;
3012
3013 // We've gotten this far, so we know we have no valid driver. All we need to do is check
3014 // for a wire that we can place the error on.
3015
3016 for( SCH_ITEM* item : aSubgraph->m_items )
3017 {
3018 if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
3019 wires.emplace_back( item );
3020 else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
3021 wires.emplace_back( item );
3022 }
3023
3024 if( !wires.empty() )
3025 {
3026 SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
3027
3028 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
3029 ercItem->SetItems( wires[0],
3030 wires.size() > 1 ? wires[1] : nullptr,
3031 wires.size() > 2 ? wires[2] : nullptr,
3032 wires.size() > 3 ? wires[3] : nullptr );
3033
3034 SCH_MARKER* marker = new SCH_MARKER( ercItem, wires[0]->GetPosition() );
3035 screen->Append( marker );
3036
3037 return false;
3038 }
3039
3040 return true;
3041}
@ ERCE_WIRE_DANGLING
Some wires are not connected to anything else.
Definition: erc_settings.h:72
@ LAYER_WIRE
Definition: layer_ids.h:344

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_WIRE_DANGLING, SCH_ITEM::GetLayer(), SCH_SHEET_PATH::LastScreen(), LAYER_WIRE, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckHierSheets()

int CONNECTION_GRAPH::ercCheckHierSheets ( )
private

Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on the parent sheet object.

Parameters
aSubgraphis the subgraph to examine
Returns
the number of errors found

Definition at line 3189 of file connection_graph.cpp.

3190{
3191 int errors = 0;
3192
3193 ERC_SETTINGS& settings = m_schematic->ErcSettings();
3194
3195 for( const SCH_SHEET_PATH& sheet : m_sheetList )
3196 {
3197 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
3198 {
3199 if( item->Type() != SCH_SHEET_T )
3200 continue;
3201
3202 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
3203
3204 std::map<wxString, SCH_SHEET_PIN*> pins;
3205 std::map<wxString, SCH_HIERLABEL*> labels;
3206
3207 for( SCH_SHEET_PIN* pin : parentSheet->GetPins() )
3208 {
3209 if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
3210 pins[pin->GetText()] = pin;
3211
3212 if( pin->IsDangling() && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
3213 {
3214 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
3215 ercItem->SetItems( pin );
3216
3217 SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
3218 sheet.LastScreen()->Append( marker );
3219
3220 errors++;
3221 }
3222 }
3223
3224 if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
3225 {
3226 std::set<wxString> matchedPins;
3227
3228 for( SCH_ITEM* subItem : parentSheet->GetScreen()->Items() )
3229 {
3230 if( subItem->Type() == SCH_HIER_LABEL_T )
3231 {
3232 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
3233
3234 if( !pins.count( label->GetText() ) )
3235 labels[label->GetText()] = label;
3236 else
3237 matchedPins.insert( label->GetText() );
3238 }
3239 }
3240
3241 for( const wxString& matched : matchedPins )
3242 pins.erase( matched );
3243
3244 for( const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
3245 {
3246 wxString msg = wxString::Format( _( "Sheet pin %s has no matching hierarchical "
3247 "label inside the sheet" ),
3248 UnescapeString( unmatched.first ) );
3249
3250 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
3251 ercItem->SetItems( unmatched.second );
3252 ercItem->SetErrorMessage( msg );
3253 ercItem->SetSheetSpecificPath( sheet );
3254 ercItem->SetItemsSheetPaths( sheet );
3255
3256 SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
3257 sheet.LastScreen()->Append( marker );
3258
3259 errors++;
3260 }
3261
3262 for( const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
3263 {
3264 wxString msg = wxString::Format( _( "Hierarchical label %s has no matching "
3265 "sheet pin in the parent sheet" ),
3266 UnescapeString( unmatched.first ) );
3267
3268 SCH_SHEET_PATH parentSheetPath = sheet;
3269 parentSheetPath.push_back( parentSheet );
3270
3271 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
3272 ercItem->SetItems( unmatched.second );
3273 ercItem->SetErrorMessage( msg );
3274 ercItem->SetSheetSpecificPath( parentSheetPath );
3275 ercItem->SetItemsSheetPaths( parentSheetPath );
3276
3277 SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
3278 parentSheet->GetScreen()->Append( marker );
3279
3280 errors++;
3281 }
3282 }
3283 }
3284 }
3285
3286 return errors;
3287}
SCH_SHEET_LIST m_sheetList
Container for ERC settings.
Definition: erc_settings.h:114
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:130
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:185
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:106
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:175
@ ERCE_PIN_NOT_CONNECTED
Pin not connected and not no connect symbol.
Definition: erc_settings.h:42
@ ERCE_HIERACHICAL_LABEL
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:47
@ SCH_SHEET_T
Definition: typeinfo.h:158

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_HIERACHICAL_LABEL, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), Format(), SCH_SHEET::GetPins(), SCH_SHEET::GetScreen(), EDA_TEXT::GetText(), ERC_SETTINGS::IsTestEnabled(), SCH_SCREEN::Items(), m_schematic, m_sheetList, pin, SCH_SHEET_PATH::push_back(), SCH_HIER_LABEL_T, SCH_SHEET_T, and UnescapeString().

Referenced by RunERC().

◆ ercCheckLabels()

bool CONNECTION_GRAPH::ercCheckLabels ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for proper connection of labels.

Labels should be connected to something

Parameters
aSubgraphis the subgraph to examine
aCheckGlobalLabelsis true if global labels should be checked for loneliness
Returns
true for no errors, false for errors

Definition at line 3044 of file connection_graph.cpp.

3045{
3046 // Label connection rules:
3047 // Any label without a no-connect needs to have at least 2 pins, otherwise it is invalid
3048 // Local labels are flagged if they don't connect to any pins and don't have a no-connect
3049 // Global labels are flagged if they appear only once, don't connect to any local labels,
3050 // and don't have a no-connect marker
3051
3052
3053 if( !aSubgraph->m_driver_connection )
3054 return true;
3055
3056 // Buses are excluded from this test: many users create buses with only a single instance
3057 // and it's not really a problem as long as the nets in the bus pass ERC
3058 if( aSubgraph->m_driver_connection->IsBus() )
3059 return true;
3060
3061 ERC_SETTINGS& settings = m_schematic->ErcSettings();
3062 bool ok = true;
3063 int pinCount = 0;
3064 bool has_nc = !!aSubgraph->m_no_connect;
3065
3066 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
3067
3068
3069 auto hasPins =
3070 []( const CONNECTION_SUBGRAPH* aLocSubgraph ) -> int
3071 {
3072 return
3073 std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(), []( const SCH_ITEM* item )
3074 { return item->Type() == SCH_PIN_T; } );
3075 };
3076
3077 auto reportError = [&]( SCH_TEXT* aText, int errCode )
3078 {
3079 if( settings.IsTestEnabled( errCode ) )
3080 {
3081 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
3082 ercItem->SetItems( aText );
3083
3084 SCH_MARKER* marker = new SCH_MARKER( ercItem, aText->GetPosition() );
3085 aSubgraph->m_sheet.LastScreen()->Append( marker );
3086 }
3087 };
3088
3089 pinCount = hasPins( aSubgraph );
3090
3091 for( SCH_ITEM* item : aSubgraph->m_items )
3092 {
3093 switch( item->Type() )
3094 {
3095 case SCH_LABEL_T:
3096 case SCH_GLOBAL_LABEL_T:
3097 case SCH_HIER_LABEL_T:
3098 {
3099 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
3100
3101 label_map[item->Type()].push_back( text );
3102
3103 // Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
3104 // we want to error if an individual label in the subgraph is floating, even if it's
3105 // connected to other valid things by way of another label on the same sheet.
3106 if( text->IsDangling() )
3107 {
3108 reportError( text, ERCE_LABEL_NOT_CONNECTED );
3109 return false;
3110 }
3111
3112 break;
3113 }
3114
3115 default:
3116 break;
3117 }
3118 }
3119
3120 if( label_map.empty() )
3121 return true;
3122
3123 wxString netName = GetResolvedSubgraphName( aSubgraph );
3124
3125 wxCHECK_MSG( m_schematic, true, wxS( "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
3126
3127 // Labels that have multiple pins connected are not dangling (may be used for naming segments)
3128 // so leave them without errors here
3129 if( pinCount > 1 )
3130 return true;
3131
3132 for( auto& [type, label_vec] : label_map )
3133 {
3134
3135 switch( type )
3136 {
3137 case SCH_GLOBAL_LABEL_T:
3138 if( !settings.IsTestEnabled( ERCE_GLOBLABEL ) )
3139 continue;
3140
3141 break;
3142 default:
3143 if( !settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
3144 continue;
3145
3146 break;
3147 }
3148
3149 for( SCH_TEXT* text : label_vec )
3150 {
3151 int allPins = pinCount;
3152
3153 auto it = m_net_name_to_subgraphs_map.find( netName );
3154
3155 if( it != m_net_name_to_subgraphs_map.end() )
3156 {
3157 for( const CONNECTION_SUBGRAPH* neighbor : it->second )
3158 {
3159 if( neighbor == aSubgraph )
3160 continue;
3161
3162 if( neighbor->m_no_connect )
3163 has_nc = true;
3164
3165 allPins += hasPins( neighbor );
3166 }
3167 }
3168
3169 if( allPins == 1 && !has_nc )
3170 {
3171 reportError( text,
3173 ok = false;
3174 }
3175
3176 if( allPins == 0 )
3177 {
3178 reportError( text,
3180 ok = false;
3181 }
3182 }
3183 }
3184
3185 return ok;
3186}
size_t hasPins(const CONNECTION_SUBGRAPH *aLocSubgraph)
Get the number of pins in a given subgraph.
wxString GetResolvedSubgraphName(const CONNECTION_SUBGRAPH *aSubGraph) const
Returns the fully-resolved netname for a given subgraph.
VECTOR2I GetPosition() const override
Definition: sch_text.h:203
@ ERCE_LABEL_NOT_CONNECTED
Label not connected to anything.
Definition: erc_settings.h:50
@ ERCE_GLOBLABEL
A global label is unique.
Definition: erc_settings.h:69

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, SCHEMATIC::ErcSettings(), SCH_TEXT::GetPosition(), GetResolvedSubgraphName(), hasPins(), SCH_CONNECTION::IsBus(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_items, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, text, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckMultipleDrivers()

bool CONNECTION_GRAPH::ercCheckMultipleDrivers ( const CONNECTION_SUBGRAPH aSubgraph)
private

If the subgraph has multiple drivers of equal priority that are graphically connected, ResolveDrivers() will have stored the second driver for use by this function, which actually creates the markers.

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2441 of file connection_graph.cpp.

2442{
2443 wxCHECK( aSubgraph, false );
2444 /*
2445 * This was changed late in 6.0 to fix https://gitlab.com/kicad/code/kicad/-/issues/9367
2446 * so I'm going to leave the original code in for just a little while. If anyone comes
2447 * across this in 7.0 development (or later), feel free to delete.
2448 */
2449#if 0
2450 if( aSubgraph->m_second_driver )
2451 {
2452 SCH_ITEM* primary = aSubgraph->m_first_driver;
2453 SCH_ITEM* secondary = aSubgraph->m_second_driver;
2454
2455 wxPoint pos = primary->Type() == SCH_PIN_T ?
2456 static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2457 primary->GetPosition();
2458
2459 const wxString& primaryName = aSubgraph->GetNameForDriver( primary );
2460 const wxString& secondaryName = aSubgraph->GetNameForDriver( secondary );
2461
2462 wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2463 "items; %s will be used in the netlist" ),
2464 primaryName, secondaryName, primaryName );
2465
2466 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2467 ercItem->SetItems( primary, secondary );
2468 ercItem->SetErrorMessage( msg );
2469
2470 SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2471 aSubgraph->m_sheet.LastScreen()->Append( marker );
2472
2473 return false;
2474 }
2475#else
2476 if( aSubgraph->m_multiple_drivers )
2477 {
2478 for( SCH_ITEM* driver : aSubgraph->m_drivers )
2479 {
2480 if( driver == aSubgraph->m_driver )
2481 continue;
2482
2483 if( driver->Type() == SCH_GLOBAL_LABEL_T
2484 || driver->Type() == SCH_HIER_LABEL_T
2485 || driver->Type() == SCH_LABEL_T
2486 || ( driver->Type() == SCH_PIN_T
2487 && static_cast<SCH_PIN*>( driver )->IsPowerConnection() ) )
2488 {
2489 const wxString& primaryName = aSubgraph->GetNameForDriver( aSubgraph->m_driver );
2490 const wxString& secondaryName = aSubgraph->GetNameForDriver( driver );
2491
2492 if( primaryName == secondaryName )
2493 continue;
2494
2495 wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2496 "items; %s will be used in the netlist" ),
2497 primaryName, secondaryName, primaryName );
2498
2499 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2500 ercItem->SetItems( aSubgraph->m_driver, driver );
2501 ercItem->SetErrorMessage( msg );
2502
2503 SCH_MARKER* marker = new SCH_MARKER( ercItem, driver->GetPosition() );
2504 aSubgraph->m_sheet.LastScreen()->Append( marker );
2505
2506 return false;
2507 }
2508 }
2509 }
2510#endif
2511
2512 return true;
2513}
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
bool IsPowerConnection() const
Definition: sch_pin.h:158
@ ERCE_DRIVER_CONFLICT
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:61

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_DRIVER_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetNameForDriver(), EDA_ITEM::GetPosition(), SCH_PIN::IsPowerConnection(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_first_driver, CONNECTION_SUBGRAPH::m_multiple_drivers, CONNECTION_SUBGRAPH::m_second_driver, CONNECTION_SUBGRAPH::m_sheet, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckNetclassConflicts()

bool CONNECTION_GRAPH::ercCheckNetclassConflicts ( const std::vector< CONNECTION_SUBGRAPH * > &  subgraphs)
private

Definition at line 2516 of file connection_graph.cpp.

2517{
2518 wxString firstNetclass;
2519 SCH_ITEM* firstNetclassDriver = nullptr;
2520
2521 for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
2522 {
2523 for( SCH_ITEM* item : subgraph->m_items )
2524 {
2525 const wxString netclass = subgraph->GetNetclassForDriver( item );
2526
2527 if( netclass.IsEmpty() )
2528 continue;
2529
2530 if( netclass != firstNetclass )
2531 {
2532 if( !firstNetclassDriver )
2533 {
2534 firstNetclass = netclass;
2535 firstNetclassDriver = item;
2536 continue;
2537 }
2538
2539 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NETCLASS_CONFLICT );
2540 ercItem->SetItems( firstNetclassDriver, item );
2541
2542 SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
2543 subgraph->m_sheet.LastScreen()->Append( marker );
2544
2545 return false;
2546 }
2547 }
2548 }
2549
2550 return true;
2551}
@ ERCE_NETCLASS_CONFLICT
Multiple labels assign different netclasses to same net.
Definition: erc_settings.h:68

References ERC_ITEM::Create(), ERCE_NETCLASS_CONFLICT, and EDA_ITEM::GetPosition().

Referenced by RunERC().

◆ ercCheckNoConnects()

bool CONNECTION_GRAPH::ercCheckNoConnects ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for proper presence or absence of no-connect symbols.

A pin with a no-connect symbol should not have any connections A pin without a no-connect symbol should have at least one connection

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2783 of file connection_graph.cpp.

2784{
2785 ERC_SETTINGS& settings = m_schematic->ErcSettings();
2786 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2787 SCH_SCREEN* screen = sheet.LastScreen();
2788 bool ok = true;
2789 SCH_PIN* pin = nullptr;
2790
2791 std::set<SCH_PIN*> unique_pins;
2792 std::set<SCH_LABEL_BASE*> unique_labels;
2793
2794 wxString netName = GetResolvedSubgraphName( aSubgraph );
2795
2796 auto process_subgraph = [&]( const CONNECTION_SUBGRAPH* aProcessGraph )
2797 {
2798 // Any subgraph that contains a no-connect should not
2799 // more than one pin (which would indicate it is connected
2800
2801 for( SCH_ITEM* item : aProcessGraph->m_items )
2802 {
2803 switch( item->Type() )
2804 {
2805 case SCH_PIN_T:
2806 {
2807 SCH_PIN* test_pin = static_cast<SCH_PIN*>( item );
2808
2809 // Only link NC to pin on the current subgraph being checked
2810 if( aProcessGraph == aSubgraph )
2811 pin = test_pin;
2812
2813 if( std::none_of( unique_pins.begin(), unique_pins.end(),
2814 [test_pin]( SCH_PIN* aPin )
2815 {
2816 return test_pin->IsStacked( aPin );
2817 }
2818 ))
2819 {
2820 unique_pins.insert( test_pin );
2821 }
2822
2823 break;
2824 }
2825
2826 case SCH_LABEL_T:
2827 case SCH_GLOBAL_LABEL_T:
2828 case SCH_HIER_LABEL_T:
2829 unique_labels.insert( static_cast<SCH_LABEL_BASE*>( item ) );
2831 default:
2832 break;
2833 }
2834 }
2835 };
2836
2837 auto it = m_net_name_to_subgraphs_map.find( netName );
2838
2839 if( it != m_net_name_to_subgraphs_map.end() )
2840 {
2841 for( const CONNECTION_SUBGRAPH* subgraph : it->second )
2842 {
2843 process_subgraph( subgraph );
2844 }
2845 }
2846 else
2847 {
2848 process_subgraph( aSubgraph );
2849 }
2850
2851 if( aSubgraph->m_no_connect != nullptr )
2852 {
2853 if( unique_pins.size() > 1 && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
2854 {
2855 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
2856 VECTOR2I pos;
2857
2858 if( pin )
2859 {
2860 ercItem->SetItems( pin, aSubgraph->m_no_connect );
2861 pos = pin->GetTransformedPosition();
2862 }
2863 else
2864 {
2865 ercItem->SetItems( aSubgraph->m_no_connect );
2866 pos = aSubgraph->m_no_connect->GetPosition();
2867 }
2868
2869 SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2870 screen->Append( marker );
2871
2872 ok = false;
2873 }
2874
2875 if( unique_pins.empty() && unique_labels.empty() && settings.IsTestEnabled( ERCE_NOCONNECT_NOT_CONNECTED ) )
2876 {
2877 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
2878 ercItem->SetItems( aSubgraph->m_no_connect );
2879
2880 SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
2881 screen->Append( marker );
2882
2883 ok = false;
2884 }
2885 }
2886 else
2887 {
2888 bool has_other_connections = false;
2889 std::vector<SCH_PIN*> pins;
2890
2891 // Any subgraph that lacks a no-connect and contains a pin should also
2892 // contain at least one other potential driver
2893
2894 for( SCH_ITEM* item : aSubgraph->m_items )
2895 {
2896 switch( item->Type() )
2897 {
2898 case SCH_PIN_T:
2899 {
2900 // Stacked pins do not count as other connections but non-stacked pins do
2901 if( !has_other_connections && !pins.empty() )
2902 {
2903 SCH_PIN* test_pin = static_cast<SCH_PIN*>( item );
2904
2905 for( SCH_PIN* other_pin : pins )
2906 {
2907 if( !test_pin->IsStacked( other_pin ) )
2908 {
2909 has_other_connections = true;
2910 break;
2911 }
2912 }
2913 }
2914
2915 pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2916
2917 break;
2918 }
2919
2920 default:
2921 if( aSubgraph->GetDriverPriority( item ) != CONNECTION_SUBGRAPH::PRIORITY::NONE )
2922 has_other_connections = true;
2923
2924 break;
2925 }
2926 }
2927
2928 // For many checks, we can just use the first pin
2929 pin = pins.empty() ? nullptr : pins[0];
2930
2931 // But if there is a power pin, it might be connected elsewhere
2932 for( SCH_PIN* test_pin : pins )
2933 {
2934 if( test_pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN )
2935 {
2936 pin = test_pin;
2937 break;
2938 }
2939 }
2940
2941 // Check if invisible power input pins connect to anything else via net name,
2942 // but not for power symbols as the ones in the standard library all have invisible pins
2943 // and we want to throw unconnected errors for those even if they are connected to other
2944 // net items by name, because usually failing to connect them graphically is a mistake
2945 if( pin && !has_other_connections
2946 && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
2947 && !pin->IsVisible()
2948 && !pin->GetLibPin()->GetParent()->IsPower() )
2949 {
2950 wxString name = pin->Connection( &sheet )->Name();
2951 wxString local_name = pin->Connection( &sheet )->Name( true );
2952
2953 if( m_global_label_cache.count( name )
2954 || m_local_label_cache.count( std::make_pair( sheet, local_name ) ) )
2955 {
2956 has_other_connections = true;
2957 }
2958 }
2959
2960 // Only one pin, and it's not a no-connect pin
2961 if( pin && !has_other_connections
2962 && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
2963 && pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
2964 && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2965 {
2966 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2967 ercItem->SetItems( pin );
2968
2969 SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2970 screen->Append( marker );
2971
2972 ok = false;
2973 }
2974
2975 // If there are multiple pins in this SG, they might be indirectly connected (by netname)
2976 // rather than directly connected (by wires). We want to flag dangling pins even if they
2977 // join nets with another pin, as it's often a mistake
2978 if( pins.size() > 1 )
2979 {
2980 for( SCH_PIN* testPin : pins )
2981 {
2982 // We only apply this test to power symbols, because other symbols have invisible
2983 // pins that are meant to be dangling, but the KiCad standard library power symbols
2984 // have invisible pins that are *not* meant to be dangling.
2985 if( testPin->GetLibPin()->GetParent()->IsPower()
2986 && testPin->ConnectedItems( sheet ).empty()
2987 && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2988 {
2989 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2990 ercItem->SetItems( testPin );
2991
2992 SCH_MARKER* marker = new SCH_MARKER( ercItem,
2993 testPin->GetTransformedPosition() );
2994 screen->Append( marker );
2995
2996 ok = false;
2997 }
2998 }
2999 }
3000 }
3001
3002 return ok;
3003}
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
bool IsStacked(const SCH_PIN *aPin) const
Definition: sch_pin.cpp:248
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:117
@ ERCE_NOCONNECT_NOT_CONNECTED
A no connect symbol is not connected to anything.
Definition: erc_settings.h:49
@ ERCE_NOCONNECT_CONNECTED
A no connect symbol is connected to more than 1 pin.
Definition: erc_settings.h:48
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
@ 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.

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), CONNECTION_SUBGRAPH::GetDriverPriority(), EDA_ITEM::GetPosition(), GetResolvedSubgraphName(), SCH_PIN::IsStacked(), ERC_SETTINGS::IsTestEnabled(), KI_FALLTHROUGH, SCH_SHEET_PATH::LastScreen(), m_global_label_cache, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, name, CONNECTION_SUBGRAPH::NONE, pin, PT_NC, PT_NIC, PT_POWER_IN, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ FindFirstSubgraphByName()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::FindFirstSubgraphByName ( const wxString &  aNetName)

Retrieves a subgraph for the given net name, if one exists.

Searches every sheet

Parameters
aNetNameis the full net name to search for
Returns
the subgraph matching the query, or nullptr if none is found

Definition at line 2309 of file connection_graph.cpp.

2310{
2311 auto it = m_net_name_to_subgraphs_map.find( aNetName );
2312
2313 if( it == m_net_name_to_subgraphs_map.end() )
2314 return nullptr;
2315
2316 wxASSERT( !it->second.empty() );
2317
2318 return it->second[0];
2319}

References m_net_name_to_subgraphs_map.

◆ FindSubgraphByName()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::FindSubgraphByName ( const wxString &  aNetName,
const SCH_SHEET_PATH aPath 
)

Returns the subgraph for a given net name on a given sheet.

Parameters
aNetNameis the local net name to look for
aPathis a sheet path to look on
Returns
the subgraph matching the query, or nullptr if none is found

Definition at line 2288 of file connection_graph.cpp.

2290{
2291 auto it = m_net_name_to_subgraphs_map.find( aNetName );
2292
2293 if( it == m_net_name_to_subgraphs_map.end() )
2294 return nullptr;
2295
2296 for( CONNECTION_SUBGRAPH* sg : it->second )
2297 {
2298 // Cache is supposed to be valid by now
2299 wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
2300
2301 if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
2302 return sg;
2303 }
2304
2305 return nullptr;
2306}

References CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_driver_connection, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_sheet, and SCH_CONNECTION::Name().

Referenced by NETLIST_EXPORTER_BASE::CreatePinList(), and NETLIST_EXPORTER_BASE::findAllUnitsOfSymbol().

◆ generateInvisiblePinSubGraphs()

void CONNECTION_GRAPH::generateInvisiblePinSubGraphs ( )
private

Iterate through the invisible power pins to collect the global labels as drivers.

Definition at line 974 of file connection_graph.cpp.

975{
976 // Generate subgraphs for invisible power pins. These will be merged with other subgraphs
977 // on the same sheet in the next loop.
978
979 std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
980
981 for( const auto& it : m_invisible_power_pins )
982 {
983 SCH_SHEET_PATH sheet = it.first;
984 SCH_PIN* pin = it.second;
985
986 if( !pin->ConnectedItems( sheet ).empty() && !pin->GetLibPin()->GetParent()->IsPower() )
987 {
988 // ERC will warn about this: user has wired up an invisible pin
989 continue;
990 }
991
992 SCH_CONNECTION* connection = pin->GetOrInitConnection( sheet, this );
993
994 // If this pin already has a subgraph, don't need to process
995 if( !connection || connection->SubgraphCode() > 0 )
996 continue;
997
998 connection->SetName( pin->GetShownName() );
999
1000 int code = assignNewNetCode( *connection );
1001
1002 connection->SetNetCode( code );
1003
1004 CONNECTION_SUBGRAPH* subgraph;
1005 auto jj = invisible_pin_subgraphs.find( code );
1006
1007 if( jj != invisible_pin_subgraphs.end() )
1008 {
1009 subgraph = jj->second;
1010 subgraph->AddItem( pin );
1011 }
1012 else
1013 {
1014 subgraph = new CONNECTION_SUBGRAPH( this );
1015
1016 subgraph->m_code = m_last_subgraph_code++;
1017 subgraph->m_sheet = sheet;
1018
1019 subgraph->AddItem( pin );
1020 subgraph->ResolveDrivers();
1021
1022 NET_NAME_CODE_CACHE_KEY key = { subgraph->GetNetName(), code };
1023 m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1024 m_subgraphs.push_back( subgraph );
1025 m_driver_subgraphs.push_back( subgraph );
1026
1027 invisible_pin_subgraphs[code] = subgraph;
1028 }
1029
1030 connection->SetSubgraphCode( subgraph->m_code );
1031 }
1032}
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
void SetName(const wxString &aName)

References CONNECTION_SUBGRAPH::AddItem(), assignNewNetCode(), CONNECTION_SUBGRAPH::GetNetName(), CONNECTION_SUBGRAPH::m_code, m_driver_subgraphs, m_invisible_power_pins, m_last_subgraph_code, m_net_code_to_subgraphs_map, CONNECTION_SUBGRAPH::m_sheet, m_subgraphs, pin, CONNECTION_SUBGRAPH::ResolveDrivers(), SCH_CONNECTION::SetName(), SCH_CONNECTION::SetNetCode(), SCH_CONNECTION::SetSubgraphCode(), and SCH_CONNECTION::SubgraphCode().

Referenced by buildConnectionGraph().

◆ GetBusAlias()

std::shared_ptr< BUS_ALIAS > CONNECTION_GRAPH::GetBusAlias ( const wxString &  aName)

Returns a bus alias pointer for the given name if it exists (from cache)

CONNECTION_GRAPH caches these, they are owned by the SCH_SCREEN that the alias was defined on. The cache is only used to update the graph.

Definition at line 2208 of file connection_graph.cpp.

2209{
2210 auto it = m_bus_alias_cache.find( aName );
2211
2212 return it != m_bus_alias_cache.end() ? it->second : nullptr;
2213}

References m_bus_alias_cache.

Referenced by SCH_CONNECTION::AppendInfoToMsgPanel(), and SCH_CONNECTION::ConfigureFromLabel().

◆ GetBusesNeedingMigration()

std::vector< const CONNECTION_SUBGRAPH * > CONNECTION_GRAPH::GetBusesNeedingMigration ( )

Determines which subgraphs have more than one conflicting bus label.

See also
DIALOG_MIGRATE_BUSES
Returns
a list of subgraphs that need migration

Definition at line 2216 of file connection_graph.cpp.

2217{
2218 std::vector<const CONNECTION_SUBGRAPH*> ret;
2219
2220 for( CONNECTION_SUBGRAPH* subgraph : m_subgraphs )
2221 {
2222 // Graph is supposed to be up-to-date before calling this
2223 wxASSERT( !subgraph->m_dirty );
2224
2225 if( !subgraph->m_driver )
2226 continue;
2227
2228 SCH_CONNECTION* connection = subgraph->m_driver->Connection( &subgraph->m_sheet );
2229
2230 if( !connection->IsBus() )
2231 continue;
2232
2233 auto labels = subgraph->GetBusLabels();
2234
2235 if( labels.size() > 1 )
2236 {
2237 bool different = false;
2238 wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2239
2240 for( unsigned i = 1; i < labels.size(); ++i )
2241 {
2242 if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2243 {
2244 different = true;
2245 break;
2246 }
2247 }
2248
2249 if( !different )
2250 continue;
2251
2252 wxLogTrace( ConnTrace, wxS( "SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
2253 connection->Name() );
2254
2255 ret.push_back( subgraph );
2256 }
2257 }
2258
2259 return ret;
2260}
SCH_ITEM * m_driver
The SCH_ITEM that drives this connection's net.
wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
Definition: sch_text.cpp:342

References SCH_ITEM::Connection(), ConnTrace, SCH_TEXT::GetShownText(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::m_driver, m_subgraphs, and SCH_CONNECTION::Name().

Referenced by DIALOG_MIGRATE_BUSES::loadGraphData().

◆ getDefaultConnection()

std::shared_ptr< SCH_CONNECTION > CONNECTION_GRAPH::getDefaultConnection ( SCH_ITEM aItem,
CONNECTION_SUBGRAPH aSubgraph 
)
private

Builds a new default connection for the given item based on its properties.

Handles strong drivers (power pins and labels) only

Parameters
aItemis an item that can generate a connection name
aSubgraphis used to determine the sheet to use and retrieve the cached name
Returns
a connection generated from the item, or nullptr if item is not valid

Definition at line 2099 of file connection_graph.cpp.

2101{
2102 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>( nullptr );
2103
2104 switch( aItem->Type() )
2105 {
2106 case SCH_PIN_T:
2107 {
2108 SCH_PIN* pin = static_cast<SCH_PIN*>( aItem );
2109
2110 if( pin->IsPowerConnection() )
2111 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
2112
2113 break;
2114 }
2115
2116 case SCH_GLOBAL_LABEL_T:
2117 case SCH_HIER_LABEL_T:
2118 case SCH_LABEL_T:
2119 {
2120 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
2121 break;
2122 }
2123
2124 default:
2125 break;
2126 }
2127
2128 if( c )
2129 {
2130 c->SetGraph( this );
2131 c->ConfigureFromLabel( aSubgraph->GetNameForDriver( aItem ) );
2132 }
2133
2134 return c;
2135}

References CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::m_sheet, pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by processSubGraphs(), and propagateToNeighbors().

◆ GetNetMap()

◆ GetResolvedSubgraphName()

wxString CONNECTION_GRAPH::GetResolvedSubgraphName ( const CONNECTION_SUBGRAPH aSubGraph) const

Returns the fully-resolved netname for a given subgraph.

Parameters
aSubGraphReference to the subgraph
Returns
Netname string usable with m_net_name_to_subgraphs_map

Definition at line 2263 of file connection_graph.cpp.

2264{
2265 wxString retval = aSubGraph->GetNetName();
2266 bool found = false;
2267
2268 // This is a hacky way to find the true subgraph net name (why do we not store it?)
2269 // TODO: Remove once the actual netname of the subgraph is stored with the subgraph
2270
2271 for( auto it = m_net_name_to_subgraphs_map.begin(); it != m_net_name_to_subgraphs_map.end() && !found; ++it )
2272 {
2273 for( CONNECTION_SUBGRAPH* graph : it->second )
2274 {
2275 if( graph == aSubGraph )
2276 {
2277 retval = it->first;
2278 found = true;
2279 break;
2280 }
2281 }
2282 }
2283
2284 return retval;
2285}

References CONNECTION_SUBGRAPH::GetNetName(), and m_net_name_to_subgraphs_map.

Referenced by ercCheckLabels(), and ercCheckNoConnects().

◆ GetSubgraphForItem()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::GetSubgraphForItem ( SCH_ITEM aItem)

Definition at line 2322 of file connection_graph.cpp.

2323{
2324 auto it = m_item_to_subgraph_map.find( aItem );
2325 CONNECTION_SUBGRAPH* ret = it != m_item_to_subgraph_map.end() ? it->second : nullptr;
2326
2327 while( ret && ret->m_absorbed )
2328 ret = ret->m_absorbed_by;
2329
2330 return ret;
2331}

References CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, and m_item_to_subgraph_map.

Referenced by SCH_EDITOR_CONTROL::UpdateNetHighlighting().

◆ hasPins()

size_t CONNECTION_GRAPH::hasPins ( const CONNECTION_SUBGRAPH aLocSubgraph)
private

Get the number of pins in a given subgraph.

Parameters
aLocSubgraphSubgraph to search
Returns
total number of pins in the subgraph

Referenced by ercCheckLabels().

◆ matchBusMember()

SCH_CONNECTION * CONNECTION_GRAPH::matchBusMember ( SCH_CONNECTION aBusConnection,
SCH_CONNECTION aSearch 
)
staticprivate

Search for a matching bus member inside a bus connection.

For bus groups, this returns a bus member that matches aSearch by name. For bus vectors, this returns a bus member that matches by vector index.

Parameters
aBusConnectionis the bus connection to search
aSearchis the net connection to search for
Returns
a member of aBusConnection that matches aSearch

Definition at line 2138 of file connection_graph.cpp.

2140{
2141 wxASSERT( aBusConnection->IsBus() );
2142
2143 SCH_CONNECTION* match = nullptr;
2144
2145 if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
2146 {
2147 // Vector bus: compare against index, because we allow the name
2148 // to be different
2149
2150 for( const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->Members() )
2151 {
2152 if( bus_member->VectorIndex() == aSearch->VectorIndex() )
2153 {
2154 match = bus_member.get();
2155 break;
2156 }
2157 }
2158 }
2159 else
2160 {
2161 // Group bus
2162 for( const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->Members() )
2163 {
2164 // Vector inside group: compare names, because for bus groups
2165 // we expect the naming to be consistent across all usages
2166 // TODO(JE) explain this in the docs
2167 if( c->Type() == CONNECTION_TYPE::BUS )
2168 {
2169 for( const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
2170 {
2171 if( bus_member->LocalName() == aSearch->LocalName() )
2172 {
2173 match = bus_member.get();
2174 break;
2175 }
2176 }
2177 }
2178 else if( c->LocalName() == aSearch->LocalName() )
2179 {
2180 match = c.get();
2181 break;
2182 }
2183 }
2184 }
2185
2186 return match;
2187}
CONNECTION_TYPE Type() const
wxString LocalName() const
long VectorIndex() const

References BUS, SCH_CONNECTION::IsBus(), SCH_CONNECTION::LocalName(), SCH_CONNECTION::Members(), SCH_CONNECTION::Type(), and SCH_CONNECTION::VectorIndex().

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ processSubGraphs()

void CONNECTION_GRAPH::processSubGraphs ( )
private

Process all subgraphs to assign netcodes and merge subgraphs based on labels.

Definition at line 1035 of file connection_graph.cpp.

1036{
1037 // Here we do all the local (sheet) processing of each subgraph, including assigning net
1038 // codes, merging subgraphs together that use label connections, etc.
1039
1040 // Cache remaining valid subgraphs by sheet path
1041 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1042 m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1043
1044 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1045
1046 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1047 {
1048 if( subgraph->m_absorbed )
1049 continue;
1050
1051 SCH_CONNECTION* connection = subgraph->m_driver_connection;
1052 SCH_SHEET_PATH sheet = subgraph->m_sheet;
1053 wxString name = connection->Name();
1054
1055 // Test subgraphs with weak drivers for net name conflicts and fix them
1056 unsigned suffix = 1;
1057
1058 auto create_new_name =
1059 [&suffix]( SCH_CONNECTION* aConn ) -> wxString
1060 {
1061 wxString newName;
1062 wxString suffixStr = std::to_wstring( suffix );
1063
1064 // For group buses with a prefix, we can add the suffix to the prefix.
1065 // If they don't have a prefix, we force the creation of a prefix so that
1066 // two buses don't get inadvertently shorted together.
1067 if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1068 {
1069 wxString prefix = aConn->BusPrefix();
1070
1071 if( prefix.empty() )
1072 prefix = wxT( "BUS" ); // So result will be "BUS_1{...}"
1073
1074 wxString oldName = aConn->Name().AfterFirst( '{' );
1075
1076 newName << prefix << wxT( "_" ) << suffixStr << wxT( "{" ) << oldName;
1077
1078 aConn->ConfigureFromLabel( newName );
1079 }
1080 else
1081 {
1082 newName << aConn->Name() << wxT( "_" ) << suffixStr;
1083 aConn->SetSuffix( wxString( wxT( "_" ) ) << suffixStr );
1084 }
1085
1086 suffix++;
1087 return newName;
1088 };
1089
1090 if( !subgraph->m_strong_driver )
1091 {
1092 std::vector<CONNECTION_SUBGRAPH*>* vec = &m_net_name_to_subgraphs_map.at( name );
1093
1094 // If we are a unique bus vector, check if we aren't actually unique because of another
1095 // subgraph with a similar bus vector
1096 if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1097 {
1098 wxString prefixOnly = name.BeforeFirst( '[' ) + wxT( "[]" );
1099 vec = &m_net_name_to_subgraphs_map.at( prefixOnly );
1100 }
1101
1102 if( vec->size() > 1 )
1103 {
1104 wxString new_name = create_new_name( connection );
1105
1106 while( m_net_name_to_subgraphs_map.count( new_name ) )
1107 new_name = create_new_name( connection );
1108
1109 wxLogTrace( ConnTrace, wxS( "%ld (%s) is weakly driven and not unique. Changing to %s." ),
1110 subgraph->m_code, name, new_name );
1111
1112 alg::delete_matching( *vec, subgraph );
1113
1114 m_net_name_to_subgraphs_map[new_name].emplace_back( subgraph );
1115
1116 name = new_name;
1117 }
1118 else
1119 {
1120 // If there is no conflict, promote sheet pins to be strong drivers so that they
1121 // will be considered below for propagation/merging.
1122
1123 // It is possible for this to generate a conflict if the sheet pin has the same
1124 // name as a global label on the same sheet, because global merging will then treat
1125 // this subgraph as if it had a matching local label. So, for those cases, we
1126 // don't apply this promotion
1127
1128 if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1129 {
1130 bool conflict = false;
1131 wxString global_name = connection->Name( true );
1132 auto kk = m_net_name_to_subgraphs_map.find( global_name );
1133
1134 if( kk != m_net_name_to_subgraphs_map.end() )
1135 {
1136 // A global will conflict if it is on the same sheet as this subgraph, since
1137 // it would be connected by implicit local label linking
1138 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1139
1140 for( const CONNECTION_SUBGRAPH* candidate : candidates )
1141 {
1142 if( candidate->m_sheet == sheet )
1143 conflict = true;
1144 }
1145 }
1146
1147 if( conflict )
1148 {
1149 wxLogTrace( ConnTrace,
1150 wxS( "%ld (%s) skipped for promotion due to potential conflict" ),
1151 subgraph->m_code, name );
1152 }
1153 else
1154 {
1156
1157 wxLogTrace( ConnTrace,
1158 wxS( "%ld (%s) weakly driven by unique sheet pin %s, promoting" ),
1159 subgraph->m_code, name,
1160 subgraph->m_driver->GetItemDescription( &unitsProvider ) );
1161
1162 subgraph->m_strong_driver = true;
1163 }
1164 }
1165 }
1166 }
1167
1168 // Assign net codes
1169
1170 if( connection->IsBus() )
1171 {
1172 int code = -1;
1173 auto it = m_bus_name_to_code_map.find( name );
1174
1175 if( it != m_bus_name_to_code_map.end() )
1176 {
1177 code = it->second;
1178 }
1179 else
1180 {
1181 code = m_last_bus_code++;
1182 m_bus_name_to_code_map[ name ] = code;
1183 }
1184
1185 connection->SetBusCode( code );
1186 assignNetCodesToBus( connection );
1187 }
1188 else
1189 {
1190 assignNewNetCode( *connection );
1191 }
1192
1193 // Reset the flag for the next loop below
1194 subgraph->m_dirty = true;
1195
1196 // Next, we merge together subgraphs that have label connections, and create
1197 // neighbor links for subgraphs that are part of a bus on the same sheet.
1198 // For merging, we consider each possible strong driver.
1199
1200 // If this subgraph doesn't have a strong driver, let's skip it, since there is no
1201 // way it will be merged with anything.
1202
1203 if( !subgraph->m_strong_driver )
1204 continue;
1205
1206 // candidate_subgraphs will contain each valid, non-bus subgraph on the same sheet
1207 // as the subgraph we are considering that has a strong driver.
1208 // Weakly driven subgraphs are not considered since they will never be absorbed or
1209 // form neighbor links.
1210
1211 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1212 std::copy_if( m_sheet_to_subgraphs_map[ subgraph->m_sheet ].begin(),
1213 m_sheet_to_subgraphs_map[ subgraph->m_sheet ].end(),
1214 std::back_inserter( candidate_subgraphs ),
1215 [&] ( const CONNECTION_SUBGRAPH* candidate )
1216 {
1217 return ( !candidate->m_absorbed &&
1218 candidate->m_strong_driver &&
1219 candidate != subgraph );
1220 } );
1221
1222 // This is a list of connections on the current subgraph to compare to the
1223 // drivers of each candidate subgraph. If the current subgraph is a bus,
1224 // we should consider each bus member.
1225 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1226
1227 // Also check the main driving connection
1228 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1229
1230 auto add_connections_to_check =
1231 [&] ( CONNECTION_SUBGRAPH* aSubgraph )
1232 {
1233 for( SCH_ITEM* possible_driver : aSubgraph->m_items )
1234 {
1235 if( possible_driver == aSubgraph->m_driver )
1236 continue;
1237
1238 auto c = getDefaultConnection( possible_driver, aSubgraph );
1239
1240 if( c )
1241 {
1242 if( c->Type() != aSubgraph->m_driver_connection->Type() )
1243 continue;
1244
1245 if( c->Name( true ) == aSubgraph->m_driver_connection->Name( true ) )
1246 continue;
1247
1248 connections_to_check.push_back( c );
1249 wxLogTrace( ConnTrace,
1250 wxS( "%lu (%s): Adding secondary driver %s" ), aSubgraph->m_code,
1251 aSubgraph->m_driver_connection->Name( true ),
1252 c->Name( true ) );
1253 }
1254 }
1255 };
1256
1257 // Now add other strong drivers
1258 // The actual connection attached to these items will have been overwritten
1259 // by the chosen driver of the subgraph, so we need to create a dummy connection
1260 add_connections_to_check( subgraph );
1261
1262 for( unsigned i = 0; i < connections_to_check.size(); i++ )
1263 {
1264 auto member = connections_to_check[i];
1265
1266 if( member->IsBus() )
1267 {
1268 connections_to_check.insert( connections_to_check.end(),
1269 member->Members().begin(),
1270 member->Members().end() );
1271 }
1272
1273 wxString test_name = member->Name( true );
1274
1275 for( CONNECTION_SUBGRAPH* candidate : candidate_subgraphs )
1276 {
1277 if( candidate->m_absorbed )
1278 continue;
1279
1280 bool match = false;
1281
1282 if( candidate->m_driver_connection->Name( true ) == test_name )
1283 {
1284 match = true;
1285 }
1286 else
1287 {
1288 if( !candidate->m_multiple_drivers )
1289 continue;
1290
1291 for( SCH_ITEM *driver : candidate->m_drivers )
1292 {
1293 if( driver == candidate->m_driver )
1294 continue;
1295
1296 // Sheet pins are not candidates for merging
1297 if( driver->Type() == SCH_SHEET_PIN_T )
1298 continue;
1299
1300 if( driver->Type() == SCH_PIN_T )
1301 {
1302 auto pin = static_cast<SCH_PIN*>( driver );
1303
1304 if( pin->IsPowerConnection() && pin->GetShownName() == test_name )
1305 {
1306 match = true;
1307 break;
1308 }
1309 }
1310 else
1311 {
1312 wxASSERT( driver->Type() == SCH_LABEL_T ||
1313 driver->Type() == SCH_GLOBAL_LABEL_T ||
1314 driver->Type() == SCH_HIER_LABEL_T );
1315
1316 if( subgraph->GetNameForDriver( driver ) == test_name )
1317 {
1318 match = true;
1319 break;
1320 }
1321 }
1322 }
1323 }
1324
1325 if( match )
1326 {
1327 if( connection->IsBus() && candidate->m_driver_connection->IsNet() )
1328 {
1329 wxLogTrace( ConnTrace, wxS( "%lu (%s) has bus child %lu (%s)" ), subgraph->m_code,
1330 connection->Name(), candidate->m_code, member->Name() );
1331
1332 subgraph->m_bus_neighbors[member].insert( candidate );
1333 candidate->m_bus_parents[member].insert( subgraph );
1334 }
1335 else
1336 {
1337 wxLogTrace( ConnTrace, wxS( "%lu (%s) absorbs neighbor %lu (%s)" ),
1338 subgraph->m_code, connection->Name(),
1339 candidate->m_code, candidate->m_driver_connection->Name() );
1340
1341 // Candidate may have other non-chosen drivers we need to follow
1342 add_connections_to_check( candidate );
1343
1344 subgraph->Absorb( candidate );
1345 invalidated_subgraphs.insert( subgraph );
1346 }
1347 }
1348 }
1349 }
1350 }
1351
1352 // Update any subgraph that was invalidated above
1353 for( CONNECTION_SUBGRAPH* subgraph : invalidated_subgraphs )
1354 {
1355 if( subgraph->m_absorbed )
1356 continue;
1357
1358 subgraph->ResolveDrivers();
1359
1360 if( subgraph->m_driver_connection->IsBus() )
1361 assignNetCodesToBus( subgraph->m_driver_connection );
1362 else
1363 assignNewNetCode( *subgraph->m_driver_connection );
1364
1365 wxLogTrace( ConnTrace, wxS( "Re-resolving drivers for %lu (%s)" ), subgraph->m_code,
1366 subgraph->m_driver_connection->Name() );
1367 }
1368
1369}
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.
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensures all members of the bus connection have a valid net code assigned.
std::unordered_map< wxString, int > m_bus_name_to_code_map
void SetBusCode(int aCode)
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
Definition: kicad_algo.h:164
@ BUS_GROUP
This item represents a bus group.

References assignNetCodesToBus(), assignNewNetCode(), BUS, BUS_GROUP, ConnTrace, alg::delete_matching(), getDefaultConnection(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::IsNet(), CONNECTION_SUBGRAPH::m_absorbed, m_bus_name_to_code_map, CONNECTION_SUBGRAPH::m_bus_parents, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, m_driver_subgraphs, CONNECTION_SUBGRAPH::m_drivers, m_last_bus_code, CONNECTION_SUBGRAPH::m_multiple_drivers, m_net_name_to_subgraphs_map, m_sheet_to_subgraphs_map, MILLIMETRES, name, SCH_CONNECTION::Name(), pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, schIUScale, SCH_CONNECTION::SetBusCode(), and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ propagateToNeighbors()

void CONNECTION_GRAPH::propagateToNeighbors ( CONNECTION_SUBGRAPH aSubgraph,
bool  aForce 
)
private

Updates all neighbors of a subgraph with this one's connectivity info.

If this subgraph contains hierarchical links, this method will descent the hierarchy and propagate the connectivity across all linked sheets.

Parameters
aSubgraphis the subgraph being processed
aForceprevents this routine from skipping subgraphs

Definition at line 1781 of file connection_graph.cpp.

1782{
1783 SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1784 std::vector<CONNECTION_SUBGRAPH*> search_list;
1785 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1786 std::vector<SCH_CONNECTION*> stale_bus_members;
1787
1788 auto visit =
1789 [&]( CONNECTION_SUBGRAPH* aParent )
1790 {
1791 for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1792 {
1793 SCH_SHEET_PATH path = aParent->m_sheet;
1794 path.push_back( pin->GetParent() );
1795
1796 auto it = m_sheet_to_subgraphs_map.find( path );
1797
1798 if( it == m_sheet_to_subgraphs_map.end() )
1799 continue;
1800
1801 for( CONNECTION_SUBGRAPH* candidate : it->second )
1802 {
1803 if( !candidate->m_strong_driver
1804 || candidate->m_hier_ports.empty()
1805 || visited.count( candidate ) )
1806 {
1807 continue;
1808 }
1809
1810 for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1811 {
1812 if( candidate->GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1813 {
1814 wxLogTrace( ConnTrace, wxS( "%lu: found child %lu (%s)" ), aParent->m_code,
1815 candidate->m_code, candidate->m_driver_connection->Name() );
1816
1817 candidate->m_hier_parent = aParent;
1818
1819 search_list.push_back( candidate );
1820 break;
1821 }
1822 }
1823 }
1824 }
1825
1826 for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1827 {
1828 SCH_SHEET_PATH path = aParent->m_sheet;
1829 path.pop_back();
1830
1831 auto it = m_sheet_to_subgraphs_map.find( path );
1832
1833 if( it == m_sheet_to_subgraphs_map.end() )
1834 continue;
1835
1836 for( CONNECTION_SUBGRAPH* candidate : it->second )
1837 {
1838 if( candidate->m_hier_pins.empty()
1839 || visited.count( candidate )
1840 || candidate->m_driver_connection->Type() != aParent->m_driver_connection->Type() )
1841 {
1842 continue;
1843 }
1844
1845 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
1846
1847 for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1848 {
1849 // If the last sheet UUIDs won't match, no need to check the full path
1850 if( pin->GetParent()->m_Uuid != last_parent_uuid )
1851 continue;
1852
1853 SCH_SHEET_PATH pin_path = path;
1854 pin_path.push_back( pin->GetParent() );
1855
1856 if( pin_path != aParent->m_sheet )
1857 continue;
1858
1859 if( aParent->GetNameForDriver( label ) == candidate->GetNameForDriver( pin ) )
1860 {
1861 wxLogTrace( ConnTrace, wxS( "%lu: found additional parent %lu (%s)" ),
1862 aParent->m_code, candidate->m_code,
1863 candidate->m_driver_connection->Name() );
1864
1865 search_list.push_back( candidate );
1866 break;
1867 }
1868 }
1869 }
1870 }
1871 };
1872
1873 auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1874 for( const auto& kv : aParentGraph->m_bus_neighbors )
1875 {
1876 for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1877 {
1878 // May have been absorbed but won't have been deleted
1879 while( neighbor->m_absorbed )
1880 neighbor = neighbor->m_absorbed_by;
1881
1882 SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1883
1884 // Now member may be out of date, since we just cloned the
1885 // connection from higher up in the hierarchy. We need to
1886 // figure out what the actual new connection is.
1887 SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1888
1889 if( !member )
1890 {
1891 // Try harder: we might match on a secondary driver
1892 for( CONNECTION_SUBGRAPH* sg : kv.second )
1893 {
1894 if( sg->m_multiple_drivers )
1895 {
1896 SCH_SHEET_PATH sheet = sg->m_sheet;
1897
1898 for( SCH_ITEM* driver : sg->m_drivers )
1899 {
1900 auto c = getDefaultConnection( driver, sg );
1901 member = matchBusMember( parent, c.get() );
1902
1903 if( member )
1904 break;
1905 }
1906 }
1907
1908 if( member )
1909 break;
1910 }
1911 }
1912
1913 // This is bad, probably an ERC error
1914 if( !member )
1915 {
1916 wxLogTrace( ConnTrace, wxS( "Could not match bus member %s in %s" ),
1917 kv.first->Name(), parent->Name() );
1918 continue;
1919 }
1920
1921 auto neighbor_conn = neighbor->m_driver_connection;
1922 auto neighbor_name = neighbor_conn->Name();
1923
1924 // Matching name: no update needed
1925 if( neighbor_name == member->Name() )
1926 continue;
1927
1928 // Was this neighbor already updated from a different sheet? Don't rename it again
1929 if( neighbor_conn->Sheet() != neighbor->m_sheet )
1930 continue;
1931
1932 // Safety check against infinite recursion
1933 wxASSERT( neighbor_conn->IsNet() );
1934
1935 wxLogTrace( ConnTrace, wxS( "%lu (%s) connected to bus member %s (local %s)" ),
1936 neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1937
1938 // Take whichever name is higher priority
1941 {
1942 member->Clone( *neighbor_conn );
1943 stale_bus_members.push_back( member );
1944 }
1945 else
1946 {
1947 neighbor_conn->Clone( *member );
1948
1949 recacheSubgraphName( neighbor, neighbor_name );
1950
1951 // Recurse onto this neighbor in case it needs to re-propagate
1952 neighbor->m_dirty = true;
1953 propagateToNeighbors( neighbor, aForce );
1954 }
1955 }
1956 }
1957 };
1958
1959 // If we are a bus, we must propagate to local neighbors and then the hierarchy
1960 if( conn->IsBus() )
1961 propagate_bus_neighbors( aSubgraph );
1962
1963 // If we have both ports and pins, skip processing as we'll be visited by a parent or child.
1964 // If we only have one or the other, process (we can either go bottom-up or top-down depending
1965 // on which subgraph comes up first)
1966 if( !aForce && !aSubgraph->m_hier_ports.empty() && !aSubgraph->m_hier_pins.empty() )
1967 {
1968 wxLogTrace( ConnTrace, wxS( "%lu (%s) has both hier ports and pins; deferring processing" ),
1969 aSubgraph->m_code, conn->Name() );
1970 return;
1971 }
1972 else if( aSubgraph->m_hier_ports.empty() && aSubgraph->m_hier_pins.empty() )
1973 {
1974 wxLogTrace( ConnTrace, wxS( "%lu (%s) has no hier pins or ports; marking clean" ),
1975 aSubgraph->m_code, conn->Name() );
1976 aSubgraph->m_dirty = false;
1977 return;
1978 }
1979
1980 visited.insert( aSubgraph );
1981
1982 wxLogTrace( ConnTrace, wxS( "Propagating %lu (%s) to subsheets" ),
1983 aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1984
1985 visit( aSubgraph );
1986
1987 for( unsigned i = 0; i < search_list.size(); i++ )
1988 {
1989 auto child = search_list[i];
1990
1991 visited.insert( child );
1992
1993 visit( child );
1994
1995 child->m_dirty = false;
1996 }
1997
1998 // Now, find the best driver for this chain of subgraphs
1999 CONNECTION_SUBGRAPH* bestDriver = aSubgraph;
2002 bool bestIsStrong = ( highest >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
2003 wxString bestName = aSubgraph->m_driver_connection->Name();
2004
2005 // Check if a subsheet has a higher-priority connection to the same net
2007 {
2008 for( CONNECTION_SUBGRAPH* subgraph : visited )
2009 {
2010 if( subgraph == aSubgraph )
2011 continue;
2012
2014 CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
2015
2016 bool candidateStrong = ( priority >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
2017 wxString candidateName = subgraph->m_driver_connection->Name();
2018 bool shorterPath = subgraph->m_sheet.size() < bestDriver->m_sheet.size();
2019 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->m_sheet.size();
2020
2021 // Pick a better driving subgraph if it:
2022 // a) has a power pin or global driver
2023 // b) is a strong driver and we're a weak driver
2024 // c) is a higher priority strong driver
2025 // d) matches our priority, is a strong driver, and has a shorter path
2026 // e) matches our strength and is at least as short, and is alphabetically lower
2027
2028 if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
2029 ( !bestIsStrong && candidateStrong ) ||
2030 ( priority > highest && candidateStrong ) ||
2031 ( priority == highest && candidateStrong && shorterPath ) ||
2032 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
2033 ( candidateName < bestName ) ) )
2034 {
2035 bestDriver = subgraph;
2036 highest = priority;
2037 bestIsStrong = candidateStrong;
2038 bestName = candidateName;
2039 }
2040 }
2041 }
2042
2043 if( bestDriver != aSubgraph )
2044 {
2045 wxLogTrace( ConnTrace, wxS( "%lu (%s) overridden by new driver %lu (%s)" ),
2046 aSubgraph->m_code, aSubgraph->m_driver_connection->Name(), bestDriver->m_code,
2047 bestDriver->m_driver_connection->Name() );
2048 }
2049
2050 conn = bestDriver->m_driver_connection;
2051
2052 for( CONNECTION_SUBGRAPH* subgraph : visited )
2053 {
2054 wxString old_name = subgraph->m_driver_connection->Name();
2055
2056 subgraph->m_driver_connection->Clone( *conn );
2057
2058 if( old_name != conn->Name() )
2059 recacheSubgraphName( subgraph, old_name );
2060
2061 if( conn->IsBus() )
2062 propagate_bus_neighbors( subgraph );
2063 }
2064
2065 // Somewhere along the way, a bus member may have been upgraded to a global or power label.
2066 // Because this can happen anywhere, we need a second pass to update all instances of that bus
2067 // member to have the correct connection info
2068 if( conn->IsBus() && !stale_bus_members.empty() )
2069 {
2070 for( SCH_CONNECTION* stale_member : stale_bus_members )
2071 {
2072 for( CONNECTION_SUBGRAPH* subgraph : visited )
2073 {
2074 SCH_CONNECTION* member = matchBusMember( subgraph->m_driver_connection,
2075 stale_member );
2076
2077 if( !member )
2078 {
2079 wxLogTrace( ConnTrace, wxS( "WARNING: failed to match stale member %s in %s." ),
2080 stale_member->Name(), subgraph->m_driver_connection->Name() );
2081 continue;
2082 }
2083
2084 wxLogTrace( ConnTrace, wxS( "Updating %lu (%s) member %s to %s" ), subgraph->m_code,
2085 subgraph->m_driver_connection->Name(), member->LocalName(),
2086 stale_member->Name() );
2087
2088 member->Clone( *stale_member );
2089
2090 propagate_bus_neighbors( subgraph );
2091 }
2092 }
2093 }
2094
2095 aSubgraph->m_dirty = false;
2096}
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_HIERLABEL * > m_hier_ports
std::vector< SCH_SHEET_PIN * > m_hier_pins
CONNECTION_SUBGRAPH * m_hier_parent
Definition: kiid.h:48
size_t size() const
Forwarded method from std::vector.
#define kv

References SCH_CONNECTION::Clone(), ConnTrace, getDefaultConnection(), CONNECTION_SUBGRAPH::GetDriverPriority(), CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::HIER_LABEL, SCH_CONNECTION::IsBus(), kv, SCH_CONNECTION::LocalName(), CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_hier_pins, CONNECTION_SUBGRAPH::m_hier_ports, CONNECTION_SUBGRAPH::m_multiple_drivers, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, CONNECTION_SUBGRAPH::m_strong_driver, matchBusMember(), SCH_CONNECTION::Name(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, propagateToNeighbors(), SCH_SHEET_PATH::push_back(), recacheSubgraphName(), SCH_SHEET_PATH::size(), and SCH_CONNECTION::Type().

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ recacheSubgraphName()

void CONNECTION_GRAPH::recacheSubgraphName ( CONNECTION_SUBGRAPH aSubgraph,
const wxString &  aOldName 
)
private

Definition at line 2190 of file connection_graph.cpp.

2192{
2193 auto it = m_net_name_to_subgraphs_map.find( aOldName );
2194
2195 if( it != m_net_name_to_subgraphs_map.end() )
2196 {
2197 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2198 alg::delete_matching( vec, aSubgraph );
2199 }
2200
2201 wxLogTrace( ConnTrace, wxS( "recacheSubgraphName: %s => %s" ), aOldName,
2202 aSubgraph->m_driver_connection->Name() );
2203
2204 m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
2205}

References ConnTrace, alg::delete_matching(), CONNECTION_SUBGRAPH::m_driver_connection, m_net_name_to_subgraphs_map, and SCH_CONNECTION::Name().

Referenced by propagateToNeighbors().

◆ Recalculate()

void CONNECTION_GRAPH::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.

Parameters
aSheetListis the list of possibly modified sheets
aUnconditionalis true if an unconditional full recalculation should be done
aChangedItemHandleran optional handler to receive any changed items

Definition at line 455 of file connection_graph.cpp.

457{
458 PROF_TIMER recalc_time( "CONNECTION_GRAPH::Recalculate" );
459
460 if( aUnconditional )
461 Reset();
462
463 PROF_TIMER update_items( "updateItemConnectivity" );
464
465 m_sheetList = aSheetList;
466
467 for( const SCH_SHEET_PATH& sheet : aSheetList )
468 {
469 std::vector<SCH_ITEM*> items;
470 // Store current unit value, to regenerate it after calculations
471 // (useful in complex hierarchies)
472 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
473
474 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
475 {
476 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
477 items.push_back( item );
478
479 // Ensure the hierarchy info stored in SCREENS is built and up to date
480 // (multi-unit symbols)
481 if( item->Type() == SCH_SYMBOL_T )
482 {
483 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
484 int new_unit = symbol->GetUnitSelection( &sheet );
485
486 // Store the initial unit value, to regenerate it after calculations,
487 // if modified
488 if( symbol->GetUnit() != new_unit )
489 symbolsChanged.push_back( { symbol, symbol->GetUnit() } );
490
491 symbol->UpdateUnit( new_unit );
492 }
493 }
494
495 m_items.reserve( m_items.size() + items.size() );
496
497 updateItemConnectivity( sheet, items );
498
499 // UpdateDanglingState() also adds connected items for SCH_TEXT
500 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
501
502 // Restore the m_unit member, to avoid changes in current active sheet path
503 // after calculations
504 for( auto& item : symbolsChanged )
505 {
506 item.first->UpdateUnit( item.second );
507 }
508 }
509
510 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
511 update_items.Show();
512
513 PROF_TIMER build_graph( "buildConnectionGraph" );
514
515 buildConnectionGraph( aChangedItemHandler );
516
517 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
518 build_graph.Show();
519
520 recalc_time.Stop();
521
522 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
523 recalc_time.Show();
524}
void buildConnectionGraph(std::function< void(SCH_ITEM *)> *aChangedItemHandler)
Generates the connection graph (after all item connectivity has been updated)
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
Schematic symbol object.
Definition: sch_symbol.h:81
int GetUnit() const
Definition: sch_symbol.h:228
void UpdateUnit(int aUnit)
Change the unit number to aUnit without setting any internal flags.
Definition: sch_symbol.cpp:394
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:771
@ SCH_SYMBOL_T
Definition: typeinfo.h:156

References SCH_SYMBOL::GetUnit(), SCH_SYMBOL::GetUnitSelection(), m_items, m_sheetList, Reset(), SCH_SYMBOL_T, and updateItemConnectivity().

Referenced by EESCHEMA_HELPERS::LoadSchematic(), SCH_EDIT_FRAME::RecalculateConnections(), and SCH_SCREENS::UpdateSymbolLinks().

◆ Reset()

◆ resolveAllDrivers()

void CONNECTION_GRAPH::resolveAllDrivers ( )
private

Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel.

Definition at line 839 of file connection_graph.cpp.

840{
841 // Resolve drivers for subgraphs and propagate connectivity info
842 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
843
844 std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( dirty_graphs ),
845 [&] ( const CONNECTION_SUBGRAPH* candidate )
846 {
847 return candidate->m_dirty;
848 } );
849
850 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
851
852 auto update_lambda = []( CONNECTION_SUBGRAPH* subgraph ) -> size_t
853 {
854 if( !subgraph->m_dirty )
855 return 0;
856
857 // Special processing for some items
858 for( SCH_ITEM* item : subgraph->m_items )
859 {
860 switch( item->Type() )
861 {
862 case SCH_NO_CONNECT_T:
863 subgraph->m_no_connect = item;
864 break;
865
867 subgraph->m_bus_entry = item;
868 break;
869
870 case SCH_PIN_T:
871 {
872 auto pin = static_cast<SCH_PIN*>( item );
873
874 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
875 subgraph->m_no_connect = item;
876
877 break;
878 }
879
880 default:
881 break;
882 }
883 }
884
885 subgraph->ResolveDrivers( true );
886 subgraph->m_dirty = false;
887
888 return 1;
889 };
890
892
893 tp.push_loop( dirty_graphs.size(),
894 [&]( const int a, const int b)
895 {
896 for( int ii = a; ii < b; ++ii )
897 update_lambda( dirty_graphs[ii] );
898 });
899 tp.wait_for_tasks();
900
901 // Now discard any non-driven subgraphs from further consideration
902
903 std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( m_driver_subgraphs ),
904 [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
905 {
906 return candidate->m_driver;
907 } );
908}

References GetKiCadThreadPool(), m_driver_subgraphs, m_subgraphs, pin, PT_NC, SCH_BUS_WIRE_ENTRY_T, SCH_NO_CONNECT_T, SCH_PIN_T, tp, and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ RunERC()

int CONNECTION_GRAPH::RunERC ( )

Runs electrical rule checks on the connectivity graph.

Precondition: graph is up-to-date

Returns
the number of errors found

NOTE:

We could check that labels attached to bus subgraphs follow the proper format (i.e. actually define a bus).

This check doesn't need to be here right now because labels won't actually be connected to bus wires if they aren't in the right format due to their TestDanglingEnds() implementation.

Definition at line 2334 of file connection_graph.cpp.

2335{
2336 int error_count = 0;
2337
2338 wxCHECK_MSG( m_schematic, true, wxS( "Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
2339
2340 ERC_SETTINGS& settings = m_schematic->ErcSettings();
2341
2342 // We don't want to run many ERC checks more than once on a given screen even though it may
2343 // represent multiple sheets with multiple subgraphs. We can tell these apart by drivers.
2344 std::set<SCH_ITEM*> seenDriverInstances;
2345
2346 for( CONNECTION_SUBGRAPH* subgraph : m_subgraphs )
2347 {
2348 // There shouldn't be any null sub-graph pointers.
2349 wxCHECK2( subgraph, continue );
2350
2351 // Graph is supposed to be up-to-date before calling RunERC()
2352 wxASSERT( !subgraph->m_dirty );
2353
2354 if( subgraph->m_absorbed )
2355 continue;
2356
2357 if( seenDriverInstances.count( subgraph->m_driver ) )
2358 continue;
2359
2360 if( subgraph->m_driver )
2361 seenDriverInstances.insert( subgraph->m_driver );
2362
2373 if( settings.IsTestEnabled( ERCE_DRIVER_CONFLICT ) )
2374 {
2375 if( !ercCheckMultipleDrivers( subgraph ) )
2376 error_count++;
2377 }
2378
2379 subgraph->ResolveDrivers( false );
2380
2381 if( settings.IsTestEnabled( ERCE_BUS_TO_NET_CONFLICT ) )
2382 {
2383 if( !ercCheckBusToNetConflicts( subgraph ) )
2384 error_count++;
2385 }
2386
2387 if( settings.IsTestEnabled( ERCE_BUS_ENTRY_CONFLICT ) )
2388 {
2389 if( !ercCheckBusToBusEntryConflicts( subgraph ) )
2390 error_count++;
2391 }
2392
2393 if( settings.IsTestEnabled( ERCE_BUS_TO_BUS_CONFLICT ) )
2394 {
2395 if( !ercCheckBusToBusConflicts( subgraph ) )
2396 error_count++;
2397 }
2398
2399 if( settings.IsTestEnabled( ERCE_WIRE_DANGLING ) )
2400 {
2401 if( !ercCheckFloatingWires( subgraph ) )
2402 error_count++;
2403 }
2404
2407 || settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2408 {
2409 if( !ercCheckNoConnects( subgraph ) )
2410 error_count++;
2411 }
2412
2414 || settings.IsTestEnabled( ERCE_GLOBLABEL ) )
2415 {
2416 if( !ercCheckLabels( subgraph ) )
2417 error_count++;
2418 }
2419 }
2420
2421 // Hierarchical sheet checking is done at the schematic level
2423 || settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2424 {
2425 error_count += ercCheckHierSheets();
2426 }
2427
2428 if( settings.IsTestEnabled( ERCE_NETCLASS_CONFLICT ) )
2429 {
2430 for( const auto& [ netname, subgraphs ] : m_net_name_to_subgraphs_map )
2431 {
2432 if( !ercCheckNetclassConflicts( subgraphs ) )
2433 error_count++;
2434 }
2435 }
2436
2437 return error_count;
2438}
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.
bool ercCheckNetclassConflicts(const std::vector< CONNECTION_SUBGRAPH * > &subgraphs)
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
int ercCheckHierSheets()
Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on th...
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between net and bus labels.
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper presence or absence of no-connect symbols.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.

References ercCheckBusToBusConflicts(), ercCheckBusToBusEntryConflicts(), ercCheckBusToNetConflicts(), ercCheckFloatingWires(), ercCheckHierSheets(), ercCheckLabels(), ercCheckMultipleDrivers(), ercCheckNetclassConflicts(), ercCheckNoConnects(), ERCE_BUS_ENTRY_CONFLICT, ERCE_BUS_TO_BUS_CONFLICT, ERCE_BUS_TO_NET_CONFLICT, ERCE_DRIVER_CONFLICT, ERCE_GLOBLABEL, ERCE_HIERACHICAL_LABEL, ERCE_LABEL_NOT_CONNECTED, ERCE_NETCLASS_CONFLICT, ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, ERCE_WIRE_DANGLING, SCHEMATIC::ErcSettings(), ERC_SETTINGS::IsTestEnabled(), m_net_name_to_subgraphs_map, m_schematic, and m_subgraphs.

Referenced by DIALOG_ERC::testErc().

◆ SetSchematic()

void CONNECTION_GRAPH::SetSchematic ( SCHEMATIC aSchematic)
inline

Definition at line 287 of file connection_graph.h.

288 {
289 m_schematic = aSchematic;
290 }

References m_schematic.

◆ updateItemConnectivity()

void CONNECTION_GRAPH::updateItemConnectivity ( const SCH_SHEET_PATH aSheet,
const std::vector< SCH_ITEM * > &  aItemList 
)
private

Updates the graphical connectivity between items (i.e.

where they touch) The items passed in must be on the same sheet.

In the first phase, all items in aItemList have their connections initialized for the given sheet (since they may have connections on more than one sheet, and each needs to be calculated individually). The graphical connection points for the item are added to a map that stores (x, y) -> [list of items].

Any item that is stored in the list of items that have a connection point at a given (x, y) location will eventually be electrically connected. This means that we can't store SCH_SYMBOLs in this map – we must store a structure that links a specific pin on a symbol back to that symbol: a SCH_PIN_CONNECTION. This wrapper class is a convenience for linking a pin and symbol to a specific (x, y) point.

In the second phase, we iterate over each value in the map, which is a vector of items that have overlapping connection points. After some checks to ensure that the items should actually connect, the items are linked together using ConnectedItems().

As a side effect, items are loaded into m_items for BuildConnectionGraph()

Parameters
aSheetis the path to the sheet of all items in the list
aItemListis a list of items to consider

Definition at line 527 of file connection_graph.cpp.

529{
530 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
531
532 for( SCH_ITEM* item : aItemList )
533 {
534 std::vector<VECTOR2I> points = item->GetConnectionPoints();
535 item->ConnectedItems( aSheet ).clear();
536
537 if( item->Type() == SCH_SHEET_T )
538 {
539 for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
540 {
541 pin->InitializeConnection( aSheet, this );
542
543 pin->ConnectedItems( aSheet ).clear();
544
545 connection_map[ pin->GetTextPos() ].push_back( pin );
546 m_items.emplace_back( pin );
547 }
548 }
549 else if( item->Type() == SCH_SYMBOL_T )
550 {
551 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
552
553 for( SCH_PIN* pin : symbol->GetPins( &aSheet ) )
554 {
555 pin->InitializeConnection( aSheet, this );
556
557 VECTOR2I pos = pin->GetPosition();
558
559 // because calling the first time is not thread-safe
560 pin->GetDefaultNetName( aSheet );
561 pin->ConnectedItems( aSheet ).clear();
562
563 // Invisible power pins need to be post-processed later
564
565 if( pin->IsPowerConnection() && !pin->IsVisible() )
566 m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) );
567
568 connection_map[ pos ].push_back( pin );
569 m_items.emplace_back( pin );
570 }
571 }
572 else
573 {
574 m_items.emplace_back( item );
575 SCH_CONNECTION* conn = item->InitializeConnection( aSheet, this );
576
577 // Set bus/net property here so that the propagation code uses it
578 switch( item->Type() )
579 {
580 case SCH_LINE_T:
581 conn->SetType( item->GetLayer() == LAYER_BUS ? CONNECTION_TYPE::BUS :
583 break;
584
587 // clean previous (old) links:
588 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] = nullptr;
589 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] = nullptr;
590 break;
591
592 case SCH_PIN_T:
594 break;
595
598 // clean previous (old) link:
599 static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item = nullptr;
600 break;
601
602 default:
603 break;
604 }
605
606 for( const VECTOR2I& point : points )
607 connection_map[ point ].push_back( item );
608 }
609
610 item->SetConnectivityDirty( false );
611 }
612
613 for( const auto& it : connection_map )
614 {
615 std::vector<SCH_ITEM*> connection_vec = it.second;
616 std::sort( connection_vec.begin(), connection_vec.end() );
617 connection_vec.erase( std::unique( connection_vec.begin(), connection_vec.end() ),
618 connection_vec.end() );
619
620 // Pre-scan to see if we have a bus at this location
621 SCH_LINE* busLine = aSheet.LastScreen()->GetBus( it.first );
622
623 std::mutex update_mutex;
624
625 auto update_lambda = [&]( SCH_ITEM* connected_item ) -> size_t
626 {
627 // Bus entries are special: they can have connection points in the
628 // middle of a wire segment, because the junction algo doesn't split
629 // the segment in two where you place a bus entry. This means that
630 // bus entries that don't land on the end of a line segment need to
631 // have "virtual" connection points to the segments they graphically
632 // touch.
633 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
634 {
635 // If this location only has the connection point of the bus
636 // entry itself, this means that either the bus entry is not
637 // connected to anything graphically, or that it is connected to
638 // a segment at some point other than at one of the endpoints.
639 if( connection_vec.size() == 1 )
640 {
641 if( busLine )
642 {
643 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
644 bus_entry->m_connected_bus_item = busLine;
645 }
646 }
647 }
648
649 // Bus-to-bus entries are treated just like bus wires
650 else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
651 {
652 if( connection_vec.size() < 2 )
653 {
654 if( busLine )
655 {
656 auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
657
658 if( it.first == bus_entry->GetPosition() )
659 bus_entry->m_connected_bus_items[0] = busLine;
660 else
661 bus_entry->m_connected_bus_items[1] = busLine;
662
663 std::lock_guard<std::mutex> lock( update_mutex );
664 bus_entry->AddConnectionTo( aSheet, busLine );
665 busLine->AddConnectionTo( aSheet, bus_entry );
666 }
667 }
668 }
669
670 // Change junctions to be on bus junction layer if they are touching a bus
671 else if( connected_item->Type() == SCH_JUNCTION_T )
672 {
673 connected_item->SetLayer( busLine ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
674 }
675
676 SCH_ITEM_SET& connected_set = connected_item->ConnectedItems( aSheet );
677 connected_set.reserve( connection_vec.size() );
678
679 for( SCH_ITEM* test_item : connection_vec )
680 {
681 bool bus_connection_ok = true;
682
683 if( test_item == connected_item )
684 continue;
685
686 // Set up the link between the bus entry net and the bus
687 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
688 {
689 if( test_item->GetLayer() == LAYER_BUS )
690 {
691 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
692 bus_entry->m_connected_bus_item = test_item;
693 }
694 }
695
696 // Bus entries only connect to bus lines on the end that is touching a bus line.
697 // If the user has overlapped another net line with the endpoint of the bus entry
698 // where the entry connects to a bus, we don't want to short-circuit it.
699 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
700 {
701 bus_connection_ok = !busLine || test_item->GetLayer() == LAYER_BUS;
702 }
703 else if( test_item->Type() == SCH_BUS_WIRE_ENTRY_T )
704 {
705 bus_connection_ok = !busLine || connected_item->GetLayer() == LAYER_BUS;
706 }
707
708 if( connected_item->ConnectionPropagatesTo( test_item ) &&
709 test_item->ConnectionPropagatesTo( connected_item ) &&
710 bus_connection_ok )
711 {
712 connected_set.push_back( test_item );
713 }
714 }
715
716 // If we got this far and did not find a connected bus item for a bus entry,
717 // we should do a manual scan in case there is a bus item on this connection
718 // point but we didn't pick it up earlier because there is *also* a net item here.
719 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
720 {
721 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
722
723 if( !bus_entry->m_connected_bus_item )
724 {
725 SCH_SCREEN* screen = aSheet.LastScreen();
726 SCH_LINE* bus = screen->GetBus( it.first );
727
728 if( bus )
729 bus_entry->m_connected_bus_item = bus;
730 }
731 }
732
733 return 1;
734 };
735
737
738 tp.push_loop( connection_vec.size(),
739 [&]( const int a, const int b)
740 {
741 for( int ii = a; ii < b; ++ii )
742 update_lambda( connection_vec[ii] );
743 });
744 tp.wait_for_tasks();
745 }
746}
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...
void AddConnectionTo(const SCH_SHEET_PATH &aPath, SCH_ITEM *aItem)
Add a connection link between this item and another.
Definition: sch_item.cpp:193
void SetConnectivityDirty(bool aDirty=true)
Definition: sch_item.h:415
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:433
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
@ LAYER_JUNCTION
Definition: layer_ids.h:346
@ LAYER_BUS_JUNCTION
Definition: layer_ids.h:384
@ NET
This item represents a net.
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:145
@ SCH_JUNCTION_T
Definition: typeinfo.h:142

References SCH_ITEM::AddConnectionTo(), BUS, SCH_SCREEN::GetBus(), GetKiCadThreadPool(), SCH_ITEM::GetLayer(), SCH_SYMBOL::GetPins(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, LAYER_BUS_JUNCTION, LAYER_JUNCTION, SCH_BUS_WIRE_ENTRY::m_connected_bus_item, SCH_BUS_BUS_ENTRY::m_connected_bus_items, m_invisible_power_pins, m_items, NET, pin, SCH_BUS_BUS_ENTRY_T, SCH_BUS_WIRE_ENTRY_T, SCH_JUNCTION_T, SCH_LINE_T, SCH_PIN_T, SCH_SHEET_T, SCH_SYMBOL_T, SCH_ITEM::SetConnectivityDirty(), SCH_CONNECTION::SetType(), and tp.

Referenced by Recalculate().

Member Data Documentation

◆ m_bus_alias_cache

std::unordered_map<wxString, std::shared_ptr<BUS_ALIAS> > CONNECTION_GRAPH::m_bus_alias_cache
private

Definition at line 593 of file connection_graph.h.

Referenced by buildConnectionGraph(), buildItemSubGraphs(), GetBusAlias(), and Reset().

◆ m_bus_name_to_code_map

std::unordered_map<wxString, int> CONNECTION_GRAPH::m_bus_name_to_code_map
private

Definition at line 597 of file connection_graph.h.

Referenced by processSubGraphs(), and Reset().

◆ m_driver_subgraphs

std::vector<CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_driver_subgraphs
private

◆ m_global_label_cache

std::unordered_map<wxString, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_global_label_cache
private

Definition at line 599 of file connection_graph.h.

Referenced by collectAllDriverValues(), ercCheckNoConnects(), and Reset().

◆ m_invisible_power_pins

std::vector<std::pair<SCH_SHEET_PATH, SCH_PIN*> > CONNECTION_GRAPH::m_invisible_power_pins
private

◆ m_item_to_subgraph_map

std::unordered_map<SCH_ITEM*, CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_item_to_subgraph_map
private

Definition at line 606 of file connection_graph.h.

Referenced by buildItemSubGraphs(), GetSubgraphForItem(), and Reset().

◆ m_items

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

Definition at line 580 of file connection_graph.h.

Referenced by buildItemSubGraphs(), Recalculate(), Reset(), and updateItemConnectivity().

◆ m_last_bus_code

int CONNECTION_GRAPH::m_last_bus_code
private

Definition at line 612 of file connection_graph.h.

Referenced by processSubGraphs(), and Reset().

◆ m_last_net_code

int CONNECTION_GRAPH::m_last_net_code
private

Definition at line 610 of file connection_graph.h.

Referenced by assignNewNetCode(), and Reset().

◆ m_last_subgraph_code

int CONNECTION_GRAPH::m_last_subgraph_code
private

Definition at line 614 of file connection_graph.h.

Referenced by buildItemSubGraphs(), generateInvisiblePinSubGraphs(), and Reset().

◆ m_local_label_cache

std::map< std::pair<SCH_SHEET_PATH, wxString>, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_local_label_cache
private

Definition at line 602 of file connection_graph.h.

Referenced by collectAllDriverValues(), ercCheckNoConnects(), and Reset().

◆ m_net_code_to_subgraphs_map

NET_MAP CONNECTION_GRAPH::m_net_code_to_subgraphs_map
private

◆ m_net_name_to_code_map

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

Definition at line 595 of file connection_graph.h.

Referenced by assignNewNetCode(), and Reset().

◆ m_net_name_to_subgraphs_map

std::unordered_map<wxString, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_net_name_to_subgraphs_map
private

◆ m_schematic

SCHEMATIC* CONNECTION_GRAPH::m_schematic
private

The schematic this graph represents.

Definition at line 616 of file connection_graph.h.

Referenced by buildConnectionGraph(), buildItemSubGraphs(), ercCheckHierSheets(), ercCheckLabels(), ercCheckNoConnects(), RunERC(), and SetSchematic().

◆ m_sheet_to_subgraphs_map

std::unordered_map<SCH_SHEET_PATH, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_sheet_to_subgraphs_map
private

◆ m_sheetList

SCH_SHEET_LIST CONNECTION_GRAPH::m_sheetList
private

Definition at line 577 of file connection_graph.h.

Referenced by ercCheckHierSheets(), and Recalculate().

◆ m_subgraphs

std::vector<CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_subgraphs
private

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