diff --git a/config.h b/config.h index f09c682..9822598 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 202 +#define VERSION 203 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index 904dc2e..89e3f91 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -23,12 +23,19 @@ DBC_SIGNAL::DBC_SIGNAL() factor = 1.0; intelByteOrder = false; parentMessage = nullptr; + multiplexParent = nullptr; receiver = nullptr; signalSize = 1; startBit = 1; valType = DBC_SIG_VAL_TYPE::UNSIGNED_INT; } +DBC_MULTIPLEX::DBC_MULTIPLEX() +{ + lowerBound = 0; + upperBound = 0; + sig = nullptr; +} /* The way that the DBC file format works is kind of weird... For intel format signals you count up diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index a2eb3b9..9c4d98d 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -26,18 +26,19 @@ enum DBC_SIG_VAL_TYPE enum DBC_ATTRIBUTE_VAL_TYPE { - QINT, - QFLOAT, - QSTRING, - ENUM + ATTR_INT, + ATTR_FLOAT, + ATTR_STRING, + ATTR_ENUM, }; enum DBC_ATTRIBUTE_TYPE { - GENERAL, - NODE, - MESSAGE, - SIG + ATTR_TYPE_GENERAL, + ATTR_TYPE_NODE, + ATTR_TYPE_MESSAGE, + ATTR_TYPE_SIG, + ATTR_TYPE_ANY }; class DBC_ATTRIBUTE @@ -82,6 +83,16 @@ public: }; class DBC_MESSAGE; //forward reference so that DBC_SIGNAL can compile before we get to real definition of DBC_MESSAGE +class DBC_SIGNAL; + +class DBC_MULTIPLEX +{ +public: + int lowerBound, upperBound; + DBC_SIGNAL *sig; + + DBC_MULTIPLEX(); +}; class DBC_SIGNAL { @@ -105,6 +116,8 @@ public: //TODO: this is sloppy. It shouldn't all be public! QVariant cachedValue; QList attributes; QList valList; + QList multiplexedChildren; + DBC_SIGNAL *multiplexParent; DBC_SIGNAL(); bool processAsText(const CANFrame &frame, QString &outString, bool outputName = true); diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index 8332958..8d0a188 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -373,12 +373,12 @@ void DBCFile::setAssocBus(int bus) assocBuses = bus; } -DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name) +DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name, DBC_ATTRIBUTE_TYPE type) { if (dbc_attributes.length() == 0) return nullptr; for (int i = 0; i < dbc_attributes.length(); i++) { - if (dbc_attributes[i].name.compare(name, Qt::CaseInsensitive) == 0) + if (dbc_attributes[i].name.compare(name, Qt::CaseInsensitive) == 0 && ((type == dbc_attributes[i].attrType) || (type == ATTR_TYPE_ANY) ) ) { return &dbc_attributes[i]; } @@ -481,11 +481,24 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) } else { - qDebug() << "standard signal"; - regex.setPattern("^SG\\_ *(\\w+) *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); + regex.setPattern("^SG\\_ *(\\w+) +m(\\d+)M *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); match = regex.match(line); - sig.isMultiplexed = false; - sig.isMultiplexor = false; + if (match.hasMatch()) + { + qDebug() << "Extended Multiplexor Signal"; + sig.isMultiplexor = true; //we don't set the local isMultiplexor variable because this isn't the top level multiplexor + sig.isMultiplexed = true; //but, it is both a multiplexor and multiplexed + sig.multiplexValue = match.captured(2).toInt(); + offset = 1; + } + else + { + qDebug() << "standard signal"; + regex.setPattern("^SG\\_ *(\\w+) *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); + match = regex.match(line); + sig.isMultiplexed = false; + sig.isMultiplexor = false; + } } } @@ -566,6 +579,46 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) return nullptr; } +//SG_MUL_VAL_ 2024 S1_PID_0D_VehicleSpeed S1 13-13; +bool DBCFile::parseSignalMultiplexValueLine(QString line) +{ + QRegularExpression regex; + QRegularExpressionMatch match; + + qDebug() << "Found a multiplex definition line"; + regex.setPattern("^SG\\_MUL\\_VAL\\_ (\\d+) (\\w+) (\\w+) (\\d+)\\-(\\d+);"); + match = regex.match(line); + //captured 1 is message ID + //Captured 2 is signal name + //Captured 3 is parent multiplexor + //captured 4 is the lower bound + //captured 5 is the upper bound + if (match.hasMatch()) + { + DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt()); + if (msg != nullptr) + { + DBC_SIGNAL *thisSignal = msg->sigHandler->findSignalByName(match.captured(2)); + if (thisSignal != nullptr) + { + DBC_SIGNAL *parentSignal = msg->sigHandler->findSignalByName(match.captured(3)); + if (parentSignal != nullptr) + { + //now need to add "thisSignal" to the children multiplexed signals of "parentSignal" + DBC_MULTIPLEX mx; + mx.lowerBound = match.captured(4).toInt(); + mx.upperBound = match.captured(5).toInt(); + mx.sig = thisSignal; + parentSignal->multiplexedChildren.append(mx); + thisSignal->multiplexParent = parentSignal; + return true; + } + } + } + } + return false; +} + bool DBCFile::parseValueLine(QString line) { QRegularExpression regex; @@ -732,16 +785,16 @@ bool DBCFile::parseDefaultAttrLine(QString line) { switch (found->valType) { - case QSTRING: + case ATTR_STRING: found->defaultValue = match.captured(2); break; - case QFLOAT: + case ATTR_FLOAT: found->defaultValue = match.captured(2).toFloat(); break; - case QINT: + case ATTR_INT: found->defaultValue = match.captured(2).toInt(); break; - case ENUM: + case ATTR_ENUM: QString temp = match.captured(2); found->defaultValue = 0; for (int x = 0; x < found->enumVals.count(); x++) @@ -825,6 +878,12 @@ bool DBCFile::loadFile(QString fileName) { if (!parseSignalLine(line, currentMessage)) numSigFaults++; } + + if (line.startsWith("SG_MUL_VAL_ ")) //defines a signal multiplexing value definition + { + if (!parseSignalMultiplexValueLine(line)) numSigFaults++; + } + if (line.startsWith("BU_:")) //line specifies the nodes on this canbus { qDebug() << "Found a BU line"; @@ -917,33 +976,46 @@ bool DBCFile::loadFile(QString fileName) if (parseAttribute(line.right(line.length() - 12), attr)) { //qDebug() << "Success"; - attr.attrType = SIG; + attr.attrType = ATTR_TYPE_SIG; dbc_attributes.append(attr); } } - if (line.startsWith("BA_DEF_ BO_ ")) //definition of a message attribute + else if (line.startsWith("BA_DEF_ BO_ ")) //definition of a message attribute { qDebug() << "Found a BO attribute line"; if (parseAttribute(line.right(line.length() - 12), attr)) { qDebug() << "Success"; - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; dbc_attributes.append(attr); } } - if (line.startsWith("BA_DEF_ BU_ ")) //definition of a node attribute + else if (line.startsWith("BA_DEF_ BU_ ")) //definition of a node attribute { qDebug() << "Found a BU attribute line"; if (parseAttribute(line.right(line.length() - 12), attr)) { //qDebug() << "Success"; - attr.attrType = NODE; + attr.attrType = ATTR_TYPE_NODE; dbc_attributes.append(attr); } } + else if (line.startsWith("BA_DEF_ ")) //definition of a root attribute + { + qDebug() << "Found a BU attribute line"; + + if (parseAttribute(line.right(line.length() - 9), attr)) + { + //qDebug() << "Success"; + attr.attrType = ATTR_TYPE_GENERAL; + dbc_attributes.append(attr); + } + } + + if (line.startsWith("BA_DEF_DEF_ ")) //definition of default value for an attribute { parseDefaultAttrLine(line); @@ -961,13 +1033,13 @@ bool DBCFile::loadFile(QString fileName) DBC_ATTRIBUTE *bgAttr = findAttributeByName("GenMsgBackgroundColor"); if (!bgAttr) { - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = QApplication::palette().color(QPalette::Base).name(); attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "GenMsgBackgroundColor"; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; dbc_attributes.append(attr); bgAttr = findAttributeByName("GenMsgBackgroundColor"); } @@ -975,13 +1047,13 @@ bool DBCFile::loadFile(QString fileName) DBC_ATTRIBUTE *fgAttr = findAttributeByName("GenMsgForegroundColor"); if (!fgAttr) { - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = QApplication::palette().color(QPalette::WindowText).name(); attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "GenMsgForegroundColor"; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; dbc_attributes.append(attr); fgAttr = findAttributeByName("GenMsgForegroundColor"); } @@ -1021,6 +1093,22 @@ bool DBCFile::loadFile(QString fileName) thisFG = msg->findAttrValByName("GenMsgForegroundColor"); if (thisBG) msg->bgColor = QColor(thisBG->value.toString()); if (thisFG) msg->fgColor = QColor(thisFG->value.toString()); + for (int y = 0; y < msg->sigHandler->getCount(); y++) + { + DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(y); + //if this doesn't have a multiplex parent set but is multiplexed then it must have used + //simple multiplexing instead of any extended specification. So, fill in the multiplexor signal here + //and also write the extended entry for it too. + if (sig->isMultiplexed && (sig->multiplexParent == nullptr) ) + { + sig->multiplexParent = msg->multiplexorSignal; + DBC_MULTIPLEX mlt; + mlt.sig = sig; + mlt.lowerBound = sig->multiplexValue; + mlt.upperBound = mlt.lowerBound; + msg->multiplexorSignal->multiplexedChildren.append(mlt); + } + } } if (numSigFaults > 0 || numMsgFaults > 0) @@ -1049,14 +1137,14 @@ QVariant DBCFile::processAttributeVal(QString input, DBC_ATTRIBUTE_VAL_TYPE typ) QVariant out; switch (typ) { - case QSTRING: + case ATTR_STRING: out = input; break; - case QFLOAT: + case ATTR_FLOAT: out = input.toFloat(); break; - case QINT: - case ENUM: + case ATTR_INT: + case ATTR_ENUM: out = input.toInt(); break; } @@ -1080,14 +1168,14 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr) qDebug() << "Parsing an attribute with low/high values"; attr.name = match.captured(1); QString typ = match.captured(2); - attr.attrType = SIG; + attr.attrType = ATTR_TYPE_SIG; attr.lower = 0; attr.upper = 0; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; if (!typ.compare("INT", Qt::CaseInsensitive)) { qDebug() << "INT attribute named " << attr.name; - attr.valType = QINT; + attr.valType = ATTR_INT; attr.lower = match.captured(3).toInt(); attr.upper = match.captured(4).toInt(); goodAttr = true; @@ -1095,7 +1183,7 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr) if (!typ.compare("FLOAT", Qt::CaseInsensitive)) { qDebug() << "FLOAT attribute named " << attr.name; - attr.valType = QFLOAT; + attr.valType = ATTR_FLOAT; attr.lower = match.captured(3).toDouble(); attr.upper = match.captured(4).toDouble(); goodAttr = true; @@ -1103,7 +1191,7 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr) if (!typ.compare("STRING", Qt::CaseInsensitive)) { qDebug() << "STRING attribute named " << attr.name; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; goodAttr = true; } } @@ -1119,26 +1207,26 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr) QString typ = match.captured(2); attr.lower = 0; attr.upper = 0; - attr.attrType = SIG; + attr.attrType = ATTR_TYPE_SIG; if (!typ.compare("INT", Qt::CaseInsensitive)) { qDebug() << "INT attribute named " << attr.name; - attr.valType = QINT; + attr.valType = ATTR_INT; goodAttr = true; } if (!typ.compare("FLOAT", Qt::CaseInsensitive)) { qDebug() << "FLOAT attribute named " << attr.name; - attr.valType = QFLOAT; + attr.valType = ATTR_FLOAT; goodAttr = true; } if (!typ.compare("STRING", Qt::CaseInsensitive)) { qDebug() << "STRING attribute named " << attr.name; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; goodAttr = true; } @@ -1151,7 +1239,7 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr) attr.enumVals.append(Utility::unQuote(enumStr)); qDebug() << "Enum value: " << enumStr; } - attr.valType = ENUM; + attr.valType = ATTR_ENUM; goodAttr = true; } } @@ -1378,15 +1466,15 @@ bool DBCFile::saveFile(QString fileName) msgOutput.append("BA_DEF_ "); switch (dbc_attributes[x].attrType) { - case GENERAL: + case ATTR_TYPE_GENERAL: break; - case NODE: + case ATTR_TYPE_NODE: msgOutput.append("BU_ "); break; - case MESSAGE: + case ATTR_TYPE_MESSAGE: msgOutput.append("BO_ "); break; - case SIG: + case ATTR_TYPE_SIG: msgOutput.append("SG_ "); break; } @@ -1395,16 +1483,16 @@ bool DBCFile::saveFile(QString fileName) switch (dbc_attributes[x].valType) { - case QINT: + case ATTR_INT: msgOutput.append("INT " + QString::number(dbc_attributes[x].lower) + " " + QString::number(dbc_attributes[x].upper)); break; - case QFLOAT: + case ATTR_FLOAT: msgOutput.append("FLOAT " + QString::number(dbc_attributes[x].lower) + " " + QString::number(dbc_attributes[x].upper)); break; - case QSTRING: + case ATTR_STRING: msgOutput.append("STRING "); break; - case ENUM: + case ATTR_ENUM: msgOutput.append("ENUM "); foreach (QString str, dbc_attributes[x].enumVals) { @@ -1424,14 +1512,14 @@ bool DBCFile::saveFile(QString fileName) defaultsOutput.append("BA_DEF_DEF_ \"" + dbc_attributes[x].name + "\" "); switch (dbc_attributes[x].valType) { - case QSTRING: + case ATTR_STRING: defaultsOutput.append("\"" + dbc_attributes[x].defaultValue.toString() + "\";\n"); break; - case ENUM: + case ATTR_ENUM: defaultsOutput.append("\"" + dbc_attributes[x].enumVals[dbc_attributes[x].defaultValue.toInt()] + "\";\n"); break; - case QINT: - case QFLOAT: + case ATTR_INT: + case ATTR_FLOAT: defaultsOutput.append(dbc_attributes[x].defaultValue.toString() + ";\n"); break; } @@ -1496,42 +1584,42 @@ int DBCHandler::createBlankFile() DBC_ATTRIBUTE attr; //add our custom attributes to the new file so that we know they're already there. - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = QApplication::palette().color(QPalette::Base).name(); qDebug() << attr.defaultValue; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "GenMsgBackgroundColor"; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; newFile.dbc_attributes.append(attr); - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = QApplication::palette().color(QPalette::WindowText).name(); qDebug() << attr.defaultValue; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "GenMsgForegroundColor"; - attr.valType = QSTRING; + attr.valType = ATTR_STRING; newFile.dbc_attributes.append(attr); - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = 0; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "matchingcriteria"; - attr.valType = QINT; + attr.valType = ATTR_INT; newFile.dbc_attributes.append(attr); - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = 0; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "filterlabeling"; - attr.valType = QINT; + attr.valType = ATTR_INT; newFile.dbc_attributes.append(attr); DBC_NODE falseNode; @@ -1870,24 +1958,24 @@ DBCHandler::DBCHandler() DBC_ATTRIBUTE attr; - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = matchingCriteria; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "matchingcriteria"; - attr.valType = QINT; + attr.valType = ATTR_INT; file->dbc_attributes.append(attr); file->messageHandler->setMatchingCriteria(matchingCriteria); bool filterLabeling = settings.value("DBC/FilterLabeling_" + QString(i),0).toBool(); - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = filterLabeling; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "filterlabeling"; - attr.valType = QINT; + attr.valType = ATTR_INT; file->dbc_attributes.append(attr); file->messageHandler->setFilterLabeling(filterLabeling); diff --git a/dbc/dbchandler.h b/dbc/dbchandler.h index 11bd480..53a9519 100644 --- a/dbc/dbchandler.h +++ b/dbc/dbchandler.h @@ -73,7 +73,7 @@ public: DBCFile& operator=(const DBCFile& cpy); DBC_NODE *findNodeByName(QString name); DBC_NODE *findNodeByIdx(int idx); - DBC_ATTRIBUTE *findAttributeByName(QString name); + DBC_ATTRIBUTE *findAttributeByName(QString name, DBC_ATTRIBUTE_TYPE type = ATTR_TYPE_ANY); DBC_ATTRIBUTE *findAttributeByIdx(int idx); void findAttributesByType(DBC_ATTRIBUTE_TYPE typ, QList *list); bool saveFile(QString); @@ -99,6 +99,7 @@ private: bool parseAttribute(QString inpString, DBC_ATTRIBUTE &attr); QVariant processAttributeVal(QString input, DBC_ATTRIBUTE_VAL_TYPE typ); DBC_SIGNAL* parseSignalLine(QString line, DBC_MESSAGE *msg); + bool parseSignalMultiplexValueLine(QString line); DBC_MESSAGE* parseMessageLine(QString line); bool parseValueLine(QString line); bool parseAttributeLine(QString line); diff --git a/dbc/dbcloadsavewindow.cpp b/dbc/dbcloadsavewindow.cpp index cd47371..8736ef2 100644 --- a/dbc/dbcloadsavewindow.cpp +++ b/dbc/dbcloadsavewindow.cpp @@ -35,7 +35,7 @@ DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector *frames, QWidget *p { DBCFile * file = dbcHandler->getFileByIdx(idx); ui->tableFiles->insertRow(ui->tableFiles->rowCount()); - ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(file->getFullFilename())); + ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(file->getFilename())); QString bus = QString::number(file->getAssocBus() ); ui->tableFiles->setItem(idx, 1, new QTableWidgetItem(bus)); @@ -189,7 +189,7 @@ void DBCLoadSaveWindow::loadFile() inhibitCellProcessing=true; int idx = ui->tableFiles->rowCount(); ui->tableFiles->insertRow(ui->tableFiles->rowCount()); - ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(file->getFullFilename())); + ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(file->getFilename())); ui->tableFiles->setItem(idx, 1, new QTableWidgetItem("-1")); DBC_ATTRIBUTE *attr = file->findAttributeByName("matchingcriteria"); @@ -227,7 +227,7 @@ void DBCLoadSaveWindow::saveFile() if (idx < 0) return; dbcHandler->saveDBCFile(idx); //then update the list to show the new file name (if it changed) - ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(dbcHandler->getFileByIdx(idx)->getFullFilename())); + ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(dbcHandler->getFileByIdx(idx)->getFilename())); } void DBCLoadSaveWindow::removeFile() @@ -305,13 +305,13 @@ void DBCLoadSaveWindow::matchingCriteriaChanged(int index) { DBC_ATTRIBUTE attr; - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = matchingCriteria; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "matchingcriteria"; - attr.valType = QINT; + attr.valType = ATTR_INT; file->dbc_attributes.append(attr); file->messageHandler->setMatchingCriteria(matchingCriteria); } @@ -351,13 +351,13 @@ void DBCLoadSaveWindow::cellChanged(int row, int col) { DBC_ATTRIBUTE attr; - attr.attrType = MESSAGE; + attr.attrType = ATTR_TYPE_MESSAGE; attr.defaultValue = labelFilters ? 1 : 0; attr.enumVals.clear(); attr.lower = 0; attr.upper = 0; attr.name = "labelfilters"; - attr.valType = QINT; + attr.valType = ATTR_INT; file->dbc_attributes.append(attr); file->messageHandler->setFilterLabeling(labelFilters); } diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index 76dd76c..9c50ffa 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -230,6 +230,19 @@ void DBCMainEditor::currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem } } +uint32_t DBCMainEditor::getParentMessageID(QTreeWidgetItem *cell) +{ + if (cell->data(0, Qt::UserRole) == 2) + { + return static_cast(Utility::ParseStringToNum(cell->text(0).split(" ")[0])); + } + else + { + if (cell->parent()) return getParentMessageID(cell->parent()); + else return 0; + } +} + //Double clicking is interpreted as a desire to edit the given item. void DBCMainEditor::onTreeDoubleClicked(const QModelIndex &index) { @@ -266,16 +279,21 @@ void DBCMainEditor::onTreeDoubleClicked(const QModelIndex &index) msgEditor->show(); //show allows the rest of the forms to keep going break; case 3: //a signal - idString = firstCol->parent()->text(0).split(" ")[0]; - msgID = static_cast(Utility::ParseStringToNum(idString)); + msgID = getParentMessageID(firstCol); msg = dbcFile->messageHandler->findMsgByID(msgID); - sig = msg->sigHandler->findSignalByName(firstCol->text(0).split(" ")[0]); - sigEditor->setSignalRef(sig); - sigEditor->setMessageRef(msg); - sigEditor->setFileIdx(fileIdx); - //sigEditor->setWindowModality(Qt::WindowModal); - sigEditor->refreshView(); - sigEditor->show(); + QString nameString = firstCol->text(0); + if (nameString.contains("(")) nameString = nameString.split(" ")[1]; + else nameString = nameString.split(" ")[0]; + sig = msg->sigHandler->findSignalByName(nameString); + if (sig) + { + sigEditor->setSignalRef(sig); + sigEditor->setMessageRef(msg); + sigEditor->setFileIdx(fileIdx); + //sigEditor->setWindowModality(Qt::WindowModal); + sigEditor->refreshView(); + sigEditor->show(); + } break; } } @@ -330,16 +348,8 @@ void DBCMainEditor::refreshTree() for (int i = 0; i < msg->sigHandler->getCount(); i++) { DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(i); - QTreeWidgetItem *sigItem = new QTreeWidgetItem(msgItem); - QString sigInfo = sig->name; - if (sig->comment.count() > 0) sigInfo.append(" - ").append(sig->comment); - sigItem->setText(0, sigInfo); - if (sig->isMultiplexed) sigItem->setIcon(0, multiplexedSignalIcon); - else if (sig->isMultiplexor) sigItem->setIcon(0, multiplexorSignalIcon); - else sigItem->setIcon(0, signalIcon); - sigItem->setData(0, Qt::UserRole, 3); - signalToItem.insert(sig, sigItem); - itemToSignal.insert(sigItem, sig); + //only process signals here which are "top" level + if (sig->multiplexParent == nullptr) processSignalToTree(msgItem, sig); } } } @@ -348,6 +358,39 @@ void DBCMainEditor::refreshTree() ui->treeDBC->sortItems(0, Qt::SortOrder::AscendingOrder); //sort the display list for ease in viewing by mere mortals, helps me a lot. } +QString DBCMainEditor::createSignalText(DBC_SIGNAL *sig) +{ + QString sigInfo; + if (sig->isMultiplexed) + { + sigInfo = "(" + QString::number(sig->multiplexValue) + ") "; + } + sigInfo.append(sig->name); + if (sig->comment.count() > 0) sigInfo.append(" - ").append(sig->comment); + return sigInfo; +} + +//Signals can have a hierarchial relationship with other signals so this function is separate and calls itself recursively to build the tree +void DBCMainEditor::processSignalToTree(QTreeWidgetItem *parent, DBC_SIGNAL *sig) +{ + QTreeWidgetItem *sigItem = new QTreeWidgetItem(parent); + QString sigInfo = createSignalText(sig); + sigItem->setText(0, sigInfo); + if (sig->isMultiplexor) sigItem->setIcon(0, multiplexorSignalIcon); + else if (sig->isMultiplexed) sigItem->setIcon(0, multiplexedSignalIcon); + else sigItem->setIcon(0, signalIcon); + sigItem->setData(0, Qt::UserRole, 3); + signalToItem.insert(sig, sigItem); + itemToSignal.insert(sigItem, sig); + if (sig->multiplexedChildren.count() > 0) + { + for (int i = 0; i < sig->multiplexedChildren.count(); i++) + { + processSignalToTree(sigItem, sig->multiplexedChildren[i].sig); + } + } +} + void DBCMainEditor::updatedNode(DBC_NODE *node) { if (nodeToItem.contains(node)) @@ -403,8 +446,7 @@ void DBCMainEditor::updatedSignal(DBC_SIGNAL *sig) if (signalToItem.contains(sig)) { QTreeWidgetItem *item = signalToItem.value(sig); - QString sigInfo = sig->name; - if (sig->comment.count() > 0) sigInfo.append(" - ").append(sig->comment); + QString sigInfo = createSignalText(sig); item->setText(0, sigInfo); } else qDebug() << "That signal doesn't exist. That's a bug dude."; diff --git a/dbc/dbcmaineditor.h b/dbc/dbcmaineditor.h index 02e8e1f..bfc3acd 100644 --- a/dbc/dbcmaineditor.h +++ b/dbc/dbcmaineditor.h @@ -76,6 +76,9 @@ private: void readSettings(); void writeSettings(); void refreshTree(); + void processSignalToTree(QTreeWidgetItem *parent, DBC_SIGNAL *sig); + uint32_t getParentMessageID(QTreeWidgetItem *cell); + QString createSignalText(DBC_SIGNAL *sig); }; #endif // DBCMAINEDITOR_H diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index c02fdac..1cde239 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -190,6 +190,22 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : //TODO: could look up the multiplexor and ensure that the value is within a range that the multiplexor could return currentSignal->multiplexValue = temp; }); + + connect(ui->rbExtended, &QRadioButton::toggled, + [=](bool state) + { + if (state && currentSignal) //signal is now set as an extended multiplex/multiplexor + { + currentSignal->isMultiplexed = true; + 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->txtMultiplexValue->setEnabled(currentSignal->isMultiplexed); + ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); + dbcFile->setDirtyFlag(); + }); + connect(ui->rbMultiplexed, &QRadioButton::toggled, [=](bool state) { @@ -200,6 +216,8 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : //if the set multiplexor for the message was this signal then clear it if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr; } + ui->txtMultiplexValue->setEnabled(currentSignal->isMultiplexed); + ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); dbcFile->setDirtyFlag(); }); @@ -215,6 +233,8 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : //we just set that this is the multiplexor so update the message to show that as well. dbcMessage->multiplexorSignal = currentSignal; } + ui->txtMultiplexValue->setEnabled(currentSignal->isMultiplexed); + ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); dbcFile->setDirtyFlag(); }); @@ -227,9 +247,42 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : currentSignal->isMultiplexor = false; if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr; } + ui->txtMultiplexValue->setEnabled(currentSignal->isMultiplexed); + ui->cbMultiplexParent->setEnabled(currentSignal->isMultiplexed); dbcFile->setDirtyFlag(); }); + connect(ui->cbMultiplexParent, &QComboBox::currentTextChanged, + [=]() + { + //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()); + DBC_SIGNAL *oldParent = currentSignal->multiplexParent; + int low = currentSignal->multiplexValue; + int high = low; + if (newSig) + { + for (int i = 0; i < oldParent->multiplexedChildren.count(); i++) + { + if (oldParent->multiplexedChildren[i].sig == currentSignal) + { + low = oldParent->multiplexedChildren[i].lowerBound; + high = oldParent->multiplexedChildren[i].upperBound; + oldParent->multiplexedChildren.removeAt(i); + break; + } + } + currentSignal->multiplexParent = newSig; + DBC_MULTIPLEX mlt; + mlt.lowerBound = low; + mlt.upperBound = high; + mlt.sig = currentSignal; + newSig->multiplexedChildren.append(mlt); + dbcFile->setDirtyFlag(); + } + }); + installEventFilter(this); } @@ -413,11 +466,37 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) ui->txtMinVal->setText(QString::number(sig->min)); ui->txtScale->setText(QString::number(sig->factor)); ui->txtUnitName->setText(sig->unitName); - ui->rbMultiplexed->setChecked(sig->isMultiplexed); - ui->rbMultiplexor->setChecked(sig->isMultiplexor); - ui->rbNotMulti->setChecked( !(sig->isMultiplexor | sig->isMultiplexed) ); + if (sig->isMultiplexed && sig->isMultiplexor) + { + ui->rbMultiplexed->setChecked(false); + ui->rbMultiplexor->setChecked(false); + ui->rbNotMulti->setChecked(false); + ui->rbExtended->setChecked(true); + } + else + { + ui->rbMultiplexed->setChecked(sig->isMultiplexed); + ui->rbMultiplexor->setChecked(sig->isMultiplexor); + ui->rbNotMulti->setChecked( !(sig->isMultiplexor | sig->isMultiplexed) ); + } qDebug() << sig->isMultiplexor << "*" << sig->isMultiplexed; + ui->cbMultiplexParent->clear(); + + int numSigs = dbcMessage->sigHandler->getCount(); + for (int i = 0; i < numSigs; i++) + { + DBC_SIGNAL *sig_iter = dbcMessage->sigHandler->findSignalByIdx(i); + if (sig_iter->isMultiplexor && (sig_iter != sig)) + { + ui->cbMultiplexParent->addItem(sig_iter->name); + if (sig->multiplexParent == sig_iter) ui->cbMultiplexParent->setCurrentIndex(ui->cbMultiplexParent->count() - 1); + } + } + + ui->txtMultiplexValue->setEnabled(sig->isMultiplexed); + ui->cbMultiplexParent->setEnabled(sig->isMultiplexed); + memset(bitpattern, 0, 8); //clear it out first. int startBit, endBit; diff --git a/ui/dbcsignaleditor.ui b/ui/dbcsignaleditor.ui index 4a1d45c..7d15ee7 100644 --- a/ui/dbcsignaleditor.ui +++ b/ui/dbcsignaleditor.ui @@ -160,7 +160,7 @@ - Not multiplexed + None @@ -178,6 +178,13 @@ + + + + Extended + + + @@ -190,16 +197,26 @@ - + Comment: - + + + + + + + + Multiplex Parent + + +