diff --git a/canframemodel.cpp b/canframemodel.cpp index 3edcdeb..7724912 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -508,19 +508,25 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const tempString.append(" <" + msg->name + ">\n"); if (msg->comment.length() > 1) tempString.append(msg->comment + "\n"); for (int j = 0; j < msg->sigHandler->getCount(); j++) - { + { QString sigString; DBC_SIGNAL* sig = msg->sigHandler->findSignalByIdx(j); - if (sig->processAsText(thisFrame, sigString)) + + if ( (sig->multiplexParent == nullptr) && sig->processAsText(thisFrame, sigString)) { tempString.append(sigString); tempString.append("\n"); + if (sig->isMultiplexor) + { + qDebug() << "Multiplexor. Diving into the tree"; + tempString.append(sig->processSignalTree(thisFrame)); + } } - else if (sig->isMultiplexed && overwriteDups) //wasn't in this exact frame but is in the message. Use cached value - { - tempString.append(sig->makePrettyOutput(sig->cachedValue.toDouble(), sig->cachedValue.toLongLong())); - tempString.append("\n"); - } + //else if (sig->isMultiplexed && overwriteDups) //wasn't in this exact frame but is in the message. Use cached value + //{ + // tempString.append(sig->makePrettyOutput(sig->cachedValue.toDouble(), sig->cachedValue.toLongLong())); + // tempString.append("\n"); + //} } } } diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index 0d2da92..2ae9506 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -31,6 +31,65 @@ DBC_SIGNAL::DBC_SIGNAL() valType = DBC_SIG_VAL_TYPE::UNSIGNED_INT; } +bool DBC_SIGNAL::isSignalInMessage(const CANFrame &frame) +{ + if (isMultiplexor && !isMultiplexed) return true; //the root multiplexor is always in the message. + if (isMultiplexed) + { + if (parentMessage->multiplexorSignal != nullptr) + { + return _sigInMsgPriv(frame, parentMessage->multiplexorSignal); + } + else return false; + } + else return true; +} + +bool DBC_SIGNAL::_sigInMsgPriv(const CANFrame &frame, DBC_SIGNAL *multiplexor) +{ + int val; + if (!multiplexor->processAsInt(frame, val)) return false; + foreach (DBC_SIGNAL *child, multiplexedChildren) + { + if ((val >= child->multiplexLowValue) && (val <= child->multiplexHighValue)) + { + if (child->isMultiplexor) return _sigInMsgPriv(frame, child); //recurse down a level and keep searching + if (child == this) return true; //if we are that child then we matched! + } + } + return false; //signal not found in this message +} + +//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) +{ + QString build; + int val; + if (!this->processAsInt(frame, val)) return build; + qDebug() << val; + + foreach (DBC_SIGNAL *sig, multiplexedChildren) + { + if ( (val >= sig->multiplexLowValue) && (val <= sig->multiplexHighValue) ) + { + qDebug() << "Found match for multiplex value range - " << sig->name; + QString sigString; + if (sig->processAsText(frame, sigString)) + { + qDebug() << "Returned value: " << sigString; + build.append(sigString); + build.append("\n"); + if (sig->isMultiplexor) + { + qDebug() << "Spelunkin!"; + build.append(sig->processSignalTree(frame)); + } + } + } + } + return build; +} + /* The way that the DBC file format works is kind of weird... For intel format signals you count up from the start bit to the end bit which is (startbit + signallength - 1). At each point @@ -67,6 +126,8 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString, bool o bool isInteger = false; double endResult; + //if (!isSignalInMessage(frame)) return false; + if (valType == STRING) { QString buildString; @@ -78,18 +139,6 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString, bool o return true; } - //if this is a multiplexed signal then we have to see if it is even found in the current message - if (isMultiplexed) - { - if (parentMessage->multiplexorSignal != nullptr) - { - int val; - if (!parentMessage->multiplexorSignal->processAsInt(frame, val)) return false; - if (val != multiplexLowValue) return false; //signal not found in this message - } - else return false; - } - if (valType == SIGNED_INT) isSigned = true; if (valType == SIGNED_INT || valType == UNSIGNED_INT) { @@ -164,22 +213,13 @@ bool DBC_SIGNAL::processAsInt(const CANFrame &frame, int32_t &outValue) { int32_t result = 0; bool isSigned = false; + if (valType == STRING || valType == SP_FLOAT || valType == DP_FLOAT) { return false; } - //if this is a multiplexed signal then we have to see if it is even found in the current message - if (isMultiplexed) - { - if (parentMessage->multiplexorSignal != nullptr) - { - int val; - if (!parentMessage->multiplexorSignal->processAsInt(frame, val)) return false; - if (val != multiplexLowValue) return false; //signal not found in this message - } - else return false; - } + //if (!isSignalInMessage(frame)) return false; if (valType == SIGNED_INT) isSigned = true; if ( static_cast(frame.payload().length() * 8) < (startBit + signalSize) ) @@ -212,17 +252,7 @@ bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue) return false; } - //if this is a multiplexed signal then we have to see if it is even found in the current message - if (isMultiplexed) - { - if (parentMessage->multiplexorSignal != nullptr) - { - int val; - if (!parentMessage->multiplexorSignal->processAsInt(frame, val)) return false; - if (val != multiplexLowValue) return false; //signal not found in this message - } - else return false; - } + //if (!isSignalInMessage(frame)) return false; if (valType == SIGNED_INT) isSigned = true; if (valType == SIGNED_INT || valType == UNSIGNED_INT) diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index ca20eb1..1054a42 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -116,6 +116,7 @@ public: //TODO: this is sloppy. It shouldn't all be public! bool processAsInt(const CANFrame &frame, int32_t &outValue); bool processAsDouble(const CANFrame &frame, double &outValue); QString makePrettyOutput(double floatVal, int64_t intVal, bool outputName = true, bool isInteger = false); + QString processSignalTree(const CANFrame &frame); DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name); DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx); @@ -123,6 +124,9 @@ public: //TODO: this is sloppy. It shouldn't all be public! { return (l.name.toLower() < r.name.toLower()); } +private: + bool isSignalInMessage(const CANFrame &frame); + bool _sigInMsgPriv(const CANFrame &frame, DBC_SIGNAL *multiplexor); }; 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 38cac3f..0f09628 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -1250,6 +1250,7 @@ bool DBCFile::saveFile(QString fileName) QFile *outFile = new QFile(fileName); QString nodesOutput, msgOutput, commentsOutput, valuesOutput; QString defaultsOutput, attrValOutput; + bool hasExtendedMultiplexing = false; if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -1380,11 +1381,18 @@ bool DBCFile::saveFile(QString fileName) msgOutput.append(" SG_ " + sig->name); - if (sig->isMultiplexor) msgOutput.append(" M"); if (sig->isMultiplexed) { msgOutput.append(" m" + QString::number(sig->multiplexLowValue)); } + if (sig->isMultiplexor) + { + if (!sig->isMultiplexed) msgOutput.append(" "); + msgOutput.append("M"); + } + //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; msgOutput.append(" : " + QString::number(sig->startBit) + "|" + QString::number(sig->signalSize) + "@"); @@ -1521,6 +1529,32 @@ bool DBCFile::saveFile(QString fileName) } } + //extended multiplexing uses SG_MUL_VAL_ to specify the relationships. If a signal is marked + //as multiplexed then output a record for it. That's the most complete option. We've already + //given the single value multiplex above for backward compatibility with things that don't support extended mode + if (hasExtendedMultiplexing) + { + for (int x = 0; x < messageHandler->getCount(); x++) + { + DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x); + + for (int s = 0; s < msg->sigHandler->getCount(); s++) + { + DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(s); + + if (sig->isMultiplexed) + { + msgOutput.append("SG_MUL_VAL_ " + QString::number(msg->ID) + " "); + msgOutput.append(sig->name + " " + sig->parentMessage->name + " "); + msgOutput.append(QString::number(sig->multiplexLowValue) + "-" + QString::number(sig->multiplexHighValue) + ";"); + msgOutput.append("\n"); + outFile->write(msgOutput.toUtf8()); + msgOutput.clear(); //got to reset it after writing + } + } + } + } + //now write out all of the accumulated comments and value tables from above outFile->write(attrValOutput.toUtf8()); outFile->write(defaultsOutput.toUtf8()); diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index 356f60f..571956a 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -450,6 +450,27 @@ void DBCMainEditor::updatedSignal(DBC_SIGNAL *sig) QTreeWidgetItem *item = signalToItem.value(sig); QString sigInfo = createSignalText(sig); item->setText(0, sigInfo); + if (sig->isMultiplexed) + { + if (item->parent()->data(0, Qt::UserRole).toInt() == 3) //if our parent is another signal + { + QString nameString = item->parent()->text(0); + if (nameString.contains("(")) nameString = nameString.split(" ")[1]; + else nameString = nameString.split(" ")[0]; + DBC_SIGNAL *oldParent = sig->parentMessage->sigHandler->findSignalByName(nameString); + if (oldParent && (oldParent != sig->multiplexParent)) + { + qDebug() << "You changed the signal's parent"; + QTreeWidgetItem *newParent = nullptr; + newParent = signalToItem.value(sig->multiplexParent); + QTreeWidgetItem *prevParent = signalToItem.value(oldParent); + prevParent->removeChild(item); + newParent->addChild(item); + ui->treeDBC->setCurrentItem(item); + ui->treeDBC->sortItems(0, Qt::AscendingOrder); //resort because we just moved an item + } + } + } } else qDebug() << "That signal doesn't exist. That's a bug dude."; } diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index d20a4b5..cea4f53 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -19,6 +19,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : dbcHandler = DBCHandler::getReference(); dbcMessage = nullptr; currentSignal = nullptr; + inhibitMsgProc = false; QStringList headers2; headers2 << "Value" << "Text"; @@ -267,9 +268,12 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : dbcFile->setDirtyFlag(); }); - connect(ui->cbMultiplexParent, &QComboBox::currentTextChanged, + connect(ui->cbMultiplexParent, &QComboBox::textActivated, [=]() { + if (currentSignal == nullptr) return; + if (inhibitMsgProc) return; + //qDebug() << "Curr text: :" << ui->cbMultiplexParent->currentText(); //try to look up the signal that we're set to now, remove this signal from existing children list //add it to this one, update this signal's parent multiplexor DBC_SIGNAL *newSig = dbcMessage->sigHandler->findSignalByName(ui->cbMultiplexParent->currentText()); @@ -280,6 +284,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : currentSignal->multiplexParent = newSig; newSig->multiplexedChildren.append(currentSignal); dbcFile->setDirtyFlag(); + emit updatedTreeInfo(currentSignal); } }); @@ -431,6 +436,8 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) { unsigned char bitpattern[8]; + inhibitMsgProc = true; + if (sig == nullptr) { ui->groupBox->setEnabled(false); ui->txtName->setText(""); @@ -451,6 +458,7 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) ui->bitfield->updateData(bitpattern, true); ui->comboReceiver->setCurrentIndex(0); ui->comboType->setCurrentIndex(0); + inhibitMsgProc = false; return; } @@ -489,7 +497,7 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) for (int i = 0; i < numSigs; i++) { DBC_SIGNAL *sig_iter = dbcMessage->sigHandler->findSignalByIdx(i); - if (sig_iter->isMultiplexor && (sig_iter != sig)) + if (sig_iter && sig_iter->isMultiplexor && (sig_iter != sig)) { ui->cbMultiplexParent->addItem(sig_iter->name); if (sig->multiplexParent == sig_iter) ui->cbMultiplexParent->setCurrentIndex(ui->cbMultiplexParent->count() - 1); @@ -565,6 +573,8 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) break; } } + + inhibitMsgProc = false; } /* fillValueTable also handles "enabled" state */ diff --git a/dbc/dbcsignaleditor.h b/dbc/dbcsignaleditor.h index 0c69ea3..37f5e6d 100644 --- a/dbc/dbcsignaleditor.h +++ b/dbc/dbcsignaleditor.h @@ -38,6 +38,7 @@ private: DBC_SIGNAL *currentSignal; DBCFile *dbcFile; bool inhibitCellChanged; + bool inhibitMsgProc; void fillSignalForm(DBC_SIGNAL *sig); void fillValueTable(DBC_SIGNAL *sig);