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)
 

Static Public Attributes

static bool m_allowRealTime = true
 

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 ()
 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)
 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 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...
 

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::map< wxString, int > m_net_name_to_code_map
 
std::map< wxString, int > m_bus_name_to_code_map
 
std::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::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 248 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCHEMATIC aSchematic = nullptr)
inline

Definition at line 251 of file connection_graph.h.

251  :
252  m_last_net_code( 1 ),
253  m_last_bus_code( 1 ),
255  m_schematic( aSchematic )
256  {}
SCHEMATIC * m_schematic
The schematic this graph represents.

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 258 of file connection_graph.h.

259  {
260  Reset();
261  }

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 1690 of file connection_graph.cpp.

1691 {
1692  auto connections_to_check( aConnection->Members() );
1693 
1694  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1695  {
1696  auto member = connections_to_check[i];
1697 
1698  if( member->IsBus() )
1699  {
1700  connections_to_check.insert( connections_to_check.end(),
1701  member->Members().begin(),
1702  member->Members().end() );
1703  continue;
1704  }
1705 
1706  assignNewNetCode( *member );
1707  }
1708 }
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 1668 of file connection_graph.cpp.

1669 {
1670  int code;
1671 
1672  auto it = m_net_name_to_code_map.find( aConnection.Name() );
1673 
1674  if( it == m_net_name_to_code_map.end() )
1675  {
1676  code = m_last_net_code++;
1677  m_net_name_to_code_map[ aConnection.Name() ] = code;
1678  }
1679  else
1680  {
1681  code = it->second;
1682  }
1683 
1684  aConnection.SetNetCode( code );
1685 
1686  return code;
1687 }
wxString Name(bool aIgnoreSheet=false) const
std::map< wxString, int > m_net_name_to_code_map
void SetNetCode(int aCode)

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 ( )
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 1356 of file connection_graph.cpp.

1357 {
1358  // Recache all bus aliases for later use
1359  wxCHECK_RET( m_schematic, wxT( "Connection graph cannot be built without schematic pointer" ) );
1360 
1361  SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
1362 
1363  for( unsigned i = 0; i < all_sheets.size(); i++ )
1364  {
1365  for( const auto& alias : all_sheets[i].LastScreen()->GetBusAliases() )
1366  m_bus_alias_cache[ alias->GetName() ] = alias;
1367  }
1368 
1369  PROF_TIMER sub_graph( "buildItemSubGraphs" );
1371 
1372  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
1373  sub_graph.Show();
1374 
1375 
1382 
1384 
1386 
1387  PROF_TIMER proc_sub_graph( "ProcessSubGraphs" );
1388  processSubGraphs();
1389 
1390  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
1391  proc_sub_graph.Show();
1392 
1393  // Absorbed subgraphs should no longer be considered
1394  alg::delete_if( m_driver_subgraphs, [&]( const CONNECTION_SUBGRAPH* candidate ) -> bool
1395  {
1396  return candidate->m_absorbed;
1397  } );
1398 
1399  // Store global subgraphs for later reference
1400  std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1401  std::copy_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1402  std::back_inserter( global_subgraphs ),
1403  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1404  {
1405  return !candidate->m_local_driver;
1406  } );
1407 
1408  // Recache remaining valid subgraphs by sheet path
1409  m_sheet_to_subgraphs_map.clear();
1410 
1411  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1412  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1413 
1414  // Update item connections at this point so that neighbor propagation works
1415  std::atomic<size_t> nextSubgraph( 0 );
1416 
1417  // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
1418  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
1419  ( m_subgraphs.size() + 3 ) / 4 );
1420 
1421  std::vector<std::future<size_t>> returns( parallelThreadCount );
1422 
1423  auto preliminaryUpdateTask =
1424  [&]() -> size_t
1425  {
1426  for( size_t subgraphId = nextSubgraph++;
1427  subgraphId < m_driver_subgraphs.size();
1428  subgraphId = nextSubgraph++ )
1429  {
1430  m_driver_subgraphs[subgraphId]->UpdateItemConnections();
1431  }
1432 
1433  return 1;
1434  };
1435 
1436  if( parallelThreadCount == 1 )
1437  preliminaryUpdateTask();
1438  else
1439  {
1440  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1441  returns[ii] = std::async( std::launch::async, preliminaryUpdateTask );
1442 
1443  // Finalize the threads
1444  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1445  returns[ii].wait();
1446  }
1447 
1448  // Next time through the subgraphs, we do some post-processing to handle things like
1449  // connecting bus members to their neighboring subgraphs, and then propagate connections
1450  // through the hierarchy
1451 
1452  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1453  {
1454  if( !subgraph->m_dirty )
1455  continue;
1456 
1457  wxLogTrace( ConnTrace, wxT( "Processing %lu (%s) for propagation" ), subgraph->m_code,
1458  subgraph->m_driver_connection->Name() );
1459 
1460  // For subgraphs that are driven by a global (power port or label) and have more
1461  // than one global driver, we need to seek out other subgraphs driven by the
1462  // same name as the non-chosen driver and update them to match the chosen one.
1463 
1464  if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1465  {
1466  for( SCH_ITEM* driver : subgraph->m_drivers )
1467  {
1468  if( driver == subgraph->m_driver )
1469  continue;
1470 
1471  wxString secondary_name = subgraph->GetNameForDriver( driver );
1472 
1473  if( secondary_name == subgraph->m_driver_connection->Name() )
1474  continue;
1475 
1476  bool secondary_is_global = CONNECTION_SUBGRAPH::GetDriverPriority( driver )
1478 
1479  for( CONNECTION_SUBGRAPH* candidate : global_subgraphs )
1480  {
1481  if( candidate == subgraph )
1482  continue;
1483 
1484  if( !secondary_is_global && candidate->m_sheet != subgraph->m_sheet )
1485  continue;
1486 
1487  SCH_CONNECTION* conn = candidate->m_driver_connection;
1488 
1489  if( conn->Name() == secondary_name )
1490  {
1491  wxLogTrace( ConnTrace, wxT( "Global %lu (%s) promoted to %s" ), candidate->m_code,
1492  conn->Name(), subgraph->m_driver_connection->Name() );
1493 
1494  conn->Clone( *subgraph->m_driver_connection );
1495 
1496  candidate->m_dirty = false;
1497  }
1498  }
1499  }
1500  }
1501 
1502  // This call will handle descending the hierarchy and updating child subgraphs
1503  propagateToNeighbors( subgraph );
1504  }
1505 
1506  // Handle buses that have been linked together somewhere by member (net) connections.
1507  // This feels a bit hacky, perhaps this algorithm should be revisited in the future.
1508 
1509  // For net subgraphs that have more than one bus parent, we need to ensure that those
1510  // buses are linked together in the final netlist. The final name of each bus might not
1511  // match the local name that was used to establish the parent-child relationship, because
1512  // the bus may have been renamed by a hierarchical connection. So, for each of these cases,
1513  // we need to identify the appropriate bus members to link together (and their final names),
1514  // and then update all instances of the old name in the hierarchy.
1515 
1516  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1517  {
1518  // All SGs should have been processed by propagateToNeighbors above
1519  wxASSERT_MSG( !subgraph->m_dirty, wxT( "Subgraph not processed by propagateToNeighbors!" ) );
1520 
1521  if( subgraph->m_bus_parents.size() < 2 )
1522  continue;
1523 
1524  SCH_CONNECTION* conn = subgraph->m_driver_connection;
1525 
1526  wxLogTrace( ConnTrace, wxT( "%lu (%s) has multiple bus parents" ),
1527  subgraph->m_code, conn->Name() );
1528 
1529  wxASSERT( conn->IsNet() );
1530 
1531  for( const auto& ii : subgraph->m_bus_parents )
1532  {
1533  SCH_CONNECTION* link_member = ii.first.get();
1534 
1535  for( CONNECTION_SUBGRAPH* parent : ii.second )
1536  {
1537  while( parent->m_absorbed )
1538  parent = parent->m_absorbed_by;
1539 
1540  SCH_CONNECTION* match = matchBusMember( parent->m_driver_connection, link_member );
1541 
1542  if( !match )
1543  {
1544  wxLogTrace( ConnTrace, wxT( "Warning: could not match %s inside %lu (%s)" ),
1545  conn->Name(), parent->m_code, parent->m_driver_connection->Name() );
1546  continue;
1547  }
1548 
1549  if( conn->Name() != match->Name() )
1550  {
1551  wxString old_name = match->Name();
1552 
1553  wxLogTrace( ConnTrace, wxT( "Updating %lu (%s) member %s to %s" ), parent->m_code,
1554  parent->m_driver_connection->Name(), old_name, conn->Name() );
1555 
1556  match->Clone( *conn );
1557 
1558  auto jj = m_net_name_to_subgraphs_map.find( old_name );
1559 
1560  if( jj == m_net_name_to_subgraphs_map.end() )
1561  continue;
1562 
1563  for( CONNECTION_SUBGRAPH* old_sg : jj->second )
1564  {
1565  while( old_sg->m_absorbed )
1566  old_sg = old_sg->m_absorbed_by;
1567 
1568  old_sg->m_driver_connection->Clone( *conn );
1569  }
1570  }
1571  }
1572  }
1573  }
1574 
1575  nextSubgraph.store( 0 );
1576 
1577  auto updateItemConnectionsTask =
1578  [&]() -> size_t
1579  {
1580  for( size_t subgraphId = nextSubgraph++;
1581  subgraphId < m_driver_subgraphs.size();
1582  subgraphId = nextSubgraph++ )
1583  {
1584  CONNECTION_SUBGRAPH* subgraph = m_driver_subgraphs[subgraphId];
1585 
1586  // Make sure weakly-driven single-pin nets get the unconnected_ prefix
1587  if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
1588  subgraph->m_driver->Type() == SCH_PIN_T )
1589  {
1590  SCH_PIN* pin = static_cast<SCH_PIN*>( subgraph->m_driver );
1591  wxString name = pin->GetDefaultNetName( subgraph->m_sheet, true );
1592 
1594  }
1595 
1596  subgraph->m_dirty = false;
1597  subgraph->UpdateItemConnections();
1598 
1599  // No other processing to do on buses
1600  if( subgraph->m_driver_connection->IsBus() )
1601  continue;
1602 
1603  // As a visual aid, we can check sheet pins that are driven by themselves to see
1604  // if they should be promoted to buses
1605 
1606  if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1607  {
1608  SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( subgraph->m_driver );
1609 
1610  if( SCH_SHEET* sheet = pin->GetParent() )
1611  {
1612  wxString pinText = pin->GetText();
1613  SCH_SCREEN* screen = sheet->GetScreen();
1614 
1615  for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
1616  {
1617  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
1618 
1619  if( label->GetText() == pinText )
1620  {
1621  SCH_SHEET_PATH path = subgraph->m_sheet;
1622  path.push_back( sheet );
1623 
1624  SCH_CONNECTION* parent_conn = label->Connection( &path );
1625 
1626  if( parent_conn && parent_conn->IsBus() )
1628 
1629  break;
1630  }
1631  }
1632 
1633  if( subgraph->m_driver_connection->IsBus() )
1634  continue;
1635  }
1636  }
1637  }
1638 
1639  return 1;
1640  };
1641 
1642  if( parallelThreadCount == 1 )
1643  updateItemConnectionsTask();
1644  else
1645  {
1646  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1647  returns[ii] = std::async( std::launch::async, updateItemConnectionsTask );
1648 
1649  // Finalize the threads
1650  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1651  returns[ii].wait();
1652  }
1653 
1656 
1657  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1658  {
1659  auto key = std::make_pair( subgraph->GetNetName(),
1660  subgraph->m_driver_connection->NetCode() );
1661  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1662 
1663  m_net_name_to_subgraphs_map[subgraph->m_driver_connection->Name()].push_back( subgraph );
1664  }
1665 }
SCH_SHEET_PATH m_sheet
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
void resolveAllDrivers()
Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel.
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
NET_MAP m_net_code_to_subgraphs_map
SCHEMATIC * m_schematic
The schematic this graph represents.
void buildItemSubGraphs()
Generates individual item subgraphs on a per-sheet basis.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
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:138
int NetCode() const
wxString Name(bool aIgnoreSheet=false) const
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void generateInvisiblePinSubGraphs()
Iterate through the invisible power pins to collect the global labels as drivers.
A small class to help profiling.
Definition: profile.h:46
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
static const wxChar ConnProfileMask[]
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:87
bool IsNet() const
void processSubGraphs()
Process all subgraphs to assign netcodes and merge subgraphs based on labels.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
const char * name
Definition: DXF_plotter.cpp:56
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
void collectAllDriverValues()
Maps the driver values for each subgraph.
void SetType(CONNECTION_TYPE aType)
bool IsBus() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
Definition: kicad_algo.h:173
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:154
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
PRIORITY GetDriverPriority()
This item represents a bus vector.
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
void UpdateItemConnections()
Updates all items to match the driver connection.

