80class ERC_MARKER_PLACER
83 explicit ERC_MARKER_PLACER(
const SCHEMATIC& aSchematic ) :
84 m_schematic( aSchematic )
88 const SCH_SHEET_PATH* Find(
const KIID_PATH& aSheet )
92 m_hierarchy = m_schematic.Hierarchy();
95 for(
const SCH_SHEET_PATH&
path : m_hierarchy )
96 m_paths->emplace(
path.PathRef(), &
path );
99 if(
const auto found = m_paths->find( aSheet ); found != m_paths->end() )
100 return found->second;
102 wxLogTrace(
"KICAD_CONNECTIVITY",
"ERC connectivity references unknown sheet instance %s", aSheet.
AsString() );
106 void Place( std::shared_ptr<ERC_ITEM> aItem,
const KIID_PATH& aSheet,
const VECTOR2I& aPosition,
107 ITEM_PATHS aItemPaths = ITEM_PATHS::NONE,
bool aSheetSpecific =
true )
109 const SCH_SHEET_PATH* sheet = Find( aSheet );
114 if( aItemPaths == ITEM_PATHS::BOTH && aItem->GetAuxItemID() !=
niluuid )
115 aItem->SetItemsSheetPaths( *sheet, *sheet );
116 else if( aItemPaths != ITEM_PATHS::NONE )
117 aItem->SetItemsSheetPaths( *sheet );
119 append( std::move( aItem ), *sheet, aPosition, aSheetSpecific );
122 void Place( std::shared_ptr<ERC_ITEM> aItem,
const KIID_PATH& aSheet,
const VECTOR2I& aPosition,
123 const KIID_PATH& aMainItemSheet,
const KIID_PATH& aAuxItemSheet )
125 const SCH_SHEET_PATH* sheet = Find( aSheet );
126 const SCH_SHEET_PATH*
main = Find( aMainItemSheet );
127 const SCH_SHEET_PATH* aux = Find( aAuxItemSheet );
129 if( !sheet || !
main || !aux )
132 aItem->SetItemsSheetPaths( *
main, *aux );
133 append( std::move( aItem ), *sheet, aPosition );
136 void Report(
int aCode,
const std::vector<KIID>& aItems,
const KIID_PATH& aSheet,
const VECTOR2I& aPosition,
137 ITEM_PATHS aItemPaths = ITEM_PATHS::NONE,
const wxString& aMessage = wxEmptyString )
140 item->SetItems( aItems );
142 if( !aMessage.empty() )
143 item->SetErrorMessage( aMessage );
145 Place( std::move( item ), aSheet, aPosition, aItemPaths );
148 int Count()
const {
return m_count; }
151 void append( std::shared_ptr<ERC_ITEM> aItem,
const SCH_SHEET_PATH& aSheet,
const VECTOR2I& aPosition,
152 bool aSheetSpecific =
true )
155 aItem->SetSheetSpecificPath( aSheet );
157 aSheet.
LastScreen()->
Append(
new SCH_MARKER( std::move( aItem ), aPosition ) );
162 SCH_SHEET_LIST m_hierarchy;
163 std::optional<std::map<KIID_PATH, const SCH_SHEET_PATH*>> m_paths;
172 std::vector<SCH_CONNECTIVITY::FOOTPRINT_SOURCE>
result;
178 const auto& symbol = *
static_cast<SCH_SYMBOL*
>( item );
179 const auto&
library = symbol.GetLibSymbolRef();
180 result.push_back( {
path.PathRef(), symbol.m_Uuid, symbol.GetPosition(),
189template <
typename LOCATION>
190int reportSourceErrors(
SCHEMATIC& aSchematic,
int aCode,
const std::vector<LOCATION>& aSources )
192 ERC_MARKER_PLACER markers( aSchematic );
194 for(
const auto&
source : aSources )
195 markers.Report( aCode, {
source.item },
source.sheet,
source.position, ITEM_PATHS::MAIN );
197 return markers.Count();
200std::vector<SCH_CONNECTIVITY::NAMED_ITEM> collectNamedItems(
SCHEMATIC& aSchematic,
bool aSimilar )
206 std::vector<SCH_CONNECTIVITY::NAMED_ITEM>
result;
214 for(
SCH_ITEM* item : subgraph->GetItems() )
220 result.push_back( { sheet.
PathRef(), item->m_Uuid, item->GetPosition(),
221 label->GetShownText( &sheet,
FOR_NETNAME ), item->Type(),
229 if( !
pin->IsPower() || !symbol )
244void reportNameConflict( ERC_MARKER_PLACER& aMarkers,
ERC_SETTINGS& aSettings,
ERCE_T aCode,
251 item->SetItems( aMain.
item, aAux.
item );
277 _(
"Bidirectional Pin" ),
278 _(
"Tri-State Pin" ),
281 _(
"Unspecified Pin" ),
282 _(
"Power Input Pin" ),
283 _(
"Power Output Pin" ),
284 _(
"Open Collector" ),
294 _(
"Bidirectional Pin" ),
295 _(
"Tri-State Pin" ),
298 _(
"Unspecified Pin" ),
299 _(
"Power Input Pin" ),
300 _(
"Power Output Pin" ),
301 _(
"Open Collector" ),
340 m_sheetList( aSchematic->BuildSheetListSortedByPageNumbers() ),
342 m_nets( aSchematic->ConnectionGraph()->GetNetMap() ),
357 const auto errors =
m_schematic->Connectivity().Engine().DuplicateSheetNames();
360 for(
const auto& error : errors )
366 return markers.Count();
372 std::vector<SCH_SHEET*> list;
375 list.push_back(
static_cast<SCH_SHEET*
>( item ) );
377 for(
size_t i = 0; i < list.size(); i++ )
381 for(
size_t j = i + 1; j < list.size(); j++ )
388 const wxString variant =
m_schematic->GetCurrentVariant();
389 const wxString
name =
391 const wxString other =
394 if(
name.IsSameAs( other,
false ) )
399 ercItem->SetItems( sheet, test_item );
400 ercItem->SetSheetSpecificPath(
path );
401 ercItem->SetItemsSheetPaths(
path,
path );
424 typedef void ( *PAD_NUMBERS_FN_PTR )(
const wxString&,
PROJECT*, std::set<wxString>& );
426 PAD_NUMBERS_FN_PTR padFetcher =
429 std::map<wxString, std::set<wxString>> padCache;
431 auto getPads = [&](
const wxString& aFootprintId ) ->
const std::set<wxString>&
433 auto it = padCache.find( aFootprintId );
435 if( it != padCache.end() )
438 std::set<wxString>& pads = padCache[aFootprintId];
440 if( padFetcher && !aFootprintId.IsEmpty() )
441 padFetcher( aFootprintId, aProject, pads );
450 std::vector<SCH_CONNECTIVITY::PIN_MAP_FACT> sources;
454 sources =
m_schematic->Connectivity().Engine().PinMapSymbols( screen->ConnectivityId() );
461 sources.push_back( std::move( *
source ) );
465 for(
const auto&
source : sources )
468 const auto& pinNumbers =
source.pinNumbers;
469 const auto& jumperGroups =
source.jumperGroups;
471 auto sharesJumperGroup = [&](
const wxString& aPinA,
const wxString& aPinB )
475 if(
group.Contains( aPinA ) &&
group.Contains( aPinB ) )
488 if( pinNumbers.count( entry.m_PinNumber ) )
492 ercItem->SetItems(
source.id );
493 ercItem->SetErrorMessage(
494 wxString::Format(
_(
"Pin map '%s' references unknown symbol pin '%s'" ), map.GetName(),
495 entry.m_PinNumber ) );
504 std::map<wxString, wxString> padToPin;
510 auto it = padToPin.find(
pad );
512 if( it == padToPin.end() )
514 padToPin[
pad] = entry.m_PinNumber;
516 else if( it->second != entry.m_PinNumber
517 && !sharesJumperGroup( it->second, entry.m_PinNumber ) )
520 ercItem->SetItems(
source.id );
521 ercItem->SetErrorMessage(
522 wxString::Format(
_(
"Symbol pins '%s' and '%s' both map to pad '%s'" ),
523 it->second, entry.m_PinNumber,
pad ) );
532 if( checkBadPad && padFetcher )
550 if( pads.count(
pad ) )
554 ercItem->SetItems(
source.id );
555 ercItem->SetErrorMessage( wxString::Format(
556 _(
"Pin map '%s' references pad '%s' not present on footprint '%s'" ),
570 const wxString& number,
const wxString& footprint )
573 error->SetItems(
pin );
574 error->SetSheetSpecificPath( sheet );
575 error->SetItemsSheetPaths( sheet );
576 error->SetErrorMessage( wxString::Format(
577 _(
"Pin '%s' is connected but maps to no pad on footprint '%s'" ), number, footprint ) );
586 for(
const auto&
pin :
m_schematic->Connectivity().Engine().UnmappedPinCandidates() )
594 footprint.
Parse(
pin.footprint,
true );
598 report( *sheet,
pin.item,
pin.position,
pin.number,
pin.footprint );
619 if( fpText.IsEmpty() || fpId.
Parse( fpText,
true ) >= 0 )
629 if(
pin->IsDangling() )
633 pin->GetEffectivePadNumber( sheet, variant, fpId, &pads, &state );
635 if( state != SCH_PIN::PAD_RESOLUTION::UNMAPPED )
638 report( sheet,
pin->m_Uuid,
pin->GetPosition(),
pin->GetNumber(), fpText );
654 static wxRegEx varRefRegEx( wxT(
"(^|[^\\\\])\\$\\{.*\\}.*" ) );
656 auto reportAssertions =
658 const std::vector<SCH_CONNECTIVITY::TEXT_ASSERTION>& assertions,
const VECTOR2I& pos )
660 for(
const auto& assertion : assertions )
663 wxString
message = assertion.message;
667 ercItem->SetItems( std::vector<KIID>{ item } );
668 ercItem->SetItemsSheetPaths( sheet );
672 message +=
_(
" (in drawing sheet)" );
675 ercItem->SetSheetSpecificPath( sheet );
676 ercItem->SetErrorMessage(
message );
677 screen->Append(
new SCH_MARKER( std::move( ercItem ), pos ) );
680 return !assertions.empty();
699 ?
m_schematic->Connectivity().TextChecks( sheet.PathRef() )
702 for(
const auto&
source : sources )
704 if( reportAssertions(
source.assertionItem, sheet, screen,
source.assertions,
source.assertionPosition ) )
707 if( !varRefRegEx.Matches(
source.shownText ) )
711 ercItem->SetItems( std::vector<KIID>{
source.item } );
712 ercItem->SetSheetSpecificPath( sheet );
713 ercItem->SetItemsSheetPaths( sheet );
719 for(
const auto&
source :
m_schematic->Connectivity().TextChecks( sheet.PathRef(),
true ) )
721 if( reportAssertions(
niluuid, sheet, screen,
source.assertions,
source.assertionPosition ) )
724 if( varRefRegEx.Matches(
source.shownText ) )
727 ercItem->SetErrorMessage(
_(
"Unresolved text variable in drawing sheet" ) );
728 ercItem->SetSheetSpecificPath( sheet );
738 if( reportAssertions(
niluuid, sheet, screen,
740 text->GetPosition() ) )
750 ercItem->SetErrorMessage(
_(
"Unresolved text variable in drawing sheet" ) );
751 ercItem->SetSheetSpecificPath( sheet );
767 m_schematic->Connectivity().Engine().EmptyPowerValues() );
782 if( !
pin->IsGlobalPower() && !
pin->IsLocalPower() )
785 const SYMBOL* parent =
pin->GetLibPin() ?
pin->GetLibPin()->GetParentSymbol() :
nullptr;
793 if(
name.Trim(
false ).Trim(
true ).IsEmpty() )
796 ercItem->SetItems(
pin );
797 ercItem->SetItemsSheetPaths( sheet );
798 ercItem->SetSheetSpecificPath( sheet );
819 m_schematic->Connectivity().Engine().EmptyLabels() );
838 text.Trim(
false ).Trim(
true );
843 ercItem->SetItems( label );
844 ercItem->SetItemsSheetPaths( sheet );
845 ercItem->SetSheetSpecificPath( sheet );
865 const auto errors =
m_schematic->Connectivity().Engine().InvalidFieldNames();
868 for(
const auto& error : errors )
871 error.field.position, ITEM_PATHS::BOTH,
872 wxString::Format(
_(
"Field name has leading or trailing whitespace: '%s'" ),
873 error.field.name ) );
876 return markers.Count();
889 wxString trimmedFieldName = field.GetName();
890 trimmedFieldName.Trim();
891 trimmedFieldName.Trim(
false );
893 if( field.GetName() != trimmedFieldName )
896 ercItem->SetItems( symbol, &field );
897 ercItem->SetItemsSheetPaths( sheet, sheet );
898 ercItem->SetSheetSpecificPath( sheet );
899 ercItem->SetErrorMessage(
901 _(
"Field name has leading or trailing whitespace: '%s'" ),
917 wxString trimmedFieldName = field.GetName();
918 trimmedFieldName.Trim();
919 trimmedFieldName.Trim(
false );
921 if( field.GetName() != trimmedFieldName )
924 ercItem->SetItems( subSheet, &field );
925 ercItem->SetItemsSheetPaths( sheet, sheet );
926 ercItem->SetSheetSpecificPath( sheet );
927 ercItem->SetErrorMessage(
929 _(
"Field name has leading or trailing whitespace: '%s'" ),
949 return m_schematic->Connectivity().Engine().MultiUnitSymbols();
951 std::vector<MULTI_UNIT_GROUP>
result;
953 for(
const auto& [reference, refs] :
m_refMap )
955 if( refs.GetCount() == 0 )
959 group.reference = reference;
962 for(
size_t i = 0; i < refs.GetCount(); ++i )
986 for(
const auto& unit :
group.instances )
988 if( !unit.footprint.IsEmpty() )
999 for(
const auto& unit :
group.instances )
1001 if( unit.item == reference->
item && unit.footprint == reference->
footprint
1002 && unit.name == reference->
name && unit.sheet < reference->
sheet )
1008 for(
const auto& unit :
group.instances )
1010 if( unit.footprint.IsEmpty() || unit.footprint == reference->
footprint )
1014 error->SetErrorMessage( wxString::Format(
_(
"Different footprints assigned to %s and %s" ),
1015 reference->
name, unit.name ) );
1016 error->SetItems( std::vector<KIID>{ reference->
item, unit.item } );
1017 markers.Place( std::move( error ), unit.sheet, unit.position, reference->
sheet, unit.sheet );
1021 return markers.Count();
1031 if(
group.instances.empty() )
1034 const auto& base =
group.instances.front();
1035 std::set<int> placed;
1037 for(
const auto& instance :
group.instances )
1038 placed.insert( instance.unit );
1040 std::set<int> missing;
1041 std::set<int> power;
1042 std::set<int> input;
1043 std::set<int> bidirectional;
1045 for(
size_t i = 0; i <
group.units.size(); ++i )
1047 const int unit =
static_cast<int>( i ) + 1;
1049 if( placed.contains( unit ) )
1052 missing.insert( unit );
1054 if(
group.units[i].powerInput )
1055 power.insert( unit );
1057 if(
group.units[i].input )
1058 input.insert( unit );
1060 if(
group.units[i].bidirectional )
1061 bidirectional.insert( unit );
1065 [&](
const std::set<int>& units,
const wxString&
message,
int code )
1067 if( units.empty() || !
m_settings.IsTestEnabled( code ) )
1070 wxString names = wxS(
"[ " );
1073 for(
int unit : units )
1079 names += wxS(
", " );
1081 names +=
group.units[unit - 1].name;
1084 if( units.size() > 3 )
1085 names += wxS(
", ..." );
1087 names += wxS(
" ]" );
1088 markers.Report( code, { base.item }, base.sheet, base.position, ITEM_PATHS::MAIN,
1092 report( missing,
_(
"Symbol %s has unplaced units %s" ),
1094 report( power,
_(
"Symbol %s has input power pins in units %s that are not placed" ),
1096 report( input,
_(
"Symbol %s has input pins in units %s that are not placed" ),
1098 report( bidirectional,
_(
"Symbol %s has bidirectional pins in units %s that are not placed" ),
1102 return markers.Count();
1109 std::shared_ptr<NET_SETTINGS>& settings =
m_schematic->Project().GetProjectFile().NetSettings();
1110 wxString defaultNetclass = settings->GetDefaultNetclass()->GetName();
1119 ercItem->SetItems( std::vector<KIID>{ item } );
1120 ercItem->SetSheetSpecificPath( sheet );
1121 ercItem->SetItemsSheetPaths( sheet );
1122 ercItem->SetErrorMessage( wxString::Format(
_(
"Netclass %s is not defined" ), netclass ) );
1132 for(
const auto& reference :
m_schematic->Connectivity().Engine().NetclassReferences() )
1134 if( reference.name == defaultNetclass || settings->HasNetclass( reference.name ) )
1137 if(
const SCH_SHEET_PATH* sheet = sheets.Find( reference.sheet ) )
1138 logError( *sheet, reference.item, reference.position, reference.name );
1148 item->RunOnChildren(
1160 if( !netclass.empty()
1161 && !netclass.IsSameAs( defaultNetclass )
1162 && !settings->HasNetclass( netclass ) )
1164 logError( sheet, item->m_Uuid, item->GetPosition(), netclass );
1187 for(
const auto& conflict :
m_schematic->Connectivity().Engine().LabelWireConflicts() )
1189 std::vector<KIID> witnesses{ conflict.label };
1190 witnesses.insert( witnesses.end(), conflict.wires.begin(),
1191 conflict.wires.begin() + std::min<std::ptrdiff_t>( 3, std::ssize( conflict.wires ) ) );
1193 wxString::Format(
_(
"Label connects more than one wire at %d, %d" ),
1194 conflict.position.x, conflict.position.y ) );
1197 return markers.Count();
1202 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connMap;
1209 connMap[pt].emplace_back( label );
1212 for(
const std::pair<
const VECTOR2I, std::vector<SCH_ITEM*>>& pair : connMap )
1214 std::vector<SCH_ITEM*> lines;
1225 lines.emplace_back( line );
1228 if( lines.size() > 1 )
1235 ercItem->SetItems( pair.second.front(), lines[0], lines[1], lines[2] );
1236 ercItem->SetErrorMessage( wxString::Format(
_(
"Label connects more than one wire at %d, %d" ),
1237 pair.first.x, pair.first.y ) );
1238 ercItem->SetSheetSpecificPath( sheet );
1258 for(
const auto& junction :
m_schematic->Connectivity().Engine().FourWayJunctions() )
1261 junction.sheet, junction.position, ITEM_PATHS::NONE,
1262 wxString::Format(
_(
"Four items connected at %d, %d" ),
1263 junction.position.x, junction.position.y ) );
1266 return markers.Count();
1269 auto pinStackAlreadyRepresented =
1270 [](
SCH_PIN*
pin, std::vector<SCH_ITEM*>& collection ) ->
bool
1272 for(
SCH_ITEM*& item : collection )
1274 if( item->Type() ==
SCH_PIN_T && item->GetParentSymbol() ==
pin->GetParentSymbol() )
1288 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connMap;
1297 std::vector<SCH_ITEM*>& entry = connMap[
pin->GetPosition()];
1300 if( pinStackAlreadyRepresented(
pin, entry ) )
1303 entry.emplace_back(
pin );
1315 connMap[pt].emplace_back( line );
1318 for(
const std::pair<
const VECTOR2I, std::vector<SCH_ITEM*>>& pair : connMap )
1320 if( pair.second.size() >= 4 )
1326 ercItem->SetItems( pair.second[0], pair.second[1], pair.second[2], pair.second[3] );
1328 ercItem->SetErrorMessage( wxString::Format(
_(
"Four items connected at %d, %d" ),
1329 pair.first.x, pair.first.y ) );
1331 ercItem->SetSheetSpecificPath( sheet );
1354 for(
const auto& conflict :
m_schematic->Connectivity().Engine().NoConnectPinConflicts() )
1357 const auto witnessPins = std::min<std::ptrdiff_t>( 3, std::ssize( conflict.pins ) );
1358 std::vector<KIID> items( conflict.pins.begin(), conflict.pins.begin() + witnessPins );
1359 const auto witnessOthers = std::min<std::ptrdiff_t>( 4 - witnessPins, std::ssize( conflict.others ) );
1360 items.insert( items.end(), conflict.others.begin(), conflict.others.begin() + witnessOthers );
1362 _(
"Pin with 'no connection' type is connected" ) );
1365 return markers.Count();
1370 std::map<VECTOR2I, std::vector<SCH_ITEM*>> pinMap;
1375 if( pinMap.count( pt ) )
1376 pinMap[pt].emplace_back( aOther );
1386 pinMap[
pin->GetPosition()].emplace_back(
pin );
1399 addOther(
pin->GetPosition(),
pin );
1404 for(
const VECTOR2I& pt : item->GetConnectionPoints() )
1405 addOther( pt, item );
1409 for(
const std::pair<
const VECTOR2I, std::vector<SCH_ITEM*>>& pair : pinMap )
1411 if( pair.second.size() > 1 )
1415 for(
SCH_ITEM* item : pair.second )
1439 ercItem->SetItems( pair.second[0], pair.second[1],
1440 pair.second.size() > 2 ? pair.second[2] :
nullptr,
1441 pair.second.size() > 3 ? pair.second[3] :
nullptr );
1442 ercItem->SetErrorMessage(
_(
"Pin with 'no connection' type is connected" ) );
1443 ercItem->SetSheetSpecificPath( sheet );
1469 std::map<wxString, const SCH_CONNECTIVITY::ERC_PIN_NET*> byName;
1470 std::set<wxString> powerDriven;
1472 ERC_MARKER_PLACER markers( aSchematic );
1475 [](
const PIN& a,
const PIN& b )
1477 int order =
StrNumCmp( a.reference, b.reference );
1480 order =
StrNumCmp( a.pin.number, b.pin.number );
1486 if( a.sheet != b.sheet )
1487 return a.sheet < b.sheet;
1489 return a.pin.id < b.pin.id;
1492 const auto mismatch =
1493 [&](
const PIN& a,
const PIN& b )
1500 const auto reportPair =
1503 std::shared_ptr<ERC_ITEM> item =
ERC_ITEM::Create( ercErrorCode( pinError ) );
1505 item->SetItems( std::vector<KIID>{ a.pin.id, b.pin.id } );
1509 item->SetErrorMessage( wxString::Format(
_(
"Pins of type %s and %s are connected" ),
1515 item->SetErrorMessage( wxString::Format(
_(
"Pins of type %s and %s are connected via "
1521 markers.Place( std::move( item ), a.sheet, a.pin.position, a.sheet, b.sheet );
1524 const auto passiveOrNic =
1539 for(
auto& net : nets )
1541 std::sort( net.pins.begin(), net.pins.end(), less );
1542 byName.emplace( net.name, &net );
1544 if( net.powerDriven )
1545 powerDriven.insert( net.name );
1548 for(
const auto& net : nets )
1550 const std::vector<PIN>& pins = net.pins;
1551 const bool powerNet = std::ranges::any_of( pins,
1556 const PIN* preferred =
nullptr;
1557 std::vector<const PIN*> needsDriver;
1558 std::vector<const PIN*> nonPowerInputs;
1559 std::vector<const PIN*> powerInputs;
1560 std::vector<MISMATCH> mismatches;
1561 std::map<size_t, int> weights;
1562 bool hasDriver = net.powerDriven;
1564 for(
size_t i = 0; i < pins.size(); ++i )
1566 const PIN&
pin = pins[i];
1572 needsDriver.push_back( &
pin );
1574 if( !
pin.pin.globalPower && !
pin.pin.localPower )
1575 nonPowerInputs.push_back( &
pin );
1578 powerInputs.push_back( &
pin );
1581 || ( preferred->pin.invisible && !
pin.pin.invisible )
1589 for(
size_t j = i + 1; j < pins.size(); ++j )
1591 const PIN& other = pins[j];
1592 const bool stacked =
pin.sheet == other.sheet
1593 &&
pin.owner == other.owner
1594 &&
pin.pin.position == other.pin.position
1595 &&
pin.pin.name == other.pin.name
1596 && (
pin.pin.type == other.pin.type
1597 || passiveOrNic(
pin.pin.type )
1598 || passiveOrNic( other.pin.type ) );
1608 mismatches.push_back( { i, j, error } );
1624 std::vector<std::pair<int, size_t>> worst;
1626 for(
const auto& [
index, weight] : weights )
1627 worst.emplace_back( weight,
index );
1629 std::stable_sort( worst.begin(), worst.end(),
1630 [](
const auto& a,
const auto& b )
1632 return a.first > b.first;
1635 for(
const auto& [weight,
index] : worst )
1638 const PIN* nearest =
nullptr;
1640 std::optional<double> nearestDistance;
1642 std::erase_if( mismatches,
1643 [&](
const MISMATCH& candidate )
1645 if( candidate.first !=
index && candidate.second !=
index )
1648 const PIN& other = pins[candidate.first ==
index ? candidate.second : candidate.first];
1651 if( other.sheet !=
pin.sheet )
1653 if( !nearestDistance )
1656 error = candidate.error;
1659 else if(
const double distance =
pin.pin.position.Distance( other.pin.position );
1660 !nearestDistance ||
distance < *nearestDistance )
1664 error = candidate.error;
1671 reportPair(
pin, *nearest, error, wxString() );
1674 if( !preferred || hasDriver || net.noConnect )
1677 bool chainDriver =
false;
1681 for(
const auto&
chain : chains )
1683 if( !
chain || !
chain->GetNets().contains( net.name ) )
1686 chainDriver = std::ranges::any_of(
chain->GetNets(),
1687 [&](
const wxString&
name )
1689 return name != net.name && powerDriven.contains( name );
1700 if( aShowAllErrors )
1702 const auto& selected = powerNet && !powerInputs.empty() ? powerInputs
1703 : !nonPowerInputs.empty() ? nonPowerInputs
1706 for(
const PIN*
pin : selected )
1707 markers.Report( code, {
pin->pin.id },
pin->sheet,
pin->pin.position, ITEM_PATHS::MAIN );
1711 const PIN&
pin = powerNet && !powerInputs.empty() ? *powerInputs.front()
1713 markers.Report( code, {
pin.pin.id },
pin.sheet,
pin.pin.position, ITEM_PATHS::MAIN );
1717 for(
const std::unique_ptr<SCH_NETCHAIN>&
chain : chains )
1725 const wxString* net;
1727 std::vector<CHAIN_PIN> pins;
1729 for(
const wxString&
name :
chain->GetNets() )
1731 const auto net = byName.find(
name );
1733 if( net == byName.end() )
1736 for(
const PIN&
pin : net->second->pins )
1737 pins.push_back( { &
pin, &net->first } );
1740 std::sort( pins.begin(), pins.end(),
1741 [&](
const CHAIN_PIN& a,
const CHAIN_PIN& b )
1743 return less( *a.pin, *b.pin );
1746 for(
size_t i = 0; i < pins.size(); ++i )
1748 for(
size_t j = i + 1; j < pins.size(); ++j )
1750 if( *pins[i].net == *pins[j].net )
1754 reportPair( *pins[i].
pin, *pins[j].
pin, error,
chain->GetName() );
1759 return markers.Count();
1770 std::set<wxString> powerDrivenNets;
1772 if( !
m_schematic->ConnectionGraph()->GetCommittedNetChains().empty() )
1774 for(
const auto& [key, subgraphs] :
m_nets )
1778 for(
SCH_ITEM* item : subgraph->GetItems() )
1786 powerDrivenNets.insert( key.Name );
1795 std::unordered_map<wxString, std::vector<ERC_SCH_PIN_CONTEXT>> netToPins;
1799 using iterator_t = std::vector<ERC_SCH_PIN_CONTEXT>::iterator;
1800 std::vector<ERC_SCH_PIN_CONTEXT> pins;
1801 std::unordered_map<EDA_ITEM*, SCH_SCREEN*> pinToScreenMap;
1802 bool has_noconnect =
false;
1807 has_noconnect =
true;
1813 pins.emplace_back(
static_cast<SCH_PIN*
>( item ), subgraph->
GetSheet() );
1814 netToPins[ net.first.Name ].emplace_back(
static_cast<SCH_PIN*
>( item ), subgraph->
GetSheet() );
1820 std::sort( pins.begin(), pins.end(),
1823 int ret = StrNumCmp( lhs.Pin()->GetParentSymbol()->GetRef( &lhs.Sheet() ),
1824 rhs.Pin()->GetParentSymbol()->GetRef( &rhs.Sheet() ) );
1827 ret = StrNumCmp( lhs.Pin()->GetNumber(), rhs.Pin()->GetNumber() );
1829 return ret != 0 ? ret < 0 : lhs < rhs;
1834 bool hasDriver =
false;
1835 std::vector<ERC_SCH_PIN_CONTEXT*> pinsNeedingDrivers;
1836 std::vector<ERC_SCH_PIN_CONTEXT*> nonPowerPinsNeedingDrivers;
1837 std::vector<ERC_SCH_PIN_CONTEXT*> powerInPinsNeedingDrivers;
1842 bool ispowerNet =
false;
1853 std::vector<std::tuple<iterator_t, iterator_t, PIN_ERROR>> pin_mismatches;
1854 std::map<iterator_t, int> pin_mismatch_counts;
1856 for(
auto refIt = pins.begin(); refIt != pins.end(); ++refIt )
1866 pinsNeedingDrivers.push_back( &refPin );
1869 nonPowerPinsNeedingDrivers.push_back( &refPin );
1872 powerInPinsNeedingDrivers.push_back( &refPin );
1874 if( !needsDriver.
Pin()
1879 needsDriver = refPin;
1880 needsDriverType = needsDriver.
Pin()->
GetType();
1889 for(
auto testIt = refIt + 1; testIt != pins.end(); ++testIt )
1910 pin_mismatches.emplace_back( std::tuple<iterator_t, iterator_t,
1911 PIN_ERROR>{ refIt, testIt, pinError } );
1915 pin_mismatch_counts[refIt] =
m_settings.GetPinTypeWeight( refIt->Pin()->GetType() );
1916 pin_mismatch_counts[testIt] =
m_settings.GetPinTypeWeight( testIt->Pin()->GetType() );
1920 if( !pin_mismatch_counts.contains( testIt ) )
1921 pin_mismatch_counts.emplace( testIt, 1 );
1923 pin_mismatch_counts[testIt]++;
1925 if( !pin_mismatch_counts.contains( refIt ) )
1926 pin_mismatch_counts.emplace( refIt, 1 );
1928 pin_mismatch_counts[refIt]++;
1934 std::multimap<size_t, iterator_t, std::greater<size_t>> pins_dsc;
1936 std::transform( pin_mismatch_counts.begin(), pin_mismatch_counts.end(),
1937 std::inserter( pins_dsc, pins_dsc.begin() ),
1940 return std::pair<size_t, iterator_t>( p.second, p.first );
1943 for(
const auto& [amount, pinItBind] : pins_dsc )
1945 auto& pinIt = pinItBind;
1947 if( pin_mismatches.empty() )
1953 iterator_t nearest_pin = pins.end();
1954 double smallest_distance = std::numeric_limits<double>::infinity();
1959 [&](
const auto& tuple )
1963 if( pinIt == std::get<0>( tuple ) )
1964 other = std::get<1>( tuple );
1965 else if( pinIt == std::get<1>( tuple ) )
1966 other = std::get<0>( tuple );
1970 if( ( *pinIt ).Sheet().Cmp( ( *other ).Sheet() ) != 0 )
1972 if( std::isinf( smallest_distance ) )
1974 nearest_pin = other;
1975 pinError = std::get<2>( tuple );
1982 if( std::isinf( smallest_distance ) ||
distance < smallest_distance )
1985 nearest_pin = other;
1986 pinError = std::get<2>( tuple );
1993 if( nearest_pin != pins.end() )
1995 SCH_PIN* other_pin = nearest_pin->Pin();
1996 std::shared_ptr<ERC_ITEM> ercItem =
ERC_ITEM::Create( ercErrorCode( pinError ) );
1998 ercItem->SetItems(
pin, other_pin );
1999 ercItem->SetSheetSpecificPath( pinIt->Sheet() );
2000 ercItem->SetItemsSheetPaths( pinIt->Sheet(), nearest_pin->Sheet() );
2002 ercItem->SetErrorMessage( wxString::Format(
_(
"Pins of type %s and %s are connected" ),
2007 pinToScreenMap[
pin]->Append( marker );
2012 if( needsDriver.
Pin() && !hasDriver && !has_noconnect )
2020 bool suppressForNetChainDriver =
false;
2024 const wxString& thisNetName = net.first.Name;
2025 const auto& netChains =
m_schematic->ConnectionGraph()->GetCommittedNetChains();
2027 for(
const auto& sig : netChains )
2032 const auto& sigNets = sig->GetNets();
2033 bool containsThisNet = std::find( sigNets.begin(), sigNets.end(), thisNetName ) != sigNets.end();
2035 if( !containsThisNet )
2039 for(
const wxString& otherNet : sigNets )
2041 if( otherNet == thisNetName )
2044 if( powerDrivenNets.contains( otherNet ) )
2046 suppressForNetChainDriver =
true;
2055 if( !suppressForNetChainDriver &&
m_settings.IsTestEnabled( err_code ) )
2057 std::vector<ERC_SCH_PIN_CONTEXT*> pinsToMark;
2066 if( ispowerNet && !powerInPinsNeedingDrivers.empty() )
2067 pinsToMark = powerInPinsNeedingDrivers;
2068 else if( !nonPowerPinsNeedingDrivers.empty() )
2069 pinsToMark = nonPowerPinsNeedingDrivers;
2071 pinsToMark = pinsNeedingDrivers;
2075 if( ispowerNet && !powerInPinsNeedingDrivers.empty() )
2076 pinsToMark.push_back( powerInPinsNeedingDrivers.front() );
2078 pinsToMark.push_back( &needsDriver );
2085 ercItem->SetItems( pinCtx->Pin() );
2086 ercItem->SetSheetSpecificPath( pinCtx->Sheet() );
2087 ercItem->SetItemsSheetPaths( pinCtx->Sheet() );
2090 pinToScreenMap[pinCtx->Pin()]->Append( marker );
2105 auto& netChains =
m_schematic->ConnectionGraph()->GetCommittedNetChains();
2106 wxLogTrace(
traceSchNetChain,
"ERC TestPinToPin: cross-chain phase start chains=%zu",
2109 for(
const auto& sig : netChains )
2114 const wxString chainName = sig->GetName();
2115 const auto& sigNets = sig->GetNets();
2121 const wxString* net;
2123 std::vector<CHAIN_PIN> netChainPins;
2124 netChainPins.reserve( sigNets.size() * 4 );
2126 for(
const wxString& n : sigNets )
2128 auto it = netToPins.find( n );
2129 if( it != netToPins.end() )
2132 netChainPins.push_back( { context, &it->first } );
2136 if( netChainPins.size() < 2 )
2140 "ERC TestPinToPin: chain '%s' nets=%zu collectedPins=%zu",
2141 TO_UTF8( chainName ), sigNets.size(), netChainPins.size() );
2144 std::sort( netChainPins.begin(), netChainPins.end(),
2145 [](
const CHAIN_PIN&
left,
const CHAIN_PIN&
right )
2147 const auto& lhs = left.context;
2148 const auto& rhs = right.context;
2149 int ret = StrNumCmp( lhs.Pin()->GetParentSymbol()->GetRef( &lhs.Sheet() ),
2150 rhs.Pin()->GetParentSymbol()->GetRef( &rhs.Sheet() ) );
2152 ret = StrNumCmp( lhs.Pin()->GetNumber(), rhs.Pin()->GetNumber() );
2153 return ret != 0 ? ret < 0 : lhs < rhs;
2156 for(
size_t i = 0; i < netChainPins.size(); ++i )
2158 const auto& aContext = netChainPins[i].context;
2159 SCH_PIN* aPin = aContext.Pin();
2161 const wxString& aNet = *netChainPins[i].net;
2163 for(
size_t j = i + 1; j < netChainPins.size(); ++j )
2165 const auto& bContext = netChainPins[j].context;
2166 SCH_PIN* bPin = bContext.Pin();
2167 const wxString& bNet = *netChainPins[j].net;
2177 std::shared_ptr<ERC_ITEM> ercItem =
ERC_ITEM::Create( ercErrorCode( pinError ) );
2179 ercItem->SetItems( aPin, bPin );
2180 ercItem->SetSheetSpecificPath( aContext.Sheet() );
2181 ercItem->SetItemsSheetPaths( aContext.Sheet(), bContext.Sheet() );
2182 ercItem->SetErrorMessage( wxString::Format(
_(
"Pins of type %s and %s are connected via "
2188 aContext.Sheet().LastScreen()->Append( marker );
2208 for(
const auto& conflict :
m_schematic->Connectivity().Engine().MultiUnitPinConflicts() )
2211 ercItem->SetErrorMessage( wxString::Format(
_(
"Pin %s is connected to both %s and %s" ),
2214 conflict.firstNet ) );
2215 ercItem->SetItems( std::vector<KIID>{ conflict.other.item, conflict.first.item } );
2216 markers.Place( std::move( ercItem ), conflict.other.sheet, conflict.other.position, conflict.other.sheet,
2217 conflict.first.sheet );
2220 return markers.Count();
2230 std::unordered_map<wxString, std::vector<PIN_ON_NET>> pinToNetMap;
2234 const wxString& netName = net.first.Name;
2245 if( !
pin->GetParentSymbol()->IsMultiUnit() )
2248 wxString
name =
pin->GetParentSymbol()->GetRef( &sheet ) +
":" +
pin->GetShownNumber();
2250 pinToNetMap[
name].push_back( { netName,
pin, sheet } );
2259 std::vector<wxString> conflicted;
2261 for(
const auto& [
name, pins] : pinToNetMap )
2263 for(
const PIN_ON_NET& candidate : pins )
2265 if( candidate.m_netName != pins.front().m_netName )
2267 conflicted.push_back(
name );
2273 std::sort( conflicted.begin(), conflicted.end() );
2275 for(
const wxString&
name : conflicted )
2277 std::vector<PIN_ON_NET> pins = pinToNetMap[
name];
2279 std::sort( pins.begin(), pins.end(),
2280 [](
const PIN_ON_NET& a,
const PIN_ON_NET& b )
2282 if( a.m_netName != b.m_netName )
2283 return a.m_netName < b.m_netName;
2285 return a.m_pin->m_Uuid < b.m_pin->m_Uuid;
2288 const PIN_ON_NET& first = pins.front();
2290 for(
const PIN_ON_NET& other : pins )
2292 if( other.m_netName == first.m_netName )
2297 ercItem->SetErrorMessage( wxString::Format(
_(
"Pin %s is connected to both %s and %s" ),
2298 other.m_pin->GetShownNumber(),
2300 first.m_netName ) );
2302 ercItem->SetItems( other.m_pin, first.m_pin );
2303 ercItem->SetSheetSpecificPath( other.m_sheet );
2304 ercItem->SetItemsSheetPaths( other.m_sheet, first.m_sheet );
2307 other.m_sheet.LastScreen()->Append( marker );
2321 ERC_MARKER_PLACER markers( aSchematic );
2328 ercItem->SetItems(
pin.item );
2329 markers.Place( std::move( ercItem ),
pin.sheet,
pin.position, ITEM_PATHS::MAIN );
2338 ercItem->SetItems( conflict.first, conflict.second );
2339 ercItem->SetErrorMessage( wxString::Format(
_(
"Both %s and %s are attached to the same items; "
2340 "%s will be used in the netlist" ),
2342 conflict.secondName,
2343 conflict.firstName ) );
2344 markers.Place( std::move( ercItem ), conflict.sheet, conflict.position, ITEM_PATHS::BOTH );
2353 ercItem->SetItems( endpoint.item );
2354 ercItem->SetErrorMessage( endpoint.busEntry ?
_(
"Unconnected wire to bus entry" )
2355 :
_(
"Unconnected wire endpoint" ) );
2356 markers.Place( std::move( ercItem ), endpoint.sheet, endpoint.position );
2365 ercItem->SetItems( conflict.net, conflict.bus );
2366 markers.Place( std::move( ercItem ), conflict.sheet, conflict.position );
2375 ercItem->SetItems( conflict.canonical, conflict.other );
2377 if( conflict.mixedShapes )
2378 ercItem->SetErrorMessage(
_(
"Bus vector and bus group are graphically connected" ) );
2380 markers.Place( std::move( ercItem ), conflict.sheet, conflict.position );
2389 ercItem->SetItems( conflict.entry, conflict.bus );
2390 ercItem->SetErrorMessage( wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
2391 " member of that bus" ),
2394 markers.Place( std::move( ercItem ), conflict.sheet, conflict.position );
2407 markers.Report( code,
2408 diagnostic.pin ==
niluuid ? std::vector<KIID>{ diagnostic.flag }
2409 : std::vector<KIID>{ diagnostic.pin, diagnostic.flag },
2410 diagnostic.sheet, diagnostic.position, ITEM_PATHS::MAIN );
2426 const bool mismatch = error.kind == ERROR_KIND::MISSING_LABEL || error.kind == ERROR_KIND::MISSING_PIN;
2433 ercItem->SetItems( std::vector<KIID>{ error.item } );
2436 switch( error.kind )
2438 case ERROR_KIND::ROOT_LABEL:
2439 ercItem->SetErrorMessage( wxString::Format(
_(
"Hierarchical label '%s' in root sheet cannot be "
2440 "connected to non-existent parent sheet" ),
2444 case ERROR_KIND::MISSING_LABEL:
2445 ercItem->SetErrorMessage( wxString::Format(
_(
"Sheet pin %s has no matching hierarchical label "
2446 "inside the sheet" ),
2450 case ERROR_KIND::MISSING_PIN:
2451 ercItem->SetErrorMessage( wxString::Format(
_(
"Hierarchical label %s has no matching sheet pin "
2452 "in the parent sheet" ),
2456 case ERROR_KIND::DANGLING_PIN:
2461 const bool rootLabel = error.kind == ERROR_KIND::ROOT_LABEL;
2462 markers.Place( std::move( ercItem ), error.sheet, error.position,
2463 rootLabel ? ITEM_PATHS::NONE : ITEM_PATHS::MAIN, !rootLabel );
2474 markers.Report( code, { label.item }, label.sheet, label.position );
2499 return markers.Count();
2523 std::vector<SCH_PIN*> pins = symbol->
GetPins( &sheet );
2525 std::map<wxString, std::vector<std::pair<SCH_PIN*, wxString>>> pinsByNumber;
2532 netName =
pin->GetConnectionName( &sheet ).value_or( wxString() );
2534 netName = conn->GetNetName();
2536 pinsByNumber[
pin->GetNumber()].emplace_back(
pin, netName );
2539 for(
const auto& [pinNumber, pinNetPairs] : pinsByNumber )
2541 if( pinNetPairs.size() < 2 )
2544 wxString firstNet = pinNetPairs[0].second;
2545 bool hasDifferentNets =
false;
2546 SCH_PIN* conflictPin =
nullptr;
2548 for(
size_t i = 1; i < pinNetPairs.size(); i++ )
2550 if( pinNetPairs[i].second != firstNet )
2552 hasDifferentNets =
true;
2553 conflictPin = pinNetPairs[i].first;
2558 if( hasDifferentNets )
2563 msg.Printf(
_(
"Pin %s on symbol '%s' is connected to different nets: %s and %s" ),
2565 symbol->
GetRef( &sheet ),
2566 firstNet.IsEmpty() ?
_(
"<no net>" ) : firstNet,
2567 pinNetPairs[1].second.IsEmpty() ?
_(
"<no net>" ) : pinNetPairs[1].second );
2569 ercItem->SetErrorMessage( msg );
2570 ercItem->SetItems( pinNetPairs[0].first, conflictPin );
2571 ercItem->SetSheetSpecificPath( sheet );
2572 ercItem->SetItemsSheetPaths( sheet, sheet );
2574 SCH_MARKER* marker =
new SCH_MARKER( std::move( ercItem ), pinNetPairs[0].first->GetPosition() );
2575 screen->
Append( marker );
2594 for(
const auto& mismatch :
m_schematic->Connectivity().Engine().GroundPinErrors() )
2598 wxString::Format(
_(
"Pin %s not connected to ground net" ), mismatch.name ) );
2601 return markers.Count();
2605 [](
const wxString& txt )
2607 wxString upper = txt.Upper();
2609 return upper.Contains( wxT(
"GND" ) )
2610 || upper == wxT(
"EARTH" )
2611 || upper.StartsWith( wxT(
"EARTH_" ) )
2612 || upper == wxT(
"VSS" )
2613 || upper == wxT(
"VSSA" );
2623 bool hasGroundNet =
false;
2624 std::vector<SCH_PIN*> mismatched;
2636 const wxString net = conn ? conn->
Name(
true ) : wxString();
2637 const bool netIsGround = isGround( net );
2640 hasGroundNet =
true;
2642 if( isGround(
pin->GetShownName() ) && !netIsGround )
2643 mismatched.push_back(
pin );
2652 ercItem->SetErrorMessage( wxString::Format(
_(
"Pin %s not connected to ground net" ),
2653 pin->GetShownName() ) );
2654 ercItem->SetItems(
pin );
2655 ercItem->SetSheetSpecificPath( sheet );
2656 ercItem->SetItemsSheetPaths( sheet );
2659 screen->
Append( marker );
2675 m_schematic->Connectivity().Engine().InvalidPinNotation() );
2691 pin->GetStackedPinNumbers( &valid );
2696 ercItem->SetItems(
pin );
2697 ercItem->SetSheetSpecificPath( sheet );
2698 ercItem->SetItemsSheetPaths( sheet );
2701 screen->
Append( marker );
2715 std::map<wxString, NAMED_ITEM> globalLabels;
2716 std::map<wxString, NAMED_ITEM> localLabels;
2723 auto& labels = item.global ? globalLabels : localLabels;
2724 auto found = labels.find( item.name );
2727 if( found == labels.end()
2728 || item.item < found->second.item
2729 || ( item.item == found->second.item && item.sheet < found->second.sheet ) )
2731 labels[item.name] = item;
2737 for(
const auto& [
name, global] : globalLabels )
2739 const auto local = localLabels.find(
name );
2741 if( local == localLabels.end() )
2746 reportNameConflict( markers,
m_settings, code, global, local->second );
2749 return markers.Count();
2756 std::map<wxString, std::vector<NAMED_ITEM>> generalMap;
2758 auto normalizeLabel =
2759 [](
const wxString& aLabel )
2761 wxString stripped = aLabel.Strip( wxString::leading ).Strip( wxString::trailing );
2768 if( prefix == wxT(
"+" ) )
2769 prefix = wxEmptyString;
2772 units.Replace( wxS(
"µ" ),
'u' );
2773 units.Replace( wxS(
"μ" ),
'u' );
2775 return prefix.Lower() + value.Lower() + units.Lower();
2779 generalMap[normalizeLabel( item.name )].push_back( item );
2783 for(
auto& [
name, entries] : generalMap )
2788 if( a.sheet != b.sheet )
2789 return a.sheet.AsString() < b.sheet.AsString();
2791 return a.item < b.item;
2795 for(
size_t ii = 0; ii < entries.size(); ++ii )
2797 for(
size_t jj = ii + 1; jj < entries.size(); ++jj )
2816 reportNameConflict( markers,
m_settings, code, a, b );
2821 return markers.Count();
2835 struct LIBRARY_ISSUE
2844 std::vector<LIBRARY_ISSUE> issues;
2848 if( !optRow || ( *optRow )->Disabled() )
2853 wxString::Format(
_(
"The current configuration does not include the "
2854 "symbol library '%s'" ),
2867 wxCHECK2( uri.has_value(), uri = wxEmptyString );
2869 wxString::Format(
_(
"The symbol library '%s' was not found at '%s'" ),
2885 wxString::Format(
_(
"Symbol '%s' not found in symbol library '%s'" ),
2897 std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->
Flatten();
2898 const int flags =
m_schematic->Settings().SymbolCompareFlags();
2899 bool mismatch =
false;
2911 wxCHECK( aSymbol && aSymbol->GetLibSymbolRef(), issues );
2913 LIB_SYMBOL* embedded = aSymbol->GetLibSymbolRef().get();
2914 std::vector<wxString> messages;
2923 mismatch = messages.empty() && flattenedSymbol->Compare( *embedded, flags ) != 0;
2929 wxString::Format(
_(
"Symbol '%s' doesn't match copy in library '%s'" ),
2939 std::map<std::pair<const SCH_SCREEN*, KIID>, std::vector<LIBRARY_ISSUE>> results;
2944 std::vector<SCH_CONNECTIVITY::LIBRARY_SYMBOL_FACT> sources;
2947 std::vector<const SCH_SYMBOL*> symbols;
2951 sources =
m_schematic->Connectivity().Engine().LibrarySymbols(
path.PathRef() );
2964 symbols.push_back( symbol );
2968 std::vector<SCH_MARKER*> markers;
2970 for(
size_t ii = 0; ii < sources.size(); ++ii )
2972 const auto&
source = sources[ii];
2974 if( !
source.hasEmbeddedSymbol )
2979 if(
result == results.end() )
2981 const SCH_SYMBOL* symbol = captured ? nullptr : symbols[ii];
2982 result = results.emplace( std::make_pair( screen,
source.id ), check(
source, symbol ) ).first;
2985 for(
const LIBRARY_ISSUE& issue :
result->second )
2988 ercItem->SetItems( std::vector<KIID>{
source.id } );
2989 ercItem->SetSheetSpecificPath(
path );
2990 ercItem->SetItemsSheetPaths(
path );
2991 ercItem->SetErrorMessage( issue.message );
2992 markers.emplace_back(
new SCH_MARKER( std::move( ercItem ),
source.position ) );
2998 screen->
Append( marker );
3011 if( std::optional<LIBRARY_MANAGER_ADAPTER*> adapter =
3014 ( *adapter )->BlockUntilLoaded();
3017 typedef int (*TESTER_FN_PTR)(
const wxString&,
PROJECT* );
3024 if(
source.footprint.IsEmpty() )
3032 msg.Printf(
_(
"'%s' is not a valid footprint identifier" ),
source.footprint );
3038 const int ret = linkTester(
source.footprint, aProject );
3042 msg.Printf(
_(
"The current configuration does not include the footprint library '%s'" ),
3047 msg.Printf(
_(
"The footprint library '%s' is not enabled in the current configuration" ),
3052 msg.Printf(
_(
"Footprint '%s' not found in library '%s'" ), fpName, libName );
3064 return markers.Count();
3075 if(
source.filters.empty() )
3078 const wxString lowerId =
source.footprint.Lower();
3082 if( footprint.
Parse( lowerId ) > 0 )
3086 const bool found = std::ranges::any_of(
source.filters,
3087 [&](
const wxString&
filter )
3090 return filter.Contains( wxS(
":" ) ) ? lowerId.Matches( filter.Lower() )
3091 : lowerItemName.Matches( filter.Lower() );
3098 wxString::Format(
_(
"Assigned footprint (%s) doesn't match footprint filters (%s)" ),
3102 return markers.Count();
3115 const int gridSize =
m_schematic->Settings().m_ConnectionGridSize;
3120 std::vector<SCH_MARKER*> markers;
3122 for(
SCH_ITEM* item : screen->Items() )
3124 if( item->Type() ==
SCH_LINE_T && item->IsConnectable() )
3132 ercItem->SetItems( line );
3140 ercItem->SetItems( line );
3151 if( ( point.x % gridSize ) != 0
3152 || ( point.y % gridSize ) != 0 )
3155 ercItem->SetItems( entry );
3157 markers.emplace_back(
new SCH_MARKER( std::move( ercItem ), point ) );
3172 if( ( pinPos.
x % gridSize ) != 0 || ( pinPos.
y % gridSize ) != 0 )
3175 ercItem->SetItems(
pin );
3177 markers.emplace_back(
new SCH_MARKER( std::move( ercItem ), pinPos ) );
3186 screen->Append( marker );
3200 wxString variant =
m_schematic->GetCurrentVariant();
3207 std::vector<SCH_MARKER*> markers;
3209 for(
const auto&
source : sources )
3216 wxString msg =
reporter.GetMessages();
3222 ercItem->SetErrorMessage( msg );
3223 ercItem->SetItems(
source.id );
3224 ercItem->SetSheetSpecificPath( sheet );
3225 ercItem->SetItemsSheetPaths( sheet );
3227 markers.emplace_back(
new SCH_MARKER( std::move( ercItem ),
source.position ) );
3254 std::map<wxString, std::unique_ptr<LIB_SYMBOL>> flatAltCache;
3263 std::vector<SCH_MARKER*> markers;
3264 std::vector<SCH_CONNECTIVITY::VARIANT_SYMBOL_FACT> sources;
3265 std::vector<SCH_CONNECTIVITY::LIBRARY_SYMBOL_FACT> libraries;
3271 if( sources.empty() )
3286 auto& base = libraries.emplace_back();
3291 base.id = symbol->
m_Uuid;
3294 sources.push_back( std::move( *
source ) );
3297 std::sort( libraries.begin(), libraries.end(),
3298 [](
const auto& a,
const auto& b )
3304 for(
const auto&
source : sources )
3306 const auto base = std::lower_bound( libraries.begin(), libraries.end(),
source.id,
3307 [](
const auto& a,
const KIID&
id )
3312 if( base == libraries.end() || base->id !=
source.id )
3316 [&](
int aErrorCode,
const wxString& aMessage )
3320 ercItem->SetItems( std::vector<KIID>{
source.id } );
3321 ercItem->SetSheetSpecificPath( sheet );
3322 ercItem->SetItemsSheetPaths( sheet );
3323 ercItem->SetErrorMessage( aMessage );
3325 markers.emplace_back(
new SCH_MARKER( std::move( ercItem ), base->position ) );
3329 for(
const auto& [variantName, libId] :
source.overrides )
3331 wxString libIdStr = libId.Format();
3334 if( libId == base->library )
3337 auto cacheIt = flatAltCache.find( libIdStr );
3339 if( cacheIt == flatAltCache.end() )
3341 std::unique_ptr<LIB_SYMBOL> flatAlt;
3346 flatAlt = altSymbol->Flatten();
3352 cacheIt = flatAltCache.emplace( libIdStr, std::move( flatAlt ) ).first;
3355 const LIB_SYMBOL* flatAlt = cacheIt->second.get();
3362 wxString::Format(
_(
"Variant '%s': symbol '%s' not found in libraries" ),
3363 variantName, libIdStr ) );
3372 if( !base->hasEmbeddedSymbol )
3375 std::vector<VARIANT_COMPAT_RESULT> issues =
3381 wxString::Format(
_(
"Variant '%s', alternate '%s': %s" ),
3382 variantName, libIdStr, issue.detail ) );
3388 screen->
Append( marker );
3418 m_schematic->RebuildConnectivity(
nullptr, aProgressReporter );
3437 if( aProgressReporter )
3438 aProgressReporter->
AdvancePhase(
_(
"Checking sheet names..." ) );
3447 if( aProgressReporter )
3448 aProgressReporter->
AdvancePhase(
_(
"Checking pin maps..." ) );
3453 if( aProgressReporter )
3454 aProgressReporter->
AdvancePhase(
_(
"Checking conflicts..." ) );
3461 if( aProgressReporter )
3462 aProgressReporter->
AdvancePhase(
_(
"Checking units..." ) );
3467 if( aProgressReporter )
3468 aProgressReporter->
AdvancePhase(
_(
"Checking footprints..." ) );
3481 if( aProgressReporter )
3511 if( aProgressReporter )
3512 aProgressReporter->
AdvancePhase(
_(
"Checking similar labels..." ) );
3520 if( aProgressReporter )
3521 aProgressReporter->
AdvancePhase(
_(
"Checking local and global labels..." ) );
3528 if( aProgressReporter )
3529 aProgressReporter->
AdvancePhase(
_(
"Checking for unresolved variables..." ) );
3536 if( aProgressReporter )
3537 aProgressReporter->
AdvancePhase(
_(
"Checking field names..." ) );
3544 if( aProgressReporter )
3545 aProgressReporter->
AdvancePhase(
_(
"Checking for empty power symbol values..." ) );
3552 if( aProgressReporter )
3553 aProgressReporter->
AdvancePhase(
_(
"Checking for empty label names..." ) );
3560 if( aProgressReporter )
3561 aProgressReporter->
AdvancePhase(
_(
"Checking SPICE models..." ) );
3568 if( aProgressReporter )
3569 aProgressReporter->
AdvancePhase(
_(
"Checking no connect pins for connections..." ) );
3577 if( aProgressReporter )
3578 aProgressReporter->
AdvancePhase(
_(
"Checking for library symbol issues..." ) );
3585 if( aProgressReporter )
3586 aProgressReporter->
AdvancePhase(
_(
"Checking for footprint link issues..." ) );
3593 if( aProgressReporter )
3594 aProgressReporter->
AdvancePhase(
_(
"Checking footprint assignments against footprint filters..." ) );
3601 if( aProgressReporter )
3602 aProgressReporter->
AdvancePhase(
_(
"Checking for off grid pins and wires..." ) );
3609 if( aProgressReporter )
3610 aProgressReporter->
AdvancePhase(
_(
"Checking for four way junctions..." ) );
3617 if( aProgressReporter )
3618 aProgressReporter->
AdvancePhase(
_(
"Checking for labels on more than one wire..." ) );
3625 if( aProgressReporter )
3626 aProgressReporter->
AdvancePhase(
_(
"Checking for undefined netclasses..." ) );
3634 if( aProgressReporter )
3635 aProgressReporter->
AdvancePhase(
_(
"Checking variant symbols..." ) );
constexpr EDA_IU_SCALE schIUScale
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const NET_MAP & GetNetMap() const
A subgraph is a set of items that are electrically connected on a single sheet.
const std::set< SCH_ITEM * > & GetItems() const
Provide a read-only reference to the items in the subgraph.
const SCH_ITEM * GetNoConnect() const
const SCH_SHEET_PATH & GetSheet() const
Base class to handle basic graphic items.
Store the list of graphic items: rect, lines, polygons and texts to draw/plot the title block and fra...
DS_DRAW_ITEM_BASE * GetFirst()
void BuildDrawItemsList(const PAGE_INFO &aPageInfo, const TITLE_BLOCK &aTitleBlock)
Drawing or plot the drawing sheet.
void SetFileName(const wxString &aFileName)
Set the filename to draw/plot.
void SetSheetName(const wxString &aSheetName)
Set the sheet name to draw/plot.
void SetSheetLayer(const wxString &aSheetLayer)
Set the sheet layer to draw/plot.
void SetSheetCount(int aSheetCount)
Set the value of the count of sheets, for basic inscriptions.
void SetPageNumber(const wxString &aPageNumber)
Set the value of the sheet number.
DS_DRAW_ITEM_BASE * GetNext()
void SetProject(const PROJECT *aProject)
const PAGE_INFO & GetPageInfo()
const TITLE_BLOCK & GetTitleBlock()
KICAD_T Type() const
Returns the type of object.
virtual const wxString & GetText() const
Return the string associated with the text object.
EE_TYPE Overlapping(const BOX2I &aRect) const
EE_TYPE OfType(KICAD_T aType) const
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
A class used to associate a SCH_PIN with its owning SCH_SHEET_PATH, in order to handle ERC checks acr...
const SCH_SHEET_PATH & Sheet() const
Get the SCH_SHEET_PATH context for the paired SCH_PIN.
SCH_PIN * Pin() const
Get the SCH_PIN for this context.
Container for ERC settings.
bool IsTestEnabled(int aErrorCode) const
ERC_PIN_SORTING_METRIC GetERCSortingMetric() const
Get the type of sorting metric the ERC checker should use to resolve multi-pin errors.
PIN_ERROR GetPinMapValue(int aFirstType, int aSecondType) const
int GetPinTypeWeight(ELECTRICAL_PINTYPE aPinType) const
Get the weight for an electrical pin type.
int TestLibSymbolIssues()
Test symbols for changed library symbols and broken symbol library links.
int TestStackedPinNotation()
Checks for pin numbers that resemble stacked pin notation but are invalid.
ERC_TESTER(SCHEMATIC *aSchematic, bool aShowAllErrors=false)
void TestTextVars(DS_PROXY_VIEW_ITEM *aDrawingSheet)
Check for any unresolved text variable references.
int TestPinToPin()
Checks the full netlist against the pin-to-pin connectivity requirements.
int TestSimilarLabels()
Checks for labels that differ only in capitalization.
SCH_MULTI_UNIT_REFERENCE_MAP m_refMap
int TestEmptyLabelNames()
Check for labels with empty or whitespace-only names.
int TestFootprintLinkIssues(KIFACE *aCvPcb, PROJECT *aProject)
Test footprint links against the current footprint libraries.
static int TestConnectivity(SCHEMATIC &aSchematic)
int TestOffGridEndpoints()
Test pins and wire ends for being off grid.
int TestDuplicateSheetNames(bool aCreateMarker)
Inside a given sheet, one cannot have sheets with duplicate names (file names can be duplicated).
int TestSameLocalGlobalLabel()
Checks for global and local labels with the same name.
int TestMultUnitPinConflicts()
Checks if shared pins on multi-unit symbols have been connected to different nets.
int TestEmptyPowerValues()
Check for power symbols whose value resolves to nothing, leaving their net unnamed.
int TestNoConnectPins()
In KiCad 5 and earlier, you could connect stuff up to pins with NC electrical type.
int TestFootprintFilters()
Test symbols to ensure that assigned footprint passes any given footprint filters.
int TestPinMap(KIFACE *aCvPcb, PROJECT *aProject)
Check pin-to-pad maps (issue #2282): stale pin references, duplicate pad targets, bad pads and unmapp...
int TestFieldNameWhitespace()
Check for field names with leading or trailing whitespace.
int TestDuplicatePinNets()
Checks if duplicate pin numbers within a symbol are connected to different nets.
ERC_SETTINGS & m_settings
int TestFourWayJunction()
Test to see if there are potentially confusing 4-way junctions in the schematic.
int TestMissingNetclasses()
Tests for netclasses that are referenced but not defined.
int TestSimModelIssues()
Test SPICE models for various issues.
SCH_SHEET_LIST m_sheetList
int TestGroundPins()
Checks for ground-labeled pins not on a ground net while another pin is.
std::vector< SCH_CONNECTIVITY::MULTI_UNIT_GROUP > multiUnitSources() const
void RunTests(DS_PROXY_VIEW_ITEM *aDrawingSheet, SCH_EDIT_FRAME *aEditFrame, KIFACE *aCvPcb, PROJECT *aProject, PROGRESS_REPORTER *aProgressReporter)
int TestMissingUnits()
Test for uninstantiated units of multi unit symbols.
int TestLabelMultipleWires()
Test to see if there are labels that are connected to more than one wire.
int TestVariantSymbols()
Test all variant symbol overrides for resolution and pin compatibility.
int TestMultiunitFootprints()
Test if all units of each multiunit symbol have the same footprint assigned.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Represents a group of jumper pins or pads, keyed by name.
wxString AsString() const
bool IsLibraryLoaded(const wxString &aNickname)
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
A logical library item identifier and consists of various portions much like a URI.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
wxString GetUniStringLibId() const
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
const UTF8 & GetLibItemName() const
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Define a library symbol object.
const std::vector< ASSOCIATED_FOOTPRINT > & GetEffectiveAssociatedFootprints() const
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
bool GetDuplicatePinNumbersAreJumpers() const
virtual LIBRARY_MANAGER & GetLibraryManager() const
A symbol-owned ordered set of named pin maps.
const std::vector< PIN_MAP > & GetAll() const
const PIN_MAP * FindByName(const wxString &aName) const
const std::vector< PIN_MAP_ENTRY > & GetEntries() const
const wxString & GetName() const
A progress reporter interface for use in multi-threaded environments.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Holds all the data relating to one schematic.
SCH_CONNECTIVITY::NETCHAIN_MANAGER & NetChains() const
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
SCH_CONNECTIVITY::FACADE & Connectivity() const
CONNECTION_GRAPH * ConnectionGraph() const
ERC_SETTINGS & ErcSettings() const
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Class for a wire to bus entry.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString Name(bool aIgnoreSheet=false) const
std::vector< ERC_PIN_NET > PinNets() const
Active pins for each named net, in net name order.
std::vector< NAMED_ITEM > NamedItems() const
Every label and power pin with its resolved name, on every instance.
std::vector< FOOTPRINT_SOURCE > FootprintSources() const
Resolved footprint and filters of every symbol on every instance.
const ENGINE & Engine() const
const std::vector< std::unique_ptr< SCH_NETCHAIN > > & GetCommittedNetChains() const
Return user-created (committed) net chains (legacy accessor retained under net-chain API).
Schematic editor (Eeschema) main window.
bool RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, PROGRESS_REPORTER *aProgressReporter=nullptr, bool aCleanupDone=false)
Generate the connection data for the entire schematic hierarchy.
wxString GetUntranslatedName() const
Get the untranslated field name for storage, variable look-up, etc.
wxString GetShownText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString, int aDepth=0) const
Base class for any item which can be embedded within the SCHEMATIC container class,...
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Segment description base class to describe items which have 2 end points (track, wire,...
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
VECTOR2I GetEndPoint() const
VECTOR2I GetStartPoint() const
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
PAD_RESOLUTION
Outcome of pin-to-pad resolution (issue #2282).
VECTOR2I GetPosition() const override
bool IsStacked(const SCH_PIN *aPin) const
static bool HasIdentityPad(const wxString &aPinNumber, const std::set< wxString > &aPads)
bool IsPower() const
Check if the pin is either a global or local power pin.
ELECTRICAL_PINTYPE GetType() const
A helper to define a symbol's reference designator in a schematic.
const SCH_SHEET_PATH & GetSheetPath() const
const wxString GetFootprint() const
SCH_SYMBOL * GetSymbol() const
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
const SCH_SHEET * GetSheet(unsigned aIndex) const
SCH_SCREEN * LastScreen()
const KIID_PATH & PathRef() const
Borrow the cached path until this sheet path is modified or destroyed.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
VECTOR2I GetPosition() const override
const wxString GetFootprintFieldText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool IsGlobalPower() const override
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
VECTOR2I GetPosition() const override
const LIB_ID & GetLibId() const override
const wxString GetValue(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const override
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
VECTOR2I GetPosition() const override
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, std::span< const wxString > aPins, REPORTER &aReporter)
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
A base class for LIB_SYMBOL and SCH_SYMBOL.
virtual bool IsGlobalPower() const =0
virtual bool IsLocalPower() const =0
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
A wrapper for reporting to a wxString object.
void CheckDuplicatePins(LIB_SYMBOL *aSymbol, std::vector< wxString > &aMessages, UNITS_PROVIDER *aUnitsProvider)
const wxString CommentERC_V[]
const wxString CommentERC_H[]
const std::set< ELECTRICAL_PINTYPE > DrivenPinTypes
const std::set< ELECTRICAL_PINTYPE > DrivingPinTypes
const std::set< ELECTRICAL_PINTYPE > DrivingPowerPinTypes
@ ERCE_POWERPIN_NOT_DRIVEN
Power input pin connected to some others pins but no power out pin to drive it.
@ ERCE_DRIVER_CONFLICT
Conflicting drivers (labels, etc) on a subgraph.
@ ERCE_SIMILAR_POWER
2 power pins are equal for case insensitive comparisons.
@ ERCE_MISSING_POWER_INPUT_PIN
Symbol has power input pins that are not placed on the schematic.
@ ERCE_EMPTY_POWER_VALUE
Power symbol has no value, so it names no net.
@ ERCE_UNCONNECTED_WIRE_ENDPOINT
A label is connected to more than one wire.
@ ERCE_GROUND_PIN_NOT_GROUND
A ground-labeled pin is not on a ground net while another pin is.
@ ERCE_SIMILAR_LABELS
2 labels are equal for case insensitive comparisons.
@ ERCE_VARIANT_SYMBOL_INCOMPATIBLE
Variant symbol override fails pin compatibility.
@ ERCE_STACKED_PIN_SYNTAX
Pin name resembles stacked pin notation.
@ ERCE_LABEL_NOT_CONNECTED
Label not connected to any pins.
@ ERCE_ENDPOINT_OFF_GRID
Pin or wire-end off grid.
@ ERCE_EMPTY_LABEL_NAME
Label has an empty or whitespace-only name.
@ ERCE_SAME_LOCAL_GLOBAL_LABEL
2 labels are equal for case insensitive comparisons.
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
@ ERCE_SIMILAR_LABEL_AND_POWER
label and pin are equal for case insensitive comparisons.
@ ERCE_SAME_LOCAL_GLOBAL_POWER
Local power port and global power port have the same name.
@ ERCE_PIN_MAP_BAD_PAD
Pin map references a pad absent from the footprint.
@ ERCE_LABEL_SINGLE_PIN
A label is connected only to a single pin.
@ ERCE_BUS_ENTRY_CONFLICT
A wire connected to a bus doesn't match the bus.
@ ERCE_FOOTPRINT_LINK_ISSUES
The footprint link is invalid, or points to a missing (or inactive) footprint or library.
@ ERCE_PIN_MAP_DUPLICATE_PAD
Two symbol pins map to one pad (not stacked/jumper).
@ ERCE_BUS_TO_NET_CONFLICT
A bus wire is graphically connected to a net port/pin (or vice versa).
@ ERCE_DUPLICATE_PIN_ERROR
@ ERCE_NOCONNECT_NOT_CONNECTED
A no connect symbol is not connected to anything.
@ ERCE_DIFFERENT_UNIT_NET
Shared pin in a multi-unit symbol is connected to more than one net.
@ ERCE_FOUR_WAY_JUNCTION
A four-way junction was found.
@ ERCE_PIN_NOT_CONNECTED
Pin not connected and not no connect symbol.
@ ERCE_UNDEFINED_NETCLASS
A netclass was referenced but not defined.
@ ERCE_UNRESOLVED_VARIABLE
A text variable could not be resolved.
@ ERCE_SIMULATION_MODEL
An error was found in the simulation model.
@ ERCE_LIB_SYMBOL_MISMATCH
Symbol doesn't match copy in library.
@ ERCE_DIFFERENT_UNIT_FP
Different units of the same symbol have different footprints assigned.
@ ERCE_NOCONNECT_CONNECTED
A no connect symbol is connected to more than 1 pin.
@ ERCE_PIN_TO_PIN_WARNING
@ ERCE_PIN_NOT_DRIVEN
Pin connected to some others pins but no pin to drive it.
@ ERCE_MISSING_INPUT_PIN
Symbol has input pins that are not placed.
@ ERCE_MISSING_UNIT
Symbol has units that are not placed on the schematic.
@ ERCE_FIELD_NAME_WHITESPACE
Field name has leading or trailing whitespace.
@ ERCE_DUPLICATE_SHEET_NAME
Duplicate sheet names within a given sheet.
@ ERCE_PIN_MAP_STALE_PIN
Pin map references a pin number not on the symbol.
@ ERCE_MISSING_BIDI_PIN
Symbol has bi-directional pins that are not placed.
@ ERCE_LIB_SYMBOL_ISSUES
Symbol not found in active libraries.
@ ERCE_FOOTPRINT_FILTERS
The assigned footprint doesn't match the footprint filters.
@ ERCE_HIERACHICAL_LABEL
Mismatch between hierarchical labels and pins sheets.
@ ERCE_WIRE_DANGLING
Some wires are not connected to anything else.
@ ERCE_VARIANT_SYMBOL_INVALID
Variant symbol override LIB_ID cannot be resolved.
@ ERCE_SINGLE_GLOBAL_LABEL
A label only exists once in the schematic.
@ ERCE_PIN_MAP_UNMAPPED_PIN
A connected pin resolves to no footprint pad.
@ ERCE_LABEL_MULTIPLE_WIRES
A label is connected to more than one wire.
@ ERCE_WIRED_IMPLICIT_POWER
Wired hidden power input also joins its global net by name.
PIN_ERROR
The values a pin-to-pin entry in the pin matrix can take on.
bool m_ConnectivityEngine
Use the schematic connectivity engine instead of CONNECTION_GRAPH.
const wxChar *const traceSchNetChain
Flag to enable tracing of schematic net chain rebuild and ERC cross-chain checks.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ KIFACE_TEST_FOOTPRINT_LINK_LIBRARY_NOT_ENABLED
@ KIFACE_TEST_FOOTPRINT_LINK
@ KIFACE_TEST_FOOTPRINT_LINK_NO_LIBRARY
@ KIFACE_TEST_FOOTPRINT_LINK_NO_FOOTPRINT
@ KIFACE_FOOTPRINT_PAD_NUMBERS
Function pointer type: void (*)( const wxString& aFootprint, PROJECT* aProject, std::set<wxString>& a...
@ MISMATCH
Entries name the host with another key of this type, and none with this one.
Value keys and the key session of the schematic connectivity engine.
SOURCE_LOCATION UNCONNECTED_PIN
std::optional< PIN_MAP_FACT > ExtractPinMapFacts(const SCH_SYMBOL &aSymbol)
std::vector< SIMULATION_MODEL_FACT > ExtractSimulationModelFacts(const SCH_SHEET_PATH &aPath, const wxString &aVariantName)
std::vector< TEXT_CHECK_FACT > ExtractTextChecks(const SCH_SCREEN &aScreen, const SCH_SHEET_PATH &aPath)
SOURCE_LOCATION LABEL_LOCATION
LIBRARY_SYMBOL_FACT ExtractLibrarySymbolFact(const LIB_SYMBOL &aSymbol)
std::vector< TEXT_ASSERTION > ExtractTextAssertions(const wxString &aText)
std::optional< VARIANT_SYMBOL_FACT > ExtractVariantSymbolFact(const SCH_SYMBOL &aSymbol, const SCH_SHEET_PATH &aPath)
std::vector< UNIT_FACT > ExtractUnitFacts(const LIB_SYMBOL &aSymbol)
PGM_BASE & Pgm()
The global program "get" accessor.
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
@ PT_INPUT
usual pin input: must be connected
@ PT_NC
not connected (must be left open)
@ PT_TRISTATE
tri state bus pin
@ PT_NIC
not internally connected (may be connected to anything)
@ PT_BIDI
input or output (like port for a microprocessor)
@ PT_POWER_OUT
output of a regulator: intended to be connected to power input pins
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
wxString ElectricalPinTypeGetText(ELECTRICAL_PINTYPE)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
static const std::vector< KICAD_T > labelTypes
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
std::vector< wxString > ExpandStackedPinNotation(const wxString &aPinName, bool *aValid)
Expand stacked pin notation like [1,2,3], [1-4], [A1-A4], or [AA1-AA3,AB4,CD12-CD14] into individual ...
wxString UnescapeString(const wxString &aSource)
int SplitString(const wxString &strToSplit, wxString *strBeginning, wxString *strDigits, wxString *strEnd)
Break a string into three parts: he alphabetic preamble, the numeric part, and any alphabetic ending.
Implement a participant in the KIWAY alchemy.
virtual void * IfaceOrAddress(int aDataId)=0
Return pointer to the requested object.
bool duplicatePinNumbersAreJumpers
One symbol-pin to footprint-pad mapping inside a PIN_MAP.
Two bus claims on one island that share no member, or a bus vector joined to a bus group.
A bus wire entry whose net is not a member of the bus it touches.
An island that mixes net and bus items.
Two different strong names on one island.
One active symbol pin on one sheet instance, with the reference of its symbol.
Up to four wires and bus entries of one island that has no driver.
A hierarchical label or sheet pin with no partner, or a dangling sheet pin.
A label that connects to nothing, or to only one pin.
bool HasDuplicatePins() const
bool Matches(const LIBRARY_SYMBOL_FACT &aOther, int aCompareFlags) const
LIB_SYMBOL_ATTRIBUTES attributes
All placed units that share one reference, with the unit table of the library symbol.
One placed unit of an annotated multi-unit symbol.
A label or a power pin with its resolved net name.
A no-connect flag on a net with more than one pin, or on a net with no pin and no label.
One item on one sheet instance, for a diagnostic that needs only a location.
One dangling end of a wire or a bus wire entry.
IbisParser parser & reporter
static std::set< FOOTPRINT * > collectFootprints(const PCB_GROUP *aGroup)
const SHAPE_LINE_CHAIN chain
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
std::vector< VARIANT_COMPAT_RESULT > ValidateVariantSymbolCompatibility(const LIB_SYMBOL &aBase, const LIB_SYMBOL &aCandidate)
Check whether aCandidate can be used as a variant symbol override for aBase.
VECTOR2< int32_t > VECTOR2I