Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
8a92ff80bThis file is pinned to the selected release. Download the original to open it in your design tool.
/*
* LibrePCB - Professional EDA for everyone!
* Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
* https://librepcb.org/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "electricalrulecheck.h"
#include "../../library/cmp/component.h"
#include "../../library/cmp/componentsignal.h"
#include "../circuit/bus.h"
#include "../circuit/circuit.h"
#include "../circuit/componentinstance.h"
#include "../circuit/componentsignalinstance.h"
#include "../circuit/netclass.h"
#include "../circuit/netsignal.h"
#include "../project.h"
#include "../schematic/items/si_busjunction.h"
#include "../schematic/items/si_bussegment.h"
#include "../schematic/items/si_netpoint.h"
#include "../schematic/items/si_netsegment.h"
#include "../schematic/items/si_symbol.h"
#include "../schematic/items/si_symbolpin.h"
#include "../schematic/schematic.h"
#include "electricalrulecheckmessages.h"
#include <QtCore>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
ElectricalRuleCheck::ElectricalRuleCheck(const Project& project) noexcept
: mProject(project) {
}
ElectricalRuleCheck::~ElectricalRuleCheck() noexcept {
}
/*******************************************************************************
* General Methods
******************************************************************************/
RuleCheckMessageList ElectricalRuleCheck::runChecks() const {
mOpenNetSignals.clear();
RuleCheckMessageList msgs;
checkNetClasses(msgs);
checkNetSignals(msgs);
checkBuses(msgs);
checkComponents(msgs);
checkSchematics(msgs);
return msgs;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void ElectricalRuleCheck::checkNetClasses(RuleCheckMessageList& msgs) const {
// Don't warn if there's only one netclass, as we need one to be used as
// default when adding a new wire.
if (mProject.getCircuit().getNetClasses().count() <= 1) {
return;
}
foreach (const NetClass* netClass, mProject.getCircuit().getNetClasses()) {
if (!netClass->isUsed()) {
msgs.append(std::make_shared<ErcMsgUnusedNetClass>(*netClass));
}
}
}
void ElectricalRuleCheck::checkNetSignals(RuleCheckMessageList& msgs) const {
foreach (const NetSignal* net, mProject.getCircuit().getNetSignals()) {
// Raise a warning if the net signal is connected to less then two component
// signals. But do not count component signals of schematic-only components
// since these are just "virtual" connections, i.e. not represented by a
// real pad (see https://github.com/LibrePCB/LibrePCB/issues/739).
const QList<ComponentSignalInstance*>& sigs = net->getComponentSignals();
int registeredRealComponentCount = sigs.count();
if (registeredRealComponentCount >= 2) { // Optimization
foreach (const ComponentSignalInstance* sig, sigs) {
if (sig->getComponentInstance().getLibComponent().isSchematicOnly()) {
--registeredRealComponentCount;
}
}
}
if (registeredRealComponentCount < 2) {
mOpenNetSignals.insert(net);
msgs.append(std::make_shared<ErcMsgOpenNet>(*net));
}
}
}
void ElectricalRuleCheck::checkBuses(RuleCheckMessageList& msgs) const {
foreach (const Bus* bus, mProject.getCircuit().getBuses()) {
if (!bus->isUsed()) {
msgs.append(std::make_shared<ErcMsgUnusedBus>(*bus));
}
// Collect all connected net segments.
QHash<const NetSignal*, QVector<const SI_NetSegment*>> netSegments;
QSet<const NetSignal*> unnamedNets;
for (const SI_BusSegment* bs : bus->getSchematicBusSegments()) {
for (const SI_NetSegment* ns : bs->getAttachedNetSegments()) {
netSegments[&ns->getNetSignal()].append(ns);
if (ns->getNetLabels().isEmpty()) {
unnamedNets.insert(&ns->getNetSignal());
}
}
}
// Warn about net segments without net label.
for (const NetSignal* net : unnamedNets) {
const SI_NetSegment* ns = netSegments.value(net).value(0);
Q_ASSERT(ns);
msgs.append(std::make_shared<ErcMsgUnnamedNetInBus>(*bus, *ns));
}
// Warn about nets which are attached only once to the bus.
for (auto it = netSegments.begin(); it != netSegments.end(); it++) {
if ((it.value().count() == 1) && (!unnamedNets.contains(it.key()))) {
msgs.append(
std::make_shared<ErcMsgOpenNetInBus>(*bus, *it.value().first()));
}
}
}
}
void ElectricalRuleCheck::checkComponents(RuleCheckMessageList& msgs) const {
foreach (const ComponentInstance* cmp,
mProject.getCircuit().getComponentInstances()) {
checkComponentSignals(*cmp, msgs);
// Check for unplaced gates.
for (const ComponentSymbolVariantItem& gate :
cmp->getSymbolVariant().getSymbolItems()) {
if (!cmp->getSymbols().contains(gate.getUuid())) {
if (gate.isRequired()) {
msgs.append(std::make_shared<ErcMsgUnplacedRequiredGate>(*cmp, gate));
} else {
msgs.append(std::make_shared<ErcMsgUnplacedOptionalGate>(*cmp, gate));
}
}
}
}
}
void ElectricalRuleCheck::checkComponentSignals(
const ComponentInstance& cmp, RuleCheckMessageList& msgs) const {
foreach (const ComponentSignalInstance* sig, cmp.getSignals()) {
// Check for forced net name conflict.
const QString netName =
sig->getNetSignal() ? (*sig->getNetSignal()->getName()) : QString();
if ((sig->getCompSignal().isRequired()) && (!sig->getNetSignal())) {
msgs.append(std::make_shared<ErcMsgUnconnectedRequiredSignal>(*sig));
} else if (sig->isNetSignalNameForced() &&
(sig->getForcedNetSignalName() != netName)) {
msgs.append(std::make_shared<ErcMsgForcedNetSignalNameConflict>(*sig));
}
}
}
void ElectricalRuleCheck::checkSchematics(RuleCheckMessageList& msgs) const {
foreach (const Schematic* schematic, mProject.getSchematics()) {
checkSymbols(*schematic, msgs);
checkNetSegments(*schematic, msgs);
checkBusSegments(*schematic, msgs);
}
}
void ElectricalRuleCheck::checkSymbols(const Schematic& schematic,
RuleCheckMessageList& msgs) const {
foreach (const SI_Symbol* symbol, schematic.getSymbols()) {
checkPins(*symbol, msgs);
}
}
void ElectricalRuleCheck::checkPins(const SI_Symbol& symbol,
RuleCheckMessageList& msgs) const {
foreach (const SI_SymbolPin* pin, symbol.getPins()) {
if ((pin->getNetLines().isEmpty()) && (pin->getCompSigInstNetSignal())) {
msgs.append(std::make_shared<ErcMsgConnectedPinWithoutWire>(*pin));
}
}
}
void ElectricalRuleCheck::checkNetSegments(const Schematic& schematic,
RuleCheckMessageList& msgs) const {
foreach (const SI_NetSegment* netSegment, schematic.getNetSegments()) {
checkNetPoints(*netSegment, msgs);
// If there are no net labels, check for any open wire. But only if there's
// no "open net" warning on the net raised, since this would be quite a
// duplicate warning.
if (netSegment->getNetLabels().isEmpty() &&
(!mOpenNetSignals.contains(&netSegment->getNetSignal()))) {
foreach (const SI_NetLine* netLine, netSegment->getNetLines()) {
if (netLine->getP1().isOpen() || netLine->getP2().isOpen()) {
msgs.append(
std::make_shared<ErcMsgOpenWireInSegment>(*netSegment, *netLine));
break;
}
}
}
}
}
void ElectricalRuleCheck::checkNetPoints(const SI_NetSegment& netSegment,
RuleCheckMessageList& msgs) const {
foreach (const SI_NetPoint* netPoint, netSegment.getNetPoints()) {
if (netPoint->getNetLines().isEmpty()) {
msgs.append(std::make_shared<ErcMsgUnconnectedJunction>(*netPoint));
}
}
}
void ElectricalRuleCheck::checkBusSegments(const Schematic& schematic,
RuleCheckMessageList& msgs) const {
foreach (const SI_BusSegment* segment, schematic.getBusSegments()) {
checkBusJunctions(*segment, msgs);
}
}
void ElectricalRuleCheck::checkBusJunctions(const SI_BusSegment& segment,
RuleCheckMessageList& msgs) const {
foreach (const SI_BusJunction* bj, segment.getJunctions()) {
if (bj->getBusLines().isEmpty()) {
msgs.append(std::make_shared<ErcMsgUnconnectedJunction>(*bj));
}
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace librepcb