References buildItemSubGraphs(), BUS, SCH_CONNECTION::Clone(), collectAllDriverValues(), SCH_CONNECTION::ConfigureFromLabel(), SCH_ITEM::Connection(), ConnProfileMask, ConnTrace, alg::delete_if(), generateInvisiblePinSubGraphs(), CONNECTION_SUBGRAPH::GetDriverPriority(), 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_SUBGRAPH::m_driver_connection, m_driver_subgraphs, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_local_driver, m_net_code_to_subgraphs_map, m_net_name_to_subgraphs_map, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, CONNECTION_SUBGRAPH::m_strong_driver, m_subgraphs, matchBusMember(), name, SCH_CONNECTION::Name(), EE_RTREE::OfType(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, processSubGraphs(), propagateToNeighbors(), resolveAllDrivers(), SCH_HIER_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, SCH_CONNECTION::SetType(), PROF_TIMER::Show(), EDA_ITEM::Type(), and CONNECTION_SUBGRAPH::UpdateItemConnections().

Referenced by Recalculate().

◆ buildItemSubGraphs()

void CONNECTION_GRAPH::buildItemSubGraphs ( )
private

Generates individual item subgraphs on a per-sheet basis.

Definition at line 730 of file connection_graph.cpp.

731 {
732  // Build subgraphs from items (on a per-sheet basis)
733 
734  for( SCH_ITEM* item : m_items )
735  {
736  for( const auto& it : item->m_connection_map )
737  {
738  const SCH_SHEET_PATH& sheet = it.first;
739  SCH_CONNECTION* connection = it.second;
740 
741  if( connection->SubgraphCode() == 0 )
742  {
743  CONNECTION_SUBGRAPH* subgraph = new CONNECTION_SUBGRAPH( this );
744 
745  subgraph->m_code = m_last_subgraph_code++;
746  subgraph->m_sheet = sheet;
747 
748  subgraph->AddItem( item );
749 
750  connection->SetSubgraphCode( subgraph->m_code );
751  m_item_to_subgraph_map[item] = subgraph;
752 
753  std::list<SCH_ITEM*> memberlist;
754 
755  auto get_items =
756  [&]( SCH_ITEM* aItem ) -> bool
757  {
758  SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet, this );
759  bool unique = !( aItem->GetFlags() & CANDIDATE );
760 
761  if( conn && !conn->SubgraphCode() )
762  aItem->SetFlags( CANDIDATE );
763 
764  return ( unique && conn && ( conn->SubgraphCode() == 0 ) );
765  };
766 
767  std::copy_if( item->ConnectedItems( sheet ).begin(),
768  item->ConnectedItems( sheet ).end(),
769  std::back_inserter( memberlist ), get_items );
770 
771  for( SCH_ITEM* connected_item : memberlist )
772  {
773  if( connected_item->Type() == SCH_NO_CONNECT_T )
774  subgraph->m_no_connect = connected_item;
775 
776  SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
777 
778  wxASSERT( connected_conn );
779 
780  if( connected_conn->SubgraphCode() == 0 )
781  {
782  connected_conn->SetSubgraphCode( subgraph->m_code );
783  m_item_to_subgraph_map[connected_item] = subgraph;
784  subgraph->AddItem( connected_item );
785  SCH_ITEM_SET& citemset = connected_item->ConnectedItems( sheet );
786 
787  for( SCH_ITEM* citem : citemset )
788  {
789  if( citem->HasFlag( CANDIDATE ) )
790  continue;
791 
792  if( get_items( citem ) )
793  memberlist.push_back( citem );
794  }
795  }
796  }
797 
798  for( SCH_ITEM* connected_item : memberlist )
799  connected_item->ClearFlags( CANDIDATE );
800 
801  subgraph->m_dirty = true;
802  m_subgraphs.push_back( subgraph );
803  }
804  }
805  }
806 
807 }
SCH_SHEET_PATH m_sheet
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
std::vector< SCH_ITEM * > m_items
A subgraph is a set of items that are electrically connected on a single sheet.
#define CANDIDATE
flag indicating that the structure is connected
std::vector< SCH_ITEM * > SCH_ITEM_SET
Definition: sch_item.h:134
void SetSubgraphCode(int aCode)
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
int SubgraphCode() const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

References CONNECTION_SUBGRAPH::AddItem(), CANDIDATE, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, m_item_to_subgraph_map, m_items, m_last_subgraph_code, CONNECTION_SUBGRAPH::m_no_connect, 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 893 of file connection_graph.cpp.

