diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index 09b7cb1b..04fec405 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -12,23 +12,12 @@ DBC_MESSAGE::DBC_MESSAGE() sender = nullptr; } -DBC_SIGNAL::DBC_SIGNAL() +void DBC_SIGNAL::addMultiplexRange(int min, int max) { - bias = 0; - isMultiplexed = false; - isMultiplexor = false; - max = 1; - min = 0; - multiplexLowValue = 0; - multiplexHighValue = 0; - factor = 1.0; - intelByteOrder = false; - parentMessage = nullptr; - multiplexParent = nullptr; - receiver = nullptr; - signalSize = 1; - startBit = 1; - valType = DBC_SIG_VAL_TYPE::UNSIGNED_INT; + if (min != max) + hasExtendedMultiplexing = true; + isMultiplexed = true; + multiplexLowAndHighValues.append(QPair(min, max)); } bool DBC_SIGNAL::isSignalInMessage(const CANFrame &frame) @@ -42,11 +31,7 @@ bool DBC_SIGNAL::isSignalInMessage(const CANFrame &frame) { int val; if (!multiplexParent->processAsInt(frame, val)) return false; - if ((val >= multiplexLowValue) && (val <= multiplexHighValue)) - { - return true; - } - else return false; + return isValueMatchingMultiplex(val); } else return false; } @@ -55,6 +40,111 @@ bool DBC_SIGNAL::isSignalInMessage(const CANFrame &frame) else return true; //if signal isn't multiplexed then it's definitely in the message } +bool DBC_SIGNAL::isValueMatchingMultiplex(int val) const +{ + for (auto limitPair : multiplexLowAndHighValues) { + if ((limitPair.first <= val) && (val <= limitPair.second)) + return true; + } + return false; +} + +QString DBC_SIGNAL::multiplexDbcString(DbcMuxStringFormat fmt) const +{ + QString ret; + for (auto limitPair : multiplexLowAndHighValues) { + if (fmt == MuxStringFormat_DbcFile) { + if (!ret.isEmpty()) + ret.append(QStringLiteral(" ")); + ret.append(QString("%1-%2").arg(limitPair.first).arg(limitPair.second)); + } else { + if (!ret.isEmpty()) + ret.append(QStringLiteral(";")); + ret.append(QString::number(limitPair.first)); + if (limitPair.first != limitPair.second) + ret.append(QString("-%1").arg(limitPair.second)); + } + } + return ret; +} + +void DBC_SIGNAL::copyMultiplexValuesFromSignal(const DBC_SIGNAL &signal) +{ + isMultiplexed = signal.isMultiplexed; + for (auto multiplexSignalPair : signal.multiplexLowAndHighValues) { + multiplexLowAndHighValues.append(multiplexSignalPair); + } +} + +/** + * @brief DBC_SIGNAL::parseDbcMultiplexUiString + * Method for parsing the Vector CANDB++ like multiplex definitions: + * + * Single values has to be separated by semicolons + * and the value ranges by hypens + * (e.g.: 1;2;5-7) + * @param multiplexes in the format from the UI + * @param errorString output parameter to pass the failure text if parsing failed + * @return true if the multiplexes parameter could be parsed properly + */ +bool DBC_SIGNAL::parseDbcMultiplexUiString(const QString &multiplexes, QString &errorString) +{ + QList> multiplexLowAndHighValuesTemp; + const auto muxes = multiplexes.split(QChar(';'), Qt::SkipEmptyParts); + for (const auto &mux : muxes) { + bool ok = false; + if (mux.contains(QChar('-'))) { + const auto minMax = mux.split(QChar('-')); + if (minMax.count() != 2) { + errorString = QObject::tr("The %1 part contains more than one '-' sign").arg(mux); + return false; + } + + int min = minMax.at(0).toInt(&ok); + if (!ok) { + errorString = QObject::tr("Unable to parse the %1 part to integer").arg(minMax.at(0)); + return false; + } + + int max = minMax.at(1).toInt(&ok); + if (!ok) { + errorString = QObject::tr("Unable to parse the %1 part to integer").arg(minMax.at(1)); + return false; + } + + multiplexLowAndHighValuesTemp.append(QPair(min, max)); + } else { + int value = mux.toInt(&ok); + if (!ok) { + errorString = QObject::tr("Unable to parse the %1 part to integer").arg(mux); + return false; + } + multiplexLowAndHighValuesTemp.append(QPair(value, value)); + } + } + multiplexLowAndHighValues.clear(); + multiplexLowAndHighValues = multiplexLowAndHighValuesTemp; + return true; +} + +bool DBC_SIGNAL::multiplexesIdenticalToSignal(DBC_SIGNAL *other) const +{ + auto othersMuxes = other->multiplexLowAndHighValues; + for (auto myMux : multiplexLowAndHighValues) { + bool found = false; + for (auto otherMux : othersMuxes) { + if (myMux == otherMux) { + othersMuxes.removeAll(myMux); + found = true; + break; + } + } + if (!found) + return false; + } + return othersMuxes.isEmpty(); +} + //Take all the children of this signal and see if they exist in the message. Can be called recursively to descend the dependency tree QString DBC_SIGNAL::processSignalTree(const CANFrame &frame) { @@ -69,7 +159,7 @@ QString DBC_SIGNAL::processSignalTree(const CANFrame &frame) foreach (DBC_SIGNAL *sig, multiplexedChildren) { - if ( (val >= sig->multiplexLowValue) && (val <= sig->multiplexHighValue) ) + if (sig->isValueMatchingMultiplex(val)) { qDebug() << "Found match for multiplex value range - " << sig->name; QString sigString; diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index 11a75682..e37cc63c 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -89,31 +89,44 @@ class DBC_SIGNAL; class DBC_SIGNAL { public: //TODO: this is sloppy. It shouldn't all be public! + DBC_SIGNAL() = default; + + enum DbcMuxStringFormat { + MuxStringFormat_DbcFile, + MuxStringFormat_UI + }; QString name; - int startBit; - int signalSize; - bool intelByteOrder; //true is obviously little endian. False is big endian - bool isMultiplexor; - bool isMultiplexed; - int multiplexHighValue; - int multiplexLowValue; - DBC_SIG_VAL_TYPE valType; - double factor; - double bias; - double min; - double max; - DBC_NODE *receiver; //it is fast to have a pointer but dangerous... Make sure to walk the whole tree and delete everything so nobody has stale references. - DBC_MESSAGE *parentMessage; + int startBit = 1; + int signalSize = 1; + bool intelByteOrder = false; //true is obviously little endian. False is big endian + + bool isMultiplexor = false; + bool isMultiplexed = false; + void addMultiplexRange(int min, int max); + int multiplexHighValue = 0; + int multiplexLowValue = 0; + bool hasExtendedMultiplexing = false; + QList multiplexedChildren; + DBC_SIGNAL *multiplexParent = nullptr; + QString multiplexDbcString(DbcMuxStringFormat fmt = MuxStringFormat_DbcFile) const; + void copyMultiplexValuesFromSignal(const DBC_SIGNAL &signal); + bool parseDbcMultiplexUiString(const QString &multiplexes, QString &errorString); + bool multiplexesIdenticalToSignal(DBC_SIGNAL *other) const; + + DBC_SIG_VAL_TYPE valType = DBC_SIG_VAL_TYPE::UNSIGNED_INT; + double factor = 1.0; + double bias = 0; + double min = 0; + double max = 1; + DBC_NODE *receiver = nullptr; //it is fast to have a pointer but dangerous... Make sure to walk the whole tree and delete everything so nobody has stale references. + DBC_MESSAGE *parentMessage = nullptr; QString unitName; QString comment; QVariant cachedValue; QList attributes; QList valList; - QList multiplexedChildren; - DBC_SIGNAL *multiplexParent; DBC_SIGNAL *self; - DBC_SIGNAL(); bool processAsText(const CANFrame &frame, QString &outString, bool outputName = true, bool outputUnit = true); bool processAsInt(const CANFrame &frame, int32_t &outValue); bool processAsDouble(const CANFrame &frame, double &outValue); @@ -123,11 +136,15 @@ class DBC_SIGNAL DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name); DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx); bool isSignalInMessage(const CANFrame &frame); + bool isValueMatchingMultiplex(int val) const; + friend bool operator<(const DBC_SIGNAL& l, const DBC_SIGNAL& r) { return (l.name.toLower() < r.name.toLower()); } +private: + QList> multiplexLowAndHighValues; }; class DBCSignalHandler; //forward declaration to keep from having to include dbchandler.h in this file and thus create a loop diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index acf3aa1c..d2a7d57e 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -507,11 +507,6 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) //bool isMultiplexed = false; DBC_SIGNAL sig; - sig.multiplexLowValue = 0; - sig.multiplexHighValue = 0; - sig.isMultiplexed = false; - sig.isMultiplexor = false; - qDebug() << "Found a SG line"; regex.setPattern("^SG\\_ *([-\\w]+) +M *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); @@ -529,10 +524,7 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) if (match.hasMatch()) { qDebug() << "Multiplexed signal"; - //isMultiplexed = true; - sig.isMultiplexed = true; - sig.multiplexLowValue = match.captured(2).toInt(); - sig.multiplexHighValue = sig.multiplexLowValue; + sig.addMultiplexRange(match.captured(2).toInt(), match.captured(2).toInt()); offset = 1; } else @@ -543,9 +535,7 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) { qDebug() << "Extended Multiplexor Signal"; sig.isMultiplexor = true; //we don't set the local isMessageMultiplexor variable because this isn't the top level multiplexor - sig.isMultiplexed = true; //but, it is both a multiplexor and multiplexed - sig.multiplexLowValue = match.captured(2).toInt(); - sig.multiplexHighValue = sig.multiplexLowValue; + sig.addMultiplexRange(match.captured(2).toInt(), match.captured(2).toInt()); offset = 1; } else @@ -643,7 +633,7 @@ bool DBCFile::parseSignalMultiplexValueLine(QString line) QRegularExpressionMatch match; qDebug() << "Found a multiplex definition line"; - regex.setPattern("^SG\\_MUL\\_VAL\\_ (\\d+) ([-\\w]+) ([-\\w]+) (\\d+)\\-(\\d+);"); + regex.setPattern("^SG\\_MUL\\_VAL\\_ (\\d+) ([-\\w]+) ([-\\w]+) ((?:\\d+\\-\\d+[\\s]*[\\,]?[\\s]*)*)"); match = regex.match(line); //captured 1 is message ID //Captured 2 is signal name @@ -661,11 +651,21 @@ bool DBCFile::parseSignalMultiplexValueLine(QString line) DBC_SIGNAL *parentSignal = msg->sigHandler->findSignalByName(match.captured(3)); if (parentSignal != nullptr) { - //now need to add "thisSignal" to the children multiplexed signals of "parentSignal" + const QStringList ranges = match.captured(4).split(QChar(','), Qt::SkipEmptyParts); + for (const QString &range : ranges) { + //now need to add "thisSignal" to the children multiplexed signals of "parentSignal" + const QStringList rangeSides = range.trimmed().split(QChar('-')); + if (rangeSides.count() != 2) { + qDebug() << QString("Malformed range definition: '%2' found in the multiplexed signal: %1") + .arg(match.captured(1).arg(range.trimmed())); + return false; + } + int rangeMin = rangeSides.at(0).toInt(); + int rangeMax = rangeSides.at(1).toInt(); + thisSignal->multiplexParent = parentSignal; + thisSignal->addMultiplexRange(rangeMin, rangeMax); + } parentSignal->multiplexedChildren.append(thisSignal); - thisSignal->multiplexParent = parentSignal; - thisSignal->multiplexLowValue = match.captured(4).toInt(); - thisSignal->multiplexHighValue = match.captured(5).toInt(); return true; } } @@ -1458,7 +1458,7 @@ bool DBCFile::saveFile(QString fileName) } //check for the two telltale signs that we've got extended multiplexing going on. if (sig->isMultiplexed && sig->isMultiplexor) hasExtendedMultiplexing = true; - if (sig->multiplexLowValue != sig->multiplexHighValue) hasExtendedMultiplexing = true; + if (sig->hasExtendedMultiplexing) hasExtendedMultiplexing = true; msgOutput.append(" : " + QString::number(sig->startBit) + "|" + QString::number(sig->signalSize) + "@"); @@ -1625,7 +1625,7 @@ bool DBCFile::saveFile(QString fileName) { msgOutput.append("SG_MUL_VAL_ " + QString::number(ID) + " "); msgOutput.append(sig->name + " " + sig->multiplexParent->name + " "); - msgOutput.append(QString::number(sig->multiplexLowValue) + "-" + QString::number(sig->multiplexHighValue) + ";"); + msgOutput.append(sig->multiplexDbcString() + ";"); msgOutput.append("\n"); extMultiplexOutput.append(msgOutput); msgOutput.clear(); //got to reset it after writing @@ -2042,14 +2042,7 @@ DBCFile* DBCHandler::loadJSONFile(QString filename) if (!sigObj.find("mux_id")->isUndefined()) { QJsonValue muxVal = sigObj.find("mux_id").value(); - sig.multiplexLowValue = muxVal.toInt(); - sig.multiplexHighValue = sig.multiplexLowValue; - sig.isMultiplexed = true; - } - else - { - sig.multiplexLowValue = 0; - sig.multiplexHighValue = 0; + sig.addMultiplexRange(muxVal.toInt(), muxVal.toInt()); } QJsonValue muxerVal = sigObj.find("is_muxer").value(); if (!muxerVal.isNull()) diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index b48b05c8..50887ead 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -442,9 +442,7 @@ QString DBCMainEditor::createSignalText(DBC_SIGNAL *sig) QString sigInfo; if (sig->isMultiplexed) { - sigInfo = "(" + QString::number(sig->multiplexLowValue); - if (sig->multiplexHighValue != sig->multiplexLowValue) sigInfo += "-" + QString::number(sig->multiplexHighValue); - sigInfo += ") "; + sigInfo = "(" + sig->multiplexDbcString() + ") "; } sigInfo.append(sig->name); @@ -624,8 +622,7 @@ void DBCMainEditor::copyMessageToNode(DBC_NODE *parentNode, DBC_MESSAGE *source, sig.isMultiplexor = false; //sigSource->isMultiplexor; sig.max = sigSource->max; sig.min = sigSource->min; - sig.multiplexLowValue = sigSource->multiplexLowValue; - sig.multiplexHighValue = sigSource->multiplexHighValue; + sig.copyMultiplexValuesFromSignal(*sigSource); sig.factor = sigSource->factor; sig.intelByteOrder = sigSource->intelByteOrder; sig.parentMessage = &msg; diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index 20089fd9..dcdd5e39 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "helpwindow.h" @@ -281,33 +282,21 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : } }); - connect(ui->txtMultiplexLow, &QLineEdit::editingFinished, + connect(ui->txtMultiplexValues, &QLineEdit::editingFinished, [=]() { if (currentSignal == nullptr) return; int temp; - temp = Utility::ParseStringToNum(ui->txtMultiplexLow->text()); - if (currentSignal->multiplexLowValue != temp) + if (currentSignal->multiplexDbcString(DBC_SIGNAL::MuxStringFormat_UI) != ui->txtMultiplexValues->text()) { - pushToUndoBuffer(); - dbcFile->setDirtyFlag(); - //TODO: could look up the multiplexor and ensure that the value is within a range that the multiplexor could return - currentSignal->multiplexLowValue = temp; - } - }); - - connect(ui->txtMultiplexHigh, &QLineEdit::editingFinished, - [=]() - { - if (!currentSignal) return; - int temp; - temp = Utility::ParseStringToNum(ui->txtMultiplexHigh->text()); - if (currentSignal->multiplexHighValue != temp) - { - pushToUndoBuffer(); - dbcFile->setDirtyFlag(); //TODO: could look up the multiplexor and ensure that the value is within a range that the multiplexor could return - currentSignal->multiplexHighValue = temp; + QString errorString; + if (!currentSignal->parseDbcMultiplexUiString(ui->txtMultiplexValues->text(), errorString)) { + QMessageBox::critical(this, tr("Error"), tr("The multiplex values field contains errors:\n%1").arg(errorString)); + } else { + pushToUndoBuffer(); + dbcFile->setDirtyFlag(); + } } }); @@ -326,8 +315,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : currentSignal->isMultiplexor = true; //an extended multi signal cannot be the root multiplexor for a message so make sure to remove it if it was. if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr; - ui->txtMultiplexLow->setEnabled(currentSignal->isMultiplexed); - ui->txtMultiplexHigh->setEnabled(currentSignal->isMultiplexed); + ui->txtMultiplexValues->setEnabled(currentSignal->isMultiplexed); ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); fillSignalForm(currentSignal); } @@ -348,8 +336,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : currentSignal->isMultiplexor = false; //if the set multiplexor for the message was this signal then clear it if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr; - ui->txtMultiplexLow->setEnabled(currentSignal->isMultiplexed); - ui->txtMultiplexHigh->setEnabled(currentSignal->isMultiplexed); + ui->txtMultiplexValues->setEnabled(currentSignal->isMultiplexed); ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); fillSignalForm(currentSignal); } @@ -369,8 +356,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : currentSignal->isMultiplexor = true; //we just set that this is the multiplexor so update the message to show that as well. dbcMessage->multiplexorSignal = currentSignal; - ui->txtMultiplexLow->setEnabled(currentSignal->isMultiplexed); - ui->txtMultiplexHigh->setEnabled(currentSignal->isMultiplexed); + ui->txtMultiplexValues->setEnabled(currentSignal->isMultiplexed); ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); fillSignalForm(currentSignal); } @@ -389,8 +375,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : currentSignal->isMultiplexed = false; currentSignal->isMultiplexor = false; if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr; - ui->txtMultiplexLow->setEnabled(currentSignal->isMultiplexed); - ui->txtMultiplexHigh->setEnabled(currentSignal->isMultiplexed); + ui->txtMultiplexValues->setEnabled(currentSignal->isMultiplexed); ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); fillSignalForm(currentSignal); } @@ -587,8 +572,7 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) ui->txtMinVal->setText(""); ui->txtScale->setText(""); ui->txtUnitName->setText(""); - ui->txtMultiplexLow->setText(""); - ui->txtMultiplexHigh->setText(""); + ui->txtMultiplexValues->setText(""); ui->rbMultiplexed->setChecked(false); ui->rbMultiplexor->setChecked(false); ui->rbNotMulti->setChecked(true); @@ -604,8 +588,7 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) ui->txtName->setText(sig->name); ui->txtBias->setText(QString::number(sig->bias)); ui->txtBitLength->setText(QString::number(sig->signalSize)); - ui->txtMultiplexLow->setText(QString::number(sig->multiplexLowValue)); - ui->txtMultiplexHigh->setText(QString::number(sig->multiplexHighValue)); + ui->txtMultiplexValues->setText(sig->multiplexDbcString(DBC_SIGNAL::MuxStringFormat_UI)); ui->txtComment->setText(sig->comment); ui->txtMaxVal->setText(QString::number(sig->max)); ui->txtMinVal->setText(QString::number(sig->min)); @@ -641,8 +624,7 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) } } - ui->txtMultiplexLow->setEnabled(sig->isMultiplexed); - ui->txtMultiplexHigh->setEnabled(sig->isMultiplexed); + ui->txtMultiplexValues->setEnabled(sig->isMultiplexed); ui->cbMultiplexParent->setEnabled(sig->isMultiplexed); ui->cbIntelFormat->setChecked(sig->intelByteOrder); @@ -693,7 +675,7 @@ void DBCSignalEditor::refreshBitGrid() { DBC_SIGNAL *sig = dbcMessage->sigHandler->findSignalByIdx(x); //only set a signal name for signals which match multiplexparent with our currentsignal - if (!sig->multiplexParent || ((sig->multiplexParent == currentSignal->multiplexParent) && (sig->multiplexHighValue == currentSignal->multiplexHighValue)) ) + if (!sig->multiplexParent || ((sig->multiplexParent == currentSignal->multiplexParent) && (sig->multiplexesIdenticalToSignal(currentSignal)) )) { ui->bitfield->setSignalNames(x, sig->name); //qDebug() << sig->name << sig->multiplexParent; @@ -845,8 +827,7 @@ void DBCSignalEditor::generateUsedBits() if (sig->multiplexParent) { if (sig->multiplexParent != currentSignal->multiplexParent) continue; //go thee away! - if (sig->multiplexHighValue != currentSignal->multiplexHighValue) continue; //buzz off - if (sig->multiplexLowValue != currentSignal->multiplexLowValue) continue; + if (!sig->multiplexesIdenticalToSignal(currentSignal)) continue; //buzz off } startBit = sig->startBit; diff --git a/ui/dbcsignaleditor.ui b/ui/dbcsignaleditor.ui index df055dd5..8233d9df 100644 --- a/ui/dbcsignaleditor.ui +++ b/ui/dbcsignaleditor.ui @@ -188,40 +188,39 @@ - Multiplex Low Value + Multiplex value - + - - + + - Comment: + Multiplex Parent - - - - - + + - Multiplex Parent + Comment: - - + + - - + + - Multiplex High Value + Single values has to be separated by semicolons +and the value ranges by hypens +(e.g.: 1;2;5-7) @@ -263,8 +262,7 @@ rbMultiplexed rbMultiplexor rbExtended - txtMultiplexLow - txtMultiplexHigh + txtMultiplexValues cbMultiplexParent txtComment valuesTable diff --git a/utility.h b/utility.h index 01abc3da..66bd539f 100644 --- a/utility.h +++ b/utility.h @@ -190,6 +190,7 @@ class Utility return (double)timestamp / 1000000.0; break; } + return QVariant(); } //parses the input string to grab as much of it as possible while staying alpha numeric