894 {
895  // Check for subgraphs with the same net name but only weak drivers.
896  // For example, two wires that are both connected to hierarchical
897  // sheet pins that happen to have the same name, but are not the same.
898 
899  for( auto&& subgraph : m_driver_subgraphs )
900  {
901  wxString full_name = subgraph->m_driver_connection->Name();
902  wxString name = subgraph->m_driver_connection->Name( true );
903  m_net_name_to_subgraphs_map[full_name].emplace_back( subgraph );
904 
905  // For vector buses, we need to cache the prefix also, as two different instances of the
906  // weakly driven pin may have the same prefix but different vector start and end. We need
907  // to treat those as needing renaming also, because otherwise if they end up on a sheet with
908  // common usage, they will be incorrectly merged.
909  if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
910  {
911  wxString prefixOnly = full_name.BeforeFirst( '[' ) + wxT( "[]" );
912  m_net_name_to_subgraphs_map[prefixOnly].emplace_back( subgraph );
913  }
914 
915  subgraph->m_dirty = true;
916 
917  if( subgraph->m_strong_driver )
918  {
919  SCH_ITEM* driver = subgraph->m_driver;
920  SCH_SHEET_PATH sheet = subgraph->m_sheet;
921 
922  switch( driver->Type() )
923  {
924  case SCH_LABEL_T:
925  case SCH_HIER_LABEL_T:
926  {
927  m_local_label_cache[std::make_pair( sheet, name )].push_back( subgraph );
928  break;
929  }
930  case SCH_GLOBAL_LABEL_T:
931  {
932  m_global_label_cache[name].push_back( subgraph );
933  break;
934  }
935  case SCH_PIN_T:
936  {
937  SCH_PIN* pin = static_cast<SCH_PIN*>( driver );
938  wxASSERT( pin->IsPowerConnection() );
939  m_global_label_cache[name].push_back( subgraph );
940  break;
941  }
942  default:
943  wxLogTrace( ConnTrace, wxT( "Unexpected strong driver %s" ),
945  break;
946  }
947  }
948  }
949 }
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
static const wxChar ConnTrace[]
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
const char * name
Definition: DXF_plotter.cpp:56
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:109
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

References BUS, ConnTrace, EDA_ITEM::GetSelectMenuText(), 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, 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 2461 of file connection_graph.cpp.

2462 {
2463  wxString msg;
2464  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2465  SCH_SCREEN* screen = sheet.LastScreen();
2466 
2467  SCH_ITEM* label = nullptr;
2468  SCH_ITEM* port = nullptr;
2469 
2470  for( auto item : aSubgraph->m_items )
2471  {
2472  switch( item->Type() )
2473  {
2474  case SCH_TEXT_T:
2475  case SCH_GLOBAL_LABEL_T:
2476  {
2477  if( !label && item->Connection( &sheet )->IsBus() )
2478  label = item;
2479  break;
2480  }
2481 
2482  case SCH_SHEET_PIN_T:
2483  case SCH_HIER_LABEL_T:
2484  {
2485  if( !port && item->Connection( &sheet )->IsBus() )
2486  port = item;
2487  break;
2488  }
2489 
2490  default:
2491  break;
2492  }
2493  }
2494 
2495  if( label && port )
2496  {
2497  bool match = false;
2498 
2499  for( const auto& member : label->Connection( &sheet )->Members() )
2500  {
2501  for( const auto& test : port->Connection( &sheet )->Members() )
2502  {
2503  if( test != member && member->Name() == test->Name() )
2504  {
2505  match = true;
2506  break;
2507  }
2508  }
2509 
2510  if( match )
2511  break;
2512  }
2513 
2514  if( !match )
2515  {
2516  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
2517  ercItem->SetItems( label, port );
2518 
2519  SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
2520  screen->Append( marker );
2521 
2522  return false;
2523  }
2524  }
2525 
2526  return true;
2527 }
SCH_SHEET_PATH m_sheet
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:59
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
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:138
std::vector< SCH_ITEM * > m_items
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182

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, and SCH_TEXT_T.

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 2530 of file connection_graph.cpp.

2531 {
2532  bool conflict = false;
2533  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2534  SCH_SCREEN* screen = sheet.LastScreen();
2535 
2536  SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2537  SCH_ITEM* bus_wire = nullptr;
2538  wxString bus_name;
2539 
2540  if( !aSubgraph->m_driver_connection )
2541  {
2542  // Incomplete bus entry. Let the unconnected tests handle it.
2543  return true;
2544  }
2545 
2546  for( SCH_ITEM* item : aSubgraph->m_items )
2547  {
2548  switch( item->Type() )
2549  {
2550  case SCH_BUS_WIRE_ENTRY_T:
2551  {
2552  if( !bus_entry )
2553  bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2554  break;
2555  }
2556 
2557  default:
2558  break;
2559  }
2560  }
2561 
2562  if( bus_entry && bus_entry->m_connected_bus_item )
2563  {
2564  bus_wire = bus_entry->m_connected_bus_item;
2565 
2566  wxASSERT( bus_wire->Type() == SCH_LINE_T );
2567 
2568  // In some cases, the connection list (SCH_CONNECTION*) can be null.
2569  // Skip null connections.
2570  if( bus_entry->Connection( &sheet )
2571  && bus_wire->Type() == SCH_LINE_T
2572  && bus_wire->Connection( &sheet ) )
2573  {
2574  conflict = true; // Assume a conflict; we'll reset if we find it's OK
2575 
2576  bus_name = bus_wire->Connection( &sheet )->Name();
2577 
2578  wxString test_name = bus_entry->Connection( &sheet )->Name();
2579 
2580  for( const auto& member : bus_wire->Connection( &sheet )->Members() )
2581  {
2582  if( member->Type() == CONNECTION_TYPE::BUS )
2583  {
2584  for( const auto& sub_member : member->Members() )
2585  {
2586  if( sub_member->Name() == test_name )
2587  conflict = false;
2588  }
2589  }
2590  else if( member->Name() == test_name )
2591  {
2592  conflict = false;
2593  }
2594  }
2595  }
2596  }
2597 
2598  // Don't report warnings if this bus member has been overridden by a higher priority power pin
2599  // or global label
2600  if( conflict && CONNECTION_SUBGRAPH::GetDriverPriority( aSubgraph->m_driver )
2602  {
2603  conflict = false;
2604  }
2605 
2606  if( conflict )
2607  {
2608  wxString netName = aSubgraph->m_driver_connection->Name();
2609  wxString msg = wxString::Format( _( "Net %s is graphically connected to bus %s but is not a"
2610  " member of that bus" ),
2611  UnescapeString( netName ),
2612  UnescapeString( bus_name ) );
2613  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
2614  ercItem->SetItems( bus_entry, bus_wire );
2615  ercItem->SetErrorMessage( msg );
2616 
2617  SCH_MARKER* marker = new SCH_MARKER( ercItem, bus_entry->GetPosition() );
2618  screen->Append( marker );
2619 
2620  return false;
2621  }
2622 
2623  return true;
2624 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
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 ...
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
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:138
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
#define _(s)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:57
wxString UnescapeString(const wxString &aSource)
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
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
PRIORITY GetDriverPriority()
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
wxPoint GetPosition() const override

References _, SCH_SCREEN::Append(), BUS, SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_ENTRY_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetDriverPriority(), 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_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_CONNECTION::Name(), 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 2404 of file connection_graph.cpp.

2405 {
2406  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2407  SCH_SCREEN* screen = sheet.LastScreen();
2408 
2409  SCH_ITEM* net_item = nullptr;
2410  SCH_ITEM* bus_item = nullptr;
2411  SCH_CONNECTION conn( this );
2412 
2413  for( SCH_ITEM* item : aSubgraph->m_items )
2414  {
2415  switch( item->Type() )
2416  {
2417  case SCH_LINE_T:
2418  {
2419  if( item->GetLayer() == LAYER_BUS )
2420  bus_item = ( !bus_item ) ? item : bus_item;
2421  else
2422  net_item = ( !net_item ) ? item : net_item;
2423  break;
2424  }
2425 
2426  case SCH_LABEL_T:
2427  case SCH_GLOBAL_LABEL_T:
2428  case SCH_SHEET_PIN_T:
2429  case SCH_HIER_LABEL_T:
2430  {
2431  SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2432  conn.ConfigureFromLabel( EscapeString( text->GetShownText(), CTX_NETNAME ) );
2433 
2434  if( conn.IsBus() )
2435  bus_item = ( !bus_item ) ? item : bus_item;
2436  else
2437  net_item = ( !net_item ) ? item : net_item;
2438  break;
2439  }
2440 
2441  default:
2442  break;
2443  }
2444  }
2445 
2446  if( net_item && bus_item )
2447  {
2448  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
2449  ercItem->SetItems( net_item, bus_item );
2450 
2451  SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
2452  screen->Append( marker );
2453 
2454  return false;
2455  }
2456 
2457  return true;
2458 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:61
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
std::vector< SCH_ITEM * > m_items
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:259
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

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 2801 of file connection_graph.cpp.

2802 {
2803  if( aSubgraph->m_driver )
2804  return true;
2805 
2806  std::vector<SCH_ITEM*> wires;
2807 
2808  // We've gotten this far, so we know we have no valid driver. All we need to do is check
2809  // for a wire that we can place the error on.
2810 
2811  for( SCH_ITEM* item : aSubgraph->m_items )
2812  {
2813  if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
2814  wires.emplace_back( item );
2815  else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
2816  wires.emplace_back( item );
2817  }
2818 
2819  if( !wires.empty() )
2820  {
2821  SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2822 
2823  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
2824  ercItem->SetItems( wires[0],
2825  wires.size() > 1 ? wires[1] : nullptr,
2826  wires.size() > 2 ? wires[2] : nullptr,
2827  wires.size() > 3 ? wires[3] : nullptr );
2828 
2829  SCH_MARKER* marker = new SCH_MARKER( ercItem, wires[0]->GetPosition() );
2830  screen->Append( marker );
2831 
2832  return false;
2833  }
2834 
2835  return true;
2836 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
Some wires are not connected to anything else.
Definition: erc_settings.h:65
std::vector< SCH_ITEM * > m_items
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:259
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

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 2993 of file connection_graph.cpp.

2994 {
2995  int errors = 0;
2996 
2997  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2998 
2999  for( const SCH_SHEET_PATH& sheet : m_sheetList )
3000  {
3001  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
3002  {
3003  if( item->Type() != SCH_SHEET_T )
3004  continue;
3005 
3006  SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
3007 
3008  std::map<wxString, SCH_SHEET_PIN*> pins;
3009  std::map<wxString, SCH_HIERLABEL*> labels;
3010 
3011  for( SCH_SHEET_PIN* pin : parentSheet->GetPins() )
3012  {
3013  if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
3014  pins[pin->GetText()] = pin;
3015 
3016  if( pin->IsDangling() && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
3017  {
3018  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
3019  ercItem->SetItems( pin );
3020 
3021  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
3022  sheet.LastScreen()->Append( marker );
3023 
3024  errors++;
3025  }
3026  }
3027 
3028  if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
3029  {
3030  std::set<wxString> matchedPins;
3031 
3032  for( SCH_ITEM* subItem : parentSheet->GetScreen()->Items() )
3033  {
3034  if( subItem->Type() == SCH_HIER_LABEL_T )
3035  {
3036  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
3037 
3038  if( !pins.count( label->GetText() ) )
3039  labels[label->GetText()] = label;
3040  else
3041  matchedPins.insert( label->GetText() );
3042  }
3043  }
3044 
3045  for( const wxString& matched : matchedPins )
3046  pins.erase( matched );
3047 
3048  for( const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
3049  {
3050  wxString msg = wxString::Format( _( "Sheet pin %s has no matching hierarchical "
3051  "label inside the sheet" ),
3052  UnescapeString( unmatched.first ) );
3053 
3054  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
3055  ercItem->SetItems( unmatched.second );
3056  ercItem->SetErrorMessage( msg );
3057  ercItem->SetIsSheetSpecific();
3058 
3059  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
3060  sheet.LastScreen()->Append( marker );
3061 
3062  errors++;
3063  }
3064 
3065  for( const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
3066  {
3067  wxString msg = wxString::Format( _( "Hierarchical label %s has no matching "
3068  "sheet pin in the parent sheet" ),
3069  UnescapeString( unmatched.first ) );
3070 
3071  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
3072  ercItem->SetItems( unmatched.second );
3073  ercItem->SetErrorMessage( msg );
3074  ercItem->SetIsSheetSpecific();
3075 
3076  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
3077  parentSheet->GetScreen()->Append( marker );
3078 
3079  errors++;
3080  }
3081  }
3082  }
3083  }
3084 
3085  return errors;
3086 }
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
SCHEMATIC * m_schematic
The schematic this graph represents.
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:102
#define _(s)
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Container for ERC settings.
Definition: erc_settings.h:106
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString UnescapeString(const wxString &aSource)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:183
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
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:46
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
SCH_SHEET_LIST m_sheetList
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:154

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_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 2839 of file connection_graph.cpp.

2840 {
2841  // Label connection rules:
2842  // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2843  // Global labels are flagged if they appear only once, don't connect to any local labels,
2844  // and don't have a no-connect marker
2845 
2846  // So, if there is a no-connect, we will never generate a warning here
2847  if( aSubgraph->m_no_connect )
2848  return true;
2849 
2850  if( !aSubgraph->m_driver_connection )
2851  return true;
2852 
2853  // Buses are excluded from this test: many users create buses with only a single instance
2854  // and it's not really a problem as long as the nets in the bus pass ERC
2855  if( aSubgraph->m_driver_connection->IsBus() )
2856  return true;
2857 
2858  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2859  bool ok = true;
2860  SCH_TEXT* text = nullptr;
2861  bool hasOtherConnections = false;
2862  int pinCount = 0;
2863 
2864  auto hasPins =
2865  []( const CONNECTION_SUBGRAPH* aLocSubgraph )
2866  {
2867  for( const SCH_ITEM* item : aLocSubgraph->m_items )
2868  {
2869  switch( item->Type() )
2870  {
2871  case SCH_PIN_T:
2872  case SCH_SHEET_PIN_T:
2873  return true;
2874 
2875  default: break;
2876  }
2877  }
2878 
2879  return false;
2880  };
2881 
2882  for( SCH_ITEM* item : aSubgraph->m_items )
2883  {
2884  switch( item->Type() )
2885  {
2886  case SCH_LABEL_T:
2887  case SCH_GLOBAL_LABEL_T:
2888  case SCH_HIER_LABEL_T:
2889  {
2890  text = static_cast<SCH_TEXT*>( item );
2891 
2892  // Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
2893  // we want to error if an individual label in the subgraph is floating, even if it's
2894  // connected to other valid things by way of another label on the same sheet.
2895 
2896  if( text->IsDangling() && settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
2897  {
2898  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LABEL_NOT_CONNECTED );
2899  ercItem->SetItems( text );
2900 
2901  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2902  aSubgraph->m_sheet.LastScreen()->Append( marker );
2903  ok = false;
2904  }
2905 
2906  break;
2907  }
2908 
2909  case SCH_PIN_T:
2910  case SCH_SHEET_PIN_T:
2911  hasOtherConnections = true;
2912  pinCount++;
2913  break;
2914 
2915  default:
2916  break;
2917  }
2918  }
2919 
2920  if( !text )
2921  return true;
2922 
2923  bool isGlobal = text->Type() == SCH_GLOBAL_LABEL_T;
2924  int errCode = isGlobal ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
2925 
2926  wxCHECK_MSG( m_schematic, true, wxT( "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
2927 
2928  wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
2929 
2930  if( isGlobal )
2931  {
2932  // This will be set to true if the global is connected to a pin above, but we want to
2933  // reset this to false so that globals get flagged if they only have a single instance
2934  // connected to a single pin
2935  hasOtherConnections = ( pinCount > 1 );
2936 
2937  auto it = m_net_name_to_subgraphs_map.find( name );
2938 
2939  if( it != m_net_name_to_subgraphs_map.end() )
2940  {
2941  if( it->second.size() > 1 || aSubgraph->m_multiple_drivers )
2942  hasOtherConnections = true;
2943  }
2944  }
2945  else if( text->Type() == SCH_HIER_LABEL_T )
2946  {
2947  // For a hier label, check if the parent pin is connected
2948  if( aSubgraph->m_hier_parent
2949  && ( aSubgraph->m_hier_parent->m_strong_driver
2950  || aSubgraph->m_hier_parent->m_drivers.size() > 1) )
2951  {
2952  // For now, a simple check: if there is more than one driver, the parent is probably
2953  // connected elsewhere (because at least one driver will be the hier pin itself)
2954  hasOtherConnections = true;
2955  }
2956  }
2957  else
2958  {
2959  auto pair = std::make_pair( aSubgraph->m_sheet, name );
2960  auto it = m_local_label_cache.find( pair );
2961 
2962  if( it != m_local_label_cache.end() && it->second.size() > 1 )
2963  {
2964  for( const CONNECTION_SUBGRAPH* neighbor : it->second )
2965  {
2966  if( neighbor == aSubgraph )
2967  continue;
2968 
2969  if( hasPins( neighbor ) )
2970  {
2971  hasOtherConnections = true;
2972  break;
2973  }
2974  }
2975  }
2976  }
2977 
2978  if( !hasOtherConnections && settings.IsTestEnabled( errCode ) )
2979  {
2980  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
2981  ercItem->SetItems( text );
2982 
2983  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2984  aSubgraph->m_sheet.LastScreen()->Append( marker );
2985 
2986  return false;
2987  }
2988 
2989  return ok;
2990 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
Label not connected to anything.
Definition: erc_settings.h:49
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
std::vector< SCH_ITEM * > m_items
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Container for ERC settings.
Definition: erc_settings.h:106
A global label is unique.
Definition: erc_settings.h:63
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:56
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
CONNECTION_SUBGRAPH * m_hier_parent
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
bool IsBus() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

References SCH_SCREEN::Append(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, SCHEMATIC::ErcSettings(), EscapeString(), SCH_CONNECTION::IsBus(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_multiple_drivers, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, CONNECTION_SUBGRAPH::m_strong_driver, name, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_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 2331 of file connection_graph.cpp.

2332 {
2333  wxCHECK( aSubgraph, false );
2334  /*
2335  * This was changed late in 6.0 to fix https://gitlab.com/kicad/code/kicad/-/issues/9367
2336  * so I'm going to leave the original code in for just a little while. If anyone comes
2337  * across this in 7.0 development (or later), feel free to delete.
2338  */
2339 #if 0
2340  if( aSubgraph->m_second_driver )
2341  {
2342  SCH_ITEM* primary = aSubgraph->m_first_driver;
2343  SCH_ITEM* secondary = aSubgraph->m_second_driver;
2344 
2345  wxPoint pos = primary->Type() == SCH_PIN_T ?
2346  static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2347  primary->GetPosition();
2348 
2349  wxString primaryName = aSubgraph->GetNameForDriver( primary );
2350  wxString secondaryName = aSubgraph->GetNameForDriver( secondary );
2351 
2352  wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2353  "items; %s will be used in the netlist" ),
2354  primaryName, secondaryName, primaryName );
2355 
2356  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2357  ercItem->SetItems( primary, secondary );
2358  ercItem->SetErrorMessage( msg );
2359 
2360  SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2361  aSubgraph->m_sheet.LastScreen()->Append( marker );
2362 
2363  return false;
2364  }
2365 #else
2366  if( aSubgraph->m_multiple_drivers )
2367  {
2368  for( SCH_ITEM* driver : aSubgraph->m_drivers )
2369  {
2370  if( driver == aSubgraph->m_driver )
2371  continue;
2372 
2373  if( driver->Type() == SCH_GLOBAL_LABEL_T
2374  || driver->Type() == SCH_HIER_LABEL_T
2375  || driver->Type() == SCH_LABEL_T )
2376  {
2377  wxString primaryName = aSubgraph->GetNameForDriver( aSubgraph->m_driver );
2378  wxString secondaryName = aSubgraph->GetNameForDriver( driver );
2379 
2380  if( primaryName == secondaryName )
2381  continue;
2382 
2383  wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2384  "items; %s will be used in the netlist" ),
2385  primaryName, secondaryName, primaryName );
2386 
2387  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2388  ercItem->SetItems( aSubgraph->m_driver, driver );
2389  ercItem->SetErrorMessage( msg );
2390 
2391  SCH_MARKER* marker = new SCH_MARKER( ercItem, driver->GetPosition() );
2392  aSubgraph->m_sheet.LastScreen()->Append( marker );
2393 
2394  return false;
2395  }
2396  }
2397  }
2398 #endif
2399 
2400  return true;
2401 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
#define _(s)
std::vector< SCH_ITEM * > m_drivers
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
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
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:56
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_DRIVER_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetNameForDriver(), EDA_ITEM::GetPosition(), 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().

◆ 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 2628 of file connection_graph.cpp.

2629 {
2630  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2631  wxString msg;
2632  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2633  SCH_SCREEN* screen = sheet.LastScreen();
2634  bool ok = true;
2635 
2636  if( aSubgraph->m_no_connect != nullptr )
2637  {
2638  bool has_invalid_items = false;
2639  bool has_other_items = false;
2640  SCH_PIN* pin = nullptr;
2641  std::vector<SCH_ITEM*> invalid_items;
2642  wxPoint noConnectPos = aSubgraph->m_no_connect->GetPosition();
2643  double minDist = 0;
2644 
2645  // Any subgraph that contains both a pin and a no-connect should not
2646  // contain any other driving items.
2647 
2648  for( SCH_ITEM* item : aSubgraph->m_items )
2649  {
2650  switch( item->Type() )
2651  {
2652  case SCH_PIN_T:
2653  {
2654  SCH_PIN* candidate = static_cast<SCH_PIN*>( item );
2655  double dist = VECTOR2I( candidate->GetTransformedPosition() - noConnectPos )
2656  .SquaredEuclideanNorm();
2657 
2658  if( !pin || dist < minDist )
2659  {
2660  pin = candidate;
2661  minDist = dist;
2662  }
2663 
2664  has_invalid_items |= has_other_items;
2665  has_other_items = true;
2666  break;
2667  }
2668 
2669  case SCH_LINE_T:
2670  case SCH_JUNCTION_T:
2671  case SCH_NO_CONNECT_T:
2672  break;
2673 
2674  default:
2675  has_invalid_items = true;
2676  has_other_items = true;
2677  invalid_items.push_back( item );
2678  }
2679  }
2680 
2681  if( pin && has_invalid_items && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
2682  {
2683  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
2684  ercItem->SetItems( pin );
2685 
2686  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2687  screen->Append( marker );
2688 
2689  ok = false;
2690  }
2691 
2692  if( !has_other_items && settings.IsTestEnabled( ERCE_NOCONNECT_NOT_CONNECTED ) )
2693  {
2694  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
2695  ercItem->SetItems( aSubgraph->m_no_connect );
2696 
2697  SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
2698  screen->Append( marker );
2699 
2700  ok = false;
2701  }
2702  }
2703  else
2704  {
2705  bool has_other_connections = false;
2706  std::vector<SCH_PIN*> pins;
2707 
2708  // Any subgraph that lacks a no-connect and contains a pin should also
2709  // contain at least one other potential driver
2710 
2711  for( SCH_ITEM* item : aSubgraph->m_items )
2712  {
2713  switch( item->Type() )
2714  {
2715  case SCH_PIN_T:
2716  {
2717  if( !pins.empty() )
2718  has_other_connections = true;
2719 
2720  pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2721 
2722  break;
2723  }
2724 
2725  default:
2726  if( aSubgraph->GetDriverPriority( item ) != CONNECTION_SUBGRAPH::PRIORITY::NONE )
2727  has_other_connections = true;
2728 
2729  break;
2730  }
2731  }
2732 
2733  // For many checks, we can just use the first pin
2734  SCH_PIN* pin = pins.empty() ? nullptr : pins[0];
2735 
2736  // Check if invisible power input pins connect to anything else via net name,
2737  // but not for power symbols as the ones in the standard library all have invisible pins
2738  // and we want to throw unconnected errors for those even if they are connected to other
2739  // net items by name, because usually failing to connect them graphically is a mistake
2740  if( pin && !has_other_connections
2741  && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
2742  && !pin->IsVisible()
2743  && !pin->GetLibPin()->GetParent()->IsPower() )
2744  {
2745  wxString name = pin->Connection( &sheet )->Name();
2746  wxString local_name = pin->Connection( &sheet )->Name( true );
2747 
2748  if( m_global_label_cache.count( name )
2749  || m_local_label_cache.count( std::make_pair( sheet, local_name ) ) )
2750  {
2751  has_other_connections = true;
2752  }
2753  }
2754 
2755  // Only one pin, and it's not a no-connect pin
2756  if( pin && !has_other_connections
2757  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
2758  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
2759  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2760  {
2761  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2762  ercItem->SetItems( pin );
2763 
2764  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2765  screen->Append( marker );
2766 
2767  ok = false;
2768  }
2769 
2770  // If there are multiple pins in this SG, they might be indirectly connected (by netname)
2771  // rather than directly connected (by wires). We want to flag dangling pins even if they
2772  // join nets with another pin, as it's often a mistake
2773  if( pins.size() > 1 )
2774  {
2775  for( SCH_PIN* testPin : pins )
2776  {
2777  // We only apply this test to power symbols, because other symbols have invisible
2778  // pins that are meant to be dangling, but the KiCad standard library power symbols
2779  // have invisible pins that are *not* meant to be dangling.
2780  if( testPin->GetLibPin()->GetParent()->IsPower()
2781  && testPin->ConnectedItems( sheet ).empty()
2782  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2783  {
2784  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2785  ercItem->SetItems( testPin );
2786 
2787  SCH_MARKER* marker = new SCH_MARKER( ercItem,
2788  testPin->GetTransformedPosition() );
2789  screen->Append( marker );
2790 
2791  ok = false;
2792  }
2793  }
2794  }
2795  }
2796 
2797  return ok;
2798 }
power input (GND, VCC for ICs). Must be connected to a power output.
SCH_SHEET_PATH m_sheet
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
SCHEMATIC * m_schematic
The schematic this graph represents.
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
not internally connected (may be connected to anything)
std::vector< SCH_ITEM * > m_items
Container for ERC settings.
Definition: erc_settings.h:106
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
A no connect symbol is not connected to anything.
Definition: erc_settings.h:48
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
A no connect symbol is connected to more than 1 pin.
Definition: erc_settings.h:47
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:56
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:146
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
not connected (must be left open)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
wxPoint GetTransformedPosition() const
Definition: sch_pin.cpp:294

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(), SCH_PIN::GetTransformedPosition(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), m_global_label_cache, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, name, CONNECTION_SUBGRAPH::NONE, pin, PT_NC, PT_NIC, PT_POWER_IN, SCH_JUNCTION_T, SCH_LINE_T, SCH_NO_CONNECT_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 2208 of file connection_graph.cpp.

2209 {
2210  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2211 
2212  if( it == m_net_name_to_subgraphs_map.end() )
2213  return nullptr;
2214 
2215  wxASSERT( !it->second.empty() );
2216 
2217  return it->second[0];
2218 }
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map

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 2187 of file connection_graph.cpp.

2189 {
2190  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2191 
2192  if( it == m_net_name_to_subgraphs_map.end() )
2193  return nullptr;
2194 
2195  for( CONNECTION_SUBGRAPH* sg : it->second )
2196  {
2197  // Cache is supposed to be valid by now
2198  wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
2199 
2200  if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
2201  return sg;
2202  }
2203 
2204  return nullptr;
2205 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
wxString Name(bool aIgnoreSheet=false) const

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 952 of file connection_graph.cpp.

953 {
954  // Generate subgraphs for invisible power pins. These will be merged with other subgraphs
955  // on the same sheet in the next loop.
956 
957  std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
958 
959  for( const auto& it : m_invisible_power_pins )
960  {
961  SCH_SHEET_PATH sheet = it.first;
962  SCH_PIN* pin = it.second;
963 
964  if( !pin->ConnectedItems( sheet ).empty() && !pin->GetLibPin()->GetParent()->IsPower() )
965  {
966  // ERC will warn about this: user has wired up an invisible pin
967  continue;
968  }
969 
970  SCH_CONNECTION* connection = pin->GetOrInitConnection( sheet, this );
971 
972  // If this pin already has a subgraph, don't need to process
973  if( !connection || connection->SubgraphCode() > 0 )
974  continue;
975 
976  connection->SetName( pin->GetShownName() );
977 
978  int code = assignNewNetCode( *connection );
979 
980  connection->SetNetCode( code );
981 
982  CONNECTION_SUBGRAPH* subgraph;
983  auto jj = invisible_pin_subgraphs.find( code );
984 
985  if( jj != invisible_pin_subgraphs.end() )
986  {
987  subgraph = jj->second;
988  subgraph->AddItem( pin );
989  }
990  else
991  {
992  subgraph = new CONNECTION_SUBGRAPH( this );
993 
994  subgraph->m_code = m_last_subgraph_code++;
995  subgraph->m_sheet = sheet;
996 
997  subgraph->AddItem( pin );
998  subgraph->ResolveDrivers();
999 
1000  auto key = std::make_pair( subgraph->GetNetName(), code );
1001  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1002  m_subgraphs.push_back( subgraph );
1003  m_driver_subgraphs.push_back( subgraph );
1004 
1005  invisible_pin_subgraphs[code] = subgraph;
1006  }
1007 
1008  connection->SetSubgraphCode( subgraph->m_code );
1009  }
1010 }
SCH_SHEET_PATH m_sheet
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
void SetName(const wxString &aName)
NET_MAP m_net_code_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
void SetSubgraphCode(int aCode)
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
int SubgraphCode() const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void SetNetCode(int aCode)
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)

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 2132 of file connection_graph.cpp.

2133 {
2134  auto it = m_bus_alias_cache.find( aName );
2135 
2136  return it != m_bus_alias_cache.end() ? it->second : nullptr;
2137 }
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache

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 2140 of file connection_graph.cpp.

2141 {
2142  std::vector<const CONNECTION_SUBGRAPH*> ret;
2143 
2144  for( CONNECTION_SUBGRAPH* subgraph : m_subgraphs )
2145  {
2146  // Graph is supposed to be up-to-date before calling this
2147  wxASSERT( !subgraph->m_dirty );
2148 
2149  if( !subgraph->m_driver )
2150  continue;
2151 
2152  SCH_CONNECTION* connection = subgraph->m_driver->Connection( &subgraph->m_sheet );
2153 
2154  if( !connection->IsBus() )
2155  continue;
2156 
2157  auto labels = subgraph->GetBusLabels();
2158 
2159  if( labels.size() > 1 )
2160  {
2161  bool different = false;
2162  wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2163 
2164  for( unsigned i = 1; i < labels.size(); ++i )
2165  {
2166  if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2167  {
2168  different = true;
2169  break;
2170  }
2171  }
2172 
2173  if( !different )
2174  continue;
2175 
2176  wxLogTrace( ConnTrace, wxT( "SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
2177  connection->Name() );
2178 
2179  ret.push_back( subgraph );
2180  }
2181  }
2182 
2183  return ret;
2184 }
SCH_ITEM * m_driver
The SCH_ITEM that drives this connection's net.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
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:138
wxString Name(bool aIgnoreSheet=false) const
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsBus() const

References SCH_ITEM::Connection(), ConnTrace, 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 2023 of file connection_graph.cpp.

2025 {
2026  std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>( nullptr );
2027 
2028  switch( aItem->Type() )
2029  {
2030  case SCH_PIN_T:
2031  {
2032  SCH_PIN* pin = static_cast<SCH_PIN*>( aItem );
2033 
2034  if( pin->IsPowerConnection() )
2035  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
2036 
2037  break;
2038  }
2039 
2040  case SCH_GLOBAL_LABEL_T:
2041  case SCH_HIER_LABEL_T:
2042  case SCH_LABEL_T:
2043  {
2044  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
2045  break;
2046  }
2047 
2048  default:
2049  break;
2050  }
2051 
2052  if( c )
2053  {
2054  c->SetGraph( this );
2055  c->ConfigureFromLabel( aSubgraph->GetNameForDriver( aItem ) );
2056  }
2057 
2058  return c;
2059 }
SCH_SHEET_PATH m_sheet
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

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()

◆ GetSubgraphForItem()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::GetSubgraphForItem ( SCH_ITEM aItem)

Definition at line 2221 of file connection_graph.cpp.

2222 {
2223  auto it = m_item_to_subgraph_map.find( aItem );
2224  CONNECTION_SUBGRAPH* ret = it != m_item_to_subgraph_map.end() ? it->second : nullptr;
2225 
2226  while( ret && ret->m_absorbed )
2227  ret = ret->m_absorbed_by;
2228 
2229  return ret;
2230 }
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
A subgraph is a set of items that are electrically connected on a single sheet.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

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

Referenced by inheritNetclass(), and SCH_EDITOR_CONTROL::UpdateNetHighlighting().

◆ 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 2062 of file connection_graph.cpp.

2064 {
2065  wxASSERT( aBusConnection->IsBus() );
2066 
2067  SCH_CONNECTION* match = nullptr;
2068 
2069  if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
2070  {
2071  // Vector bus: compare against index, because we allow the name
2072  // to be different
2073 
2074  for( const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->Members() )
2075  {
2076  if( bus_member->VectorIndex() == aSearch->VectorIndex() )
2077  {
2078  match = bus_member.get();
2079  break;
2080  }
2081  }
2082  }
2083  else
2084  {
2085  // Group bus
2086  for( const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->Members() )
2087  {
2088  // Vector inside group: compare names, because for bus groups
2089  // we expect the naming to be consistent across all usages
2090  // TODO(JE) explain this in the docs
2091  if( c->Type() == CONNECTION_TYPE::BUS )
2092  {
2093  for( const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
2094  {
2095  if( bus_member->LocalName() == aSearch->LocalName() )
2096  {
2097  match = bus_member.get();
2098  break;
2099  }
2100  }
2101  }
2102  else if( c->LocalName() == aSearch->LocalName() )
2103  {
2104  match = c.get();
2105  break;
2106  }
2107  }
2108  }
2109 
2110  return match;
2111 }
wxString LocalName() const
long VectorIndex() const
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
bool IsBus() const
CONNECTION_TYPE Type() const
This item represents a bus vector.

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 1013 of file connection_graph.cpp.

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

References assignNetCodesToBus(), assignNewNetCode(), BUS, BUS_GROUP, ConnTrace, alg::delete_matching(), Format(), getDefaultConnection(), SCH_CONNECTION::IsBus(), m_bus_name_to_code_map, m_driver_subgraphs, m_last_bus_code, 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, SCH_CONNECTION::SetBusCode(), and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ propagateToNeighbors()

void CONNECTION_GRAPH::propagateToNeighbors ( CONNECTION_SUBGRAPH aSubgraph)
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.

Definition at line 1711 of file connection_graph.cpp.

1712 {
1713  SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1714  std::vector<CONNECTION_SUBGRAPH*> search_list;
1715  std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1716  std::vector<SCH_CONNECTION*> stale_bus_members;
1717 
1718  auto visit =
1719  [&]( CONNECTION_SUBGRAPH* aParent )
1720  {
1721  for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1722  {
1723  SCH_SHEET_PATH path = aParent->m_sheet;
1724  path.push_back( pin->GetParent() );
1725 
1726  auto it = m_sheet_to_subgraphs_map.find( path );
1727 
1728  if( it == m_sheet_to_subgraphs_map.end() )
1729  continue;
1730 
1731  for( CONNECTION_SUBGRAPH* candidate : it->second )
1732  {
1733  if( !candidate->m_strong_driver
1734  || candidate->m_hier_ports.empty()
1735  || visited.count( candidate ) )
1736  {
1737  continue;
1738  }
1739 
1740  for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1741  {
1742  if( candidate->GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1743  {
1744  wxLogTrace( ConnTrace, wxT( "%lu: found child %lu (%s)" ), aParent->m_code,
1745  candidate->m_code, candidate->m_driver_connection->Name() );
1746 
1747  candidate->m_hier_parent = aParent;
1748 
1749  search_list.push_back( candidate );
1750  break;
1751  }
1752  }
1753  }
1754  }
1755 
1756  for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1757  {
1758  SCH_SHEET_PATH path = aParent->m_sheet;
1759  path.pop_back();
1760 
1761  auto it = m_sheet_to_subgraphs_map.find( path );
1762 
1763  if( it == m_sheet_to_subgraphs_map.end() )
1764  continue;
1765 
1766  for( CONNECTION_SUBGRAPH* candidate : it->second )
1767  {
1768  if( candidate->m_hier_pins.empty()
1769  || visited.count( candidate )
1770  || candidate->m_driver_connection->Type() != aParent->m_driver_connection->Type() )
1771  {
1772  continue;
1773  }
1774 
1775  for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1776  {
1777  SCH_SHEET_PATH pin_path = path;
1778  pin_path.push_back( pin->GetParent() );
1779 
1780  if( pin_path != aParent->m_sheet )
1781  continue;
1782 
1783  if( aParent->GetNameForDriver( label ) == candidate->GetNameForDriver( pin ) )
1784  {
1785  wxLogTrace( ConnTrace, wxT( "%lu: found additional parent %lu (%s)" ),
1786  aParent->m_code, candidate->m_code,
1787  candidate->m_driver_connection->Name() );
1788 
1789  search_list.push_back( candidate );
1790  break;
1791  }
1792  }
1793  }
1794  }
1795  };
1796 
1797  auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1798  for( const auto& kv : aParentGraph->m_bus_neighbors )
1799  {
1800  for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1801  {
1802  // May have been absorbed but won't have been deleted
1803  while( neighbor->m_absorbed )
1804  neighbor = neighbor->m_absorbed_by;
1805 
1806  SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1807 
1808  // Now member may be out of date, since we just cloned the
1809  // connection from higher up in the hierarchy. We need to
1810  // figure out what the actual new connection is.
1811  SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1812 
1813  if( !member )
1814  {
1815  // Try harder: we might match on a secondary driver
1816  for( CONNECTION_SUBGRAPH* sg : kv.second )
1817  {
1818  if( sg->m_multiple_drivers )
1819  {
1820  SCH_SHEET_PATH sheet = sg->m_sheet;
1821 
1822  for( SCH_ITEM* driver : sg->m_drivers )
1823  {
1824  auto c = getDefaultConnection( driver, sg );
1825  member = matchBusMember( parent, c.get() );
1826 
1827  if( member )
1828  break;
1829  }
1830  }
1831 
1832  if( member )
1833  break;
1834  }
1835  }
1836 
1837  // This is bad, probably an ERC error
1838  if( !member )
1839  {
1840  wxLogTrace( ConnTrace, wxT( "Could not match bus member %s in %s" ),
1841  kv.first->Name(), parent->Name() );
1842  continue;
1843  }
1844 
1845  auto neighbor_conn = neighbor->m_driver_connection;
1846  auto neighbor_name = neighbor_conn->Name();
1847 
1848  // Matching name: no update needed
1849  if( neighbor_name == member->Name() )
1850  continue;
1851 
1852  // Was this neighbor already updated from a different sheet? Don't rename it again
1853  if( neighbor_conn->Sheet() != neighbor->m_sheet )
1854  continue;
1855 
1856  // Safety check against infinite recursion
1857  wxASSERT( neighbor_conn->IsNet() );
1858 
1859  wxLogTrace( ConnTrace, wxT( "%lu (%s) connected to bus member %s (local %s)" ),
1860  neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1861 
1862  // Take whichever name is higher priority
1865  {
1866  member->Clone( *neighbor_conn );
1867  stale_bus_members.push_back( member );
1868  }
1869  else
1870  {
1871  neighbor_conn->Clone( *member );
1872 
1873  recacheSubgraphName( neighbor, neighbor_name );
1874 
1875  // Recurse onto this neighbor in case it needs to re-propagate
1876  neighbor->m_dirty = true;
1877  propagateToNeighbors( neighbor );
1878  }
1879  }
1880  }
1881  };
1882 
1883  // If we are a bus, we must propagate to local neighbors and then the hierarchy
1884  if( conn->IsBus() )
1885  propagate_bus_neighbors( aSubgraph );
1886 
1887  // If we have both ports and pins, skip processing as we'll be visited by a parent or child.
1888  // If we only have one or the other, process (we can either go bottom-up or top-down depending
1889  // on which subgraph comes up first)
1890  if( !aSubgraph->m_hier_ports.empty() && !aSubgraph->m_hier_pins.empty() )
1891  {
1892  wxLogTrace( ConnTrace, wxT( "%lu (%s) has both hier ports and pins; deferring processing" ),
1893  aSubgraph->m_code, conn->Name() );
1894  return;
1895  }
1896  else if( aSubgraph->m_hier_ports.empty() && aSubgraph->m_hier_pins.empty() )
1897  {
1898  wxLogTrace( ConnTrace, wxT( "%lu (%s) has no hier pins or ports; marking clean" ),
1899  aSubgraph->m_code, conn->Name() );
1900  aSubgraph->m_dirty = false;
1901  return;
1902  }
1903 
1904  visited.insert( aSubgraph );
1905 
1906  wxLogTrace( ConnTrace, wxT( "Propagating %lu (%s) to subsheets" ),
1907  aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1908 
1909  visit( aSubgraph );
1910 
1911  for( unsigned i = 0; i < search_list.size(); i++ )
1912  {
1913  auto child = search_list[i];
1914 
1915  visited.insert( child );
1916 
1917  visit( child );
1918 
1919  child->m_dirty = false;
1920  }
1921 
1922  // Now, find the best driver for this chain of subgraphs
1923  CONNECTION_SUBGRAPH* bestDriver = aSubgraph;
1926  bool bestIsStrong = ( highest >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1927  wxString bestName = aSubgraph->m_driver_connection->Name();
1928 
1929  // Check if a subsheet has a higher-priority connection to the same net
1931  {
1932  for( CONNECTION_SUBGRAPH* subgraph : visited )
1933  {
1934  if( subgraph == aSubgraph )
1935  continue;
1936 
1938  CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
1939 
1940  bool candidateStrong = ( priority >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1941  wxString candidateName = subgraph->m_driver_connection->Name();
1942  bool shorterPath = subgraph->m_sheet.size() < bestDriver->m_sheet.size();
1943  bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->m_sheet.size();
1944 
1945  // Pick a better driving subgraph if it:
1946  // a) has a power pin or global driver
1947  // b) is a strong driver and we're a weak driver
1948  // c) is a higher priority strong driver
1949  // d) matches our priority, is a strong driver, and has a shorter path
1950  // e) matches our strength and is at least as short, and is alphabetically lower
1951 
1952  if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
1953  ( !bestIsStrong && candidateStrong ) ||
1954  ( priority > highest && candidateStrong ) ||
1955  ( priority == highest && candidateStrong && shorterPath ) ||
1956  ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
1957  ( candidateName < bestName ) ) )
1958  {
1959  bestDriver = subgraph;
1960  highest = priority;
1961  bestIsStrong = candidateStrong;
1962  bestName = candidateName;
1963  }
1964  }
1965  }
1966 
1967  if( bestDriver != aSubgraph )
1968  {
1969  wxLogTrace( ConnTrace, wxT( "%lu (%s) overridden by new driver %lu (%s)" ),
1970  aSubgraph->m_code, aSubgraph->m_driver_connection->Name(), bestDriver->m_code,
1971  bestDriver->m_driver_connection->Name() );
1972  }
1973 
1974  conn = bestDriver->m_driver_connection;
1975 
1976  for( CONNECTION_SUBGRAPH* subgraph : visited )
1977  {
1978  wxString old_name = subgraph->m_driver_connection->Name();
1979 
1980  subgraph->m_driver_connection->Clone( *conn );
1981 
1982  if( old_name != conn->Name() )
1983  recacheSubgraphName( subgraph, old_name );
1984 
1985  if( conn->IsBus() )
1986  propagate_bus_neighbors( subgraph );
1987  }
1988 
1989  // Somewhere along the way, a bus member may have been upgraded to a global or power label.
1990  // Because this can happen anywhere, we need a second pass to update all instances of that bus
1991  // member to have the correct connection info
1992  if( conn->IsBus() && !stale_bus_members.empty() )
1993  {
1994  for( SCH_CONNECTION* stale_member : stale_bus_members )
1995  {
1996  for( CONNECTION_SUBGRAPH* subgraph : visited )
1997  {
1998  SCH_CONNECTION* member = matchBusMember( subgraph->m_driver_connection,
1999  stale_member );
2000 
2001  if( !member )
2002  {
2003  wxLogTrace( ConnTrace, wxT( "WARNING: failed to match stale member %s in %s." ),
2004  stale_member->Name(), subgraph->m_driver_connection->Name() );
2005  continue;
2006  }
2007 
2008  wxLogTrace( ConnTrace, wxT( "Updating %lu (%s) member %s to %s" ), subgraph->m_code,
2009  subgraph->m_driver_connection->Name(), member->LocalName(),
2010  stale_member->Name() );
2011 
2012  member->Clone( *stale_member );
2013 
2014  propagate_bus_neighbors( subgraph );
2015  }
2016  }
2017  }
2018 
2019  aSubgraph->m_dirty = false;
2020 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
#define kv
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
std::vector< SCH_SHEET_PIN * > m_hier_pins
wxString LocalName() const
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
size_t size() const
Forwarded method from std::vector.
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::vector< SCH_HIERLABEL * > m_hier_ports
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
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.
CONNECTION_SUBGRAPH * m_hier_parent
bool IsBus() const
CONNECTION_TYPE Type() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
PRIORITY GetDriverPriority()
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.

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, SCH_SHEET_PATH::push_back(), recacheSubgraphName(), SCH_SHEET_PATH::size(), and SCH_CONNECTION::Type().

Referenced by buildConnectionGraph().

◆ recacheSubgraphName()

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

Definition at line 2114 of file connection_graph.cpp.

2116 {
2117  auto it = m_net_name_to_subgraphs_map.find( aOldName );
2118 
2119  if( it != m_net_name_to_subgraphs_map.end() )
2120  {
2121  std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2122  alg::delete_matching( vec, aSubgraph );
2123  }
2124 
2125  wxLogTrace( ConnTrace, wxT( "recacheSubgraphName: %s => %s" ), aOldName,
2126  aSubgraph->m_driver_connection->Name() );
2127 
2128  m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
2129 }
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
static const wxChar ConnTrace[]
wxString Name(bool aIgnoreSheet=false) const
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

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 440 of file connection_graph.cpp.

442 {
443  PROF_TIMER recalc_time( "CONNECTION_GRAPH::Recalculate" );
444 
445  if( aUnconditional )
446  Reset();
447 
448  PROF_TIMER update_items( "updateItemConnectivity" );
449 
450  m_sheetList = aSheetList;
451 
452  for( const SCH_SHEET_PATH& sheet : aSheetList )
453  {
454  std::vector<SCH_ITEM*> items;
455 
456  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
457  {
458  if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
459  items.push_back( item );
460  }
461 
462  m_items.reserve( m_items.size() + items.size() );
463 
464  updateItemConnectivity( sheet, items );
465 
466  // UpdateDanglingState() also adds connected items for SCH_TEXT
467  sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
468  }
469 
470  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
471  update_items.Show();
472 
473  PROF_TIMER build_graph( "buildConnectionGraph" );
474 
476 
477  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
478  build_graph.Show();
479 
480  recalc_time.Stop();
481 
482  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
483  recalc_time.Show();
484 
485 #ifndef DEBUG
486  // Pressure relief valve for release builds
487  const double max_recalc_time_msecs = 250.;
488 
489  if( m_allowRealTime && ADVANCED_CFG::GetCfg().m_RealTimeConnectivity &&
490  recalc_time.msecs() > max_recalc_time_msecs )
491  {
492  m_allowRealTime = false;
493  }
494 #endif
495 }
void buildConnectionGraph()
Generates the connection graph (after all item connectivity has been updated)
std::vector< SCH_ITEM * > m_items
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
A small class to help profiling.
Definition: profile.h:46
static const wxChar ConnProfileMask[]
static bool m_allowRealTime
SCH_SHEET_LIST m_sheetList
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182

References buildConnectionGraph(), ConnProfileMask, ADVANCED_CFG::GetCfg(), m_allowRealTime, m_items, m_sheetList, PROF_TIMER::msecs(), Reset(), PROF_TIMER::Show(), PROF_TIMER::Stop(), and updateItemConnectivity().

Referenced by TEST_NETLISTS_FIXTURE::loadSchematic(), SCH_EDIT_FRAME::RecalculateConnections(), and SCH_SCREENS::UpdateSymbolLinks().

◆ Reset()

void CONNECTION_GRAPH::Reset ( )

Definition at line 416 of file connection_graph.cpp.

417 {
418  for( auto& subgraph : m_subgraphs )
419  delete subgraph;
420 
421  m_items.clear();
422  m_subgraphs.clear();
423  m_driver_subgraphs.clear();
424  m_sheet_to_subgraphs_map.clear();
425  m_invisible_power_pins.clear();
426  m_bus_alias_cache.clear();
427  m_net_name_to_code_map.clear();
428  m_bus_name_to_code_map.clear();
431  m_item_to_subgraph_map.clear();
432  m_local_label_cache.clear();
433  m_global_label_cache.clear();
434  m_last_net_code = 1;
435  m_last_bus_code = 1;
437 }
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
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
NET_MAP m_net_code_to_subgraphs_map
std::vector< SCH_ITEM * > m_items
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
std::map< wxString, int > m_bus_name_to_code_map
std::map< wxString, int > m_net_name_to_code_map
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

References m_bus_alias_cache, m_bus_name_to_code_map, m_driver_subgraphs, m_global_label_cache, m_invisible_power_pins, m_item_to_subgraph_map, m_items, m_last_bus_code, m_last_net_code, m_last_subgraph_code, m_local_label_cache, m_net_code_to_subgraphs_map, m_net_name_to_code_map, m_net_name_to_subgraphs_map, m_sheet_to_subgraphs_map, and m_subgraphs.

Referenced by SCH_EDIT_FRAME::OpenProjectFiles(), Recalculate(), SCHEMATIC::Reset(), SCHEMATIC::SetRoot(), and ~CONNECTION_GRAPH().

◆ resolveAllDrivers()

void CONNECTION_GRAPH::resolveAllDrivers ( )
private

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

Definition at line 809 of file connection_graph.cpp.

810 {
811  // Resolve drivers for subgraphs and propagate connectivity info
812 
813  // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
814  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
815  ( m_subgraphs.size() + 3 ) / 4 );
816 
817  std::atomic<size_t> nextSubgraph( 0 );
818  std::vector<std::future<size_t>> returns( parallelThreadCount );
819  std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
820 
821  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( dirty_graphs ),
822  [&] ( const CONNECTION_SUBGRAPH* candidate )
823  {
824  return candidate->m_dirty;
825  } );
826 
827  auto update_lambda = [&nextSubgraph, &dirty_graphs]() -> size_t
828  {
829  for( size_t subgraphId = nextSubgraph++; subgraphId < dirty_graphs.size(); subgraphId = nextSubgraph++ )
830  {
831  auto subgraph = dirty_graphs[subgraphId];
832 
833  if( !subgraph->m_dirty )
834  continue;
835 
836  // Special processing for some items
837  for( auto item : subgraph->m_items )
838  {
839  switch( item->Type() )
840  {
841  case SCH_NO_CONNECT_T:
842  subgraph->m_no_connect = item;
843  break;
844 
846  subgraph->m_bus_entry = item;
847  break;
848 
849  case SCH_PIN_T:
850  {
851  auto pin = static_cast<SCH_PIN*>( item );
852 
853  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
854  subgraph->m_no_connect = item;
855 
856  break;
857  }
858 
859  default:
860  break;
861  }
862  }
863 
864  subgraph->ResolveDrivers( true );
865  subgraph->m_dirty = false;
866  }
867 
868  return 1;
869  };
870 
871  if( parallelThreadCount == 1 )
872  update_lambda();
873  else
874  {
875  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
876  returns[ii] = std::async( std::launch::async, update_lambda );
877 
878  // Finalize the threads
879  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
880  returns[ii].wait();
881  }
882 
883  // Now discard any non-driven subgraphs from further consideration
884 
885  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( m_driver_subgraphs ),
886  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
887  {
888  return candidate->m_driver;
889  } );
890 }
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
A subgraph is a set of items that are electrically connected on a single sheet.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
not connected (must be left open)

References m_driver_subgraphs, m_subgraphs, pin, PT_NC, SCH_BUS_WIRE_ENTRY_T, SCH_NO_CONNECT_T, and SCH_PIN_T.

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 2233 of file connection_graph.cpp.

2234 {
2235  int error_count = 0;
2236 
2237  wxCHECK_MSG( m_schematic, true, wxT( "Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
2238 
2239  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2240 
2241  // We don't want to run many ERC checks more than once on a given screen even though it may
2242  // represent multiple sheets with multiple subgraphs. We can tell these apart by drivers.
2243  std::set<SCH_ITEM*> seenDriverInstances;
2244 
2245  for( CONNECTION_SUBGRAPH* subgraph : m_subgraphs )
2246  {
2247  // There shouldn't be any null sub-graph pointers.
2248  wxCHECK2( subgraph, continue );
2249 
2250  // Graph is supposed to be up-to-date before calling RunERC()
2251  wxASSERT( !subgraph->m_dirty );
2252 
2253  if( subgraph->m_absorbed )
2254  continue;
2255 
2256  if( seenDriverInstances.count( subgraph->m_driver ) )
2257  continue;
2258 
2259  if( subgraph->m_driver )
2260  seenDriverInstances.insert( subgraph->m_driver );
2261 
2272  if( settings.IsTestEnabled( ERCE_DRIVER_CONFLICT ) )
2273  {
2274  if( !ercCheckMultipleDrivers( subgraph ) )
2275  error_count++;
2276  }
2277 
2278  subgraph->ResolveDrivers( false );
2279 
2280  if( settings.IsTestEnabled( ERCE_BUS_TO_NET_CONFLICT ) )
2281  {
2282  if( !ercCheckBusToNetConflicts( subgraph ) )
2283  error_count++;
2284  }
2285 
2286  if( settings.IsTestEnabled( ERCE_BUS_ENTRY_CONFLICT ) )
2287  {
2288  if( !ercCheckBusToBusEntryConflicts( subgraph ) )
2289  error_count++;
2290  }
2291 
2292  if( settings.IsTestEnabled( ERCE_BUS_TO_BUS_CONFLICT ) )
2293  {
2294  if( !ercCheckBusToBusConflicts( subgraph ) )
2295  error_count++;
2296  }
2297 
2298  if( settings.IsTestEnabled( ERCE_WIRE_DANGLING ) )
2299  {
2300  if( !ercCheckFloatingWires( subgraph ) )
2301  error_count++;
2302  }
2303 
2304  if( settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED )
2306  || settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2307  {
2308  if( !ercCheckNoConnects( subgraph ) )
2309  error_count++;
2310  }
2311 
2312  if( settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED )
2313  || settings.IsTestEnabled( ERCE_GLOBLABEL ) )
2314  {
2315  if( !ercCheckLabels( subgraph ) )
2316  error_count++;
2317  }
2318  }
2319 
2320  // Hierarchical sheet checking is done at the schematic level
2321  if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL )
2322  || settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2323  {
2324  error_count += ercCheckHierSheets();
2325  }
2326 
2327  return error_count;
2328 }
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:59
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:61
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
Some wires are not connected to anything else.
Definition: erc_settings.h:65
Label not connected to anything.
Definition: erc_settings.h:49
SCHEMATIC * m_schematic
The schematic this graph represents.
A subgraph is a set of items that are electrically connected on a single sheet.
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.
Container for ERC settings.
Definition: erc_settings.h:106
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:57
A no connect symbol is not connected to anything.
Definition: erc_settings.h:48
A global label is unique.
Definition: erc_settings.h:63
A no connect symbol is connected to more than 1 pin.
Definition: erc_settings.h:47
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:46
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:56
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.

References ercCheckBusToBusConflicts(), ercCheckBusToBusEntryConflicts(), ercCheckBusToNetConflicts(), ercCheckFloatingWires(), ercCheckHierSheets(), ercCheckLabels(), ercCheckMultipleDrivers(), 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_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, ERCE_WIRE_DANGLING, SCHEMATIC::ErcSettings(), ERC_SETTINGS::IsTestEnabled(), m_schematic, and m_subgraphs.

Referenced by DIALOG_ERC::testErc().

◆ SetSchematic()

void CONNECTION_GRAPH::SetSchematic ( SCHEMATIC aSchematic)
inline

Definition at line 265 of file connection_graph.h.

266  {
267  m_schematic = aSchematic;
268  }
SCHEMATIC * m_schematic
The schematic this graph represents.

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 498 of file connection_graph.cpp.

500 {
501  std::map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
502 
503  for( SCH_ITEM* item : aItemList )
504  {
505  std::vector< wxPoint > points = item->GetConnectionPoints();
506  item->ConnectedItems( aSheet ).clear();
507 
508  if( item->Type() == SCH_SHEET_T )
509  {
510  for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
511  {
512  pin->InitializeConnection( aSheet, this );
513 
514  pin->ConnectedItems( aSheet ).clear();
515 
516  connection_map[ pin->GetTextPos() ].push_back( pin );
517  m_items.emplace_back( pin );
518  }
519  }
520  else if( item->Type() == SCH_SYMBOL_T )
521  {
522  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
523 
524  for( SCH_PIN* pin : symbol->GetPins( &aSheet ) )
525  {
526  pin->InitializeConnection( aSheet, this );
527 
528  wxPoint pos = pin->GetPosition();
529 
530  // because calling the first time is not thread-safe
531  pin->GetDefaultNetName( aSheet );
532  pin->ConnectedItems( aSheet ).clear();
533 
534  // Invisible power pins need to be post-processed later
535 
536  if( pin->IsPowerConnection() && !pin->IsVisible() )
537  m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) );
538 
539  connection_map[ pos ].push_back( pin );
540  m_items.emplace_back( pin );
541  }
542  }
543  else
544  {
545  m_items.emplace_back( item );
546  SCH_CONNECTION* conn = item->InitializeConnection( aSheet, this );
547 
548  // Set bus/net property here so that the propagation code uses it
549  switch( item->Type() )
550  {
551  case SCH_LINE_T:
552  conn->SetType( item->GetLayer() == LAYER_BUS ? CONNECTION_TYPE::BUS :
554  break;
555 
556  case SCH_BUS_BUS_ENTRY_T:
557  conn->SetType( CONNECTION_TYPE::BUS );
558  // clean previous (old) links:
559  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] = nullptr;
560  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] = nullptr;
561  break;
562 
563  case SCH_PIN_T:
564  conn->SetType( CONNECTION_TYPE::NET );
565  break;
566 
568  conn->SetType( CONNECTION_TYPE::NET );
569  // clean previous (old) link:
570  static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item = nullptr;
571  break;
572 
573  default:
574  break;
575  }
576 
577  for( const wxPoint& point : points )
578  connection_map[ point ].push_back( item );
579  }
580 
581  item->SetConnectivityDirty( false );
582  }
583 
584  for( const auto& it : connection_map )
585  {
586  const std::vector<SCH_ITEM*>& connection_vec = it.second;
587 
588  // Pre-scan to see if we have a bus at this location
589  SCH_LINE* busLine = aSheet.LastScreen()->GetBus( it.first );
590 
591  // We don't want to spin up a new thread for fewer than 4 items (overhead costs)
592  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
593  ( connection_vec.size() + 3 ) / 4 );
594 
595  std::atomic<size_t> nextItem( 0 );
596  std::mutex update_mutex;
597  std::vector<std::future<size_t>> returns( parallelThreadCount );
598 
599  auto update_lambda = [&]() -> size_t
600  {
601  for( size_t ii = nextItem++; ii < connection_vec.size(); ii = nextItem++ )
602  {
603  SCH_ITEM* connected_item = connection_vec[ii];
604  // Bus entries are special: they can have connection points in the
605  // middle of a wire segment, because the junction algo doesn't split
606  // the segment in two where you place a bus entry. This means that
607  // bus entries that don't land on the end of a line segment need to
608  // have "virtual" connection points to the segments they graphically
609  // touch.
610  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
611  {
612  // If this location only has the connection point of the bus
613  // entry itself, this means that either the bus entry is not
614  // connected to anything graphically, or that it is connected to
615  // a segment at some point other than at one of the endpoints.
616  if( connection_vec.size() == 1 )
617  {
618  if( busLine )
619  {
620  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
621  bus_entry->m_connected_bus_item = busLine;
622  }
623  }
624  }
625 
626  // Bus-to-bus entries are treated just like bus wires
627  else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
628  {
629  if( connection_vec.size() < 2 )
630  {
631  if( busLine )
632  {
633  auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
634 
635  if( it.first == bus_entry->GetPosition() )
636  bus_entry->m_connected_bus_items[0] = busLine;
637  else
638  bus_entry->m_connected_bus_items[1] = busLine;
639 
640  std::lock_guard<std::mutex> lock( update_mutex );
641  bus_entry->AddConnectionTo( aSheet, busLine );
642  busLine->AddConnectionTo( aSheet, bus_entry );
643  }
644  }
645  }
646 
647  // Change junctions to be on bus junction layer if they are touching a bus
648  else if( connected_item->Type() == SCH_JUNCTION_T )
649  {
650  connected_item->SetLayer( busLine ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
651  }
652 
653  SCH_ITEM_SET& connected_set = connected_item->ConnectedItems( aSheet );
654  connected_set.reserve( connection_vec.size() );
655 
656  for( SCH_ITEM* test_item : connection_vec )
657  {
658  bool bus_connection_ok = true;
659 
660  if( test_item == connected_item )
661  continue;
662 
663  // Set up the link between the bus entry net and the bus
664  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
665  {
666  if( test_item->GetLayer() == LAYER_BUS )
667  {
668  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
669  bus_entry->m_connected_bus_item = test_item;
670  }
671  }
672 
673  // Bus entries only connect to bus lines on the end that is touching a bus line.
674  // If the user has overlapped another net line with the endpoint of the bus entry
675  // where the entry connects to a bus, we don't want to short-circuit it.
676  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
677  {
678  bus_connection_ok = !busLine || test_item->GetLayer() == LAYER_BUS;
679  }
680  else if( test_item->Type() == SCH_BUS_WIRE_ENTRY_T )
681  {
682  bus_connection_ok = !busLine || connected_item->GetLayer() == LAYER_BUS;
683  }
684 
685  if( connected_item->ConnectionPropagatesTo( test_item ) &&
686  test_item->ConnectionPropagatesTo( connected_item ) &&
687  bus_connection_ok )
688  {
689  connected_set.push_back( test_item );
690  }
691  }
692 
693  // If we got this far and did not find a connected bus item for a bus entry,
694  // we should do a manual scan in case there is a bus item on this connection
695  // point but we didn't pick it up earlier because there is *also* a net item here.
696  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
697  {
698  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
699 
700  if( !bus_entry->m_connected_bus_item )
701  {
702  SCH_SCREEN* screen = aSheet.LastScreen();
703  SCH_LINE* bus = screen->GetBus( it.first );
704 
705  if( bus )
706  bus_entry->m_connected_bus_item = bus;
707  }
708  }
709  }
710 
711  return 1;
712  };
713 
714 
715  if( parallelThreadCount == 1 )
716  update_lambda();
717  else
718  {
719  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
720  returns[ii] = std::async( std::launch::async, update_lambda );
721 
722  // Finalize the threads
723  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
724  returns[ii].wait();
725  }
726  }
727 }
void AddConnectionTo(const SCH_SHEET_PATH &aPath, SCH_ITEM *aItem)
Add a connection link between this item and another.
Definition: sch_item.cpp:183
virtual bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const
Return true if this item should propagate connection info to aItem.
Definition: sch_item.h:411
std::vector< SCH_ITEM * > m_items
std::vector< SCH_ITEM * > SCH_ITEM_SET
Definition: sch_item.h:134
SCH_LINE * GetBus(const wxPoint &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:429
void SetLayer(SCH_LAYER_ID aLayer)
Set the layer this item is on.
Definition: sch_item.h:266
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
This item represents a net.
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:259
Schematic symbol object.
Definition: sch_symbol.h:78
SCH_SCREEN * LastScreen()
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
SCH_ITEM_SET & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieve the set of items connected to this item on the given sheet.
Definition: sch_item.cpp:177
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void SetType(CONNECTION_TYPE aType)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:896
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112

References SCH_ITEM::AddConnectionTo(), BUS, SCH_ITEM::ConnectedItems(), SCH_ITEM::ConnectionPropagatesTo(), SCH_SCREEN::GetBus(), SCH_ITEM::GetLayer(), SCH_SYMBOL::GetPins(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, LAYER_BUS_JUNCTION, LAYER_JUNCTION, 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::SetLayer(), SCH_CONNECTION::SetType(), and EDA_ITEM::Type().

Referenced by Recalculate().

Member Data Documentation

◆ m_allowRealTime

◆ m_bus_alias_cache

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

Definition at line 555 of file connection_graph.h.

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

◆ m_bus_name_to_code_map

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

Definition at line 559 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::map<wxString, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_global_label_cache
private

Definition at line 561 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::map<SCH_ITEM*, CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_item_to_subgraph_map
private

Definition at line 568 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 542 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 574 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 572 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 576 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

◆ m_net_code_to_subgraphs_map

NET_MAP CONNECTION_GRAPH::m_net_code_to_subgraphs_map
private

◆ m_net_name_to_code_map

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

Definition at line 557 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 578 of file connection_graph.h.

Referenced by buildConnectionGraph(), 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 539 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: