From bba4fccac63a4b3e41f8b0f4b2ff9dde7bffa186 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Tue, 24 Aug 2021 22:28:32 -0400 Subject: [PATCH] Vast change to CAN data grid to show signal names. Many graphical tweaks, some bug fixes. --- candatagrid.cpp | 81 +++++++++++++++--- dbc/dbchandler.cpp | 171 +++++++++++++++++++++++++++++++++++++- dbc/dbchandler.h | 1 + dbc/dbcloadsavewindow.cpp | 6 ++ dbc/dbcmaineditor.cpp | 4 +- dbc/dbcsignaleditor.cpp | 17 +++- 6 files changed, 262 insertions(+), 18 deletions(-) diff --git a/candatagrid.cpp b/candatagrid.cpp index 15afe31..a879ba1 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -67,7 +67,7 @@ GridTextState CANDataGrid::getCellTextState(int x, int y) void CANDataGrid::setSignalNames(int sigIdx, const QString sigName) { if (sigIdx < 0) return; - if (sigIdx > signalNames.size()) + if (sigIdx >= signalNames.size()) { signalNames.resize(sigIdx * 2); } @@ -104,7 +104,10 @@ void CANDataGrid::paintEvent(QPaintEvent *event) unsigned char prevByte, thisByte; bool thisBit, prevBit; QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush; + QBrush greenHashBrush, blackHashBrush; QPainter painter(this); + int usedSigNum; + QString prevSigName; //if this is true then generate unique colors for each signal if ((signalColors.count() == 0) && (signalNames.count() > 0)) @@ -115,7 +118,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) { QColor newColor; while (newColor.saturation() < 40) - newColor.setRgb(QRandomGenerator::global()->bounded(160),QRandomGenerator::global()->bounded(160), QRandomGenerator::global()->bounded(160)); + newColor.setRgb(QRandomGenerator::global()->bounded(160) + 60,QRandomGenerator::global()->bounded(160) + 60, QRandomGenerator::global()->bounded(160) + 60); qDebug() << newColor; signalColors[i] = newColor; } @@ -135,6 +138,8 @@ void CANDataGrid::paintEvent(QPaintEvent *event) whiteBrush = QBrush(Qt::white); redBrush = QBrush(Qt::red); greenBrush = QBrush(Qt::green); + greenHashBrush = QBrush(QColor(0, 0xB6, 0), Qt::BDiagPattern); + blackHashBrush = QBrush(QColor(0, 0, 0), Qt::FDiagPattern); grayBrush = QBrush(QColor(230,230,230)); //the whole thing is broken up into 81 chunks which are broken up @@ -142,7 +147,8 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //taken up by helper text double bigTextSize = qMin(xSector, ySector) * 0.5; - double smallTextSize = qMin(xSector, ySector) * 0.3; + double smallTextSize = qMin(xSector, ySector) * 0.25; + double sigNameTextSize = qMin(xSector, ySector) * 0.19; painter.setPen(QPen(QApplication::palette().color(QPalette::Text))); QFont mainFont; @@ -153,7 +159,10 @@ void CANDataGrid::paintEvent(QPaintEvent *event) QFont boldFont; boldFont.setPixelSize(bigTextSize); boldFont.setBold(true); + QFont sigNameFont; + sigNameFont.setPixelSize(sigNameTextSize); + QFontMetrics smallMetric(sigNameFont); painter.setFont(smallFont); painter.drawText(QRect(viewport.left(), viewport.top(), xSector, ySector), Qt::AlignCenter, "BITS ->"); @@ -189,7 +198,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //bits that used to be set but now are unset are red, bits that used to be unset but now are set //are green - painter.setPen(QPen(Qt::gray)); + painter.setPen(QPen(Qt::black)); painter.setFont(mainFont); for (y = 0; y < 8; y++) @@ -208,11 +217,13 @@ void CANDataGrid::paintEvent(QPaintEvent *event) { if (prevBit) { - painter.setBrush(blackBrush); + if (signalColors.count() > 0) painter.setBrush(blackHashBrush); + else painter.setBrush(blackBrush); } else { - painter.setBrush(greenBrush); + if (signalColors.count() > 0) painter.setBrush(greenHashBrush); + else painter.setBrush(greenBrush); } } else @@ -223,9 +234,10 @@ void CANDataGrid::paintEvent(QPaintEvent *event) } else { + usedSigNum = -1; if ((usedData[y] & (1 << (7-x))) == (1 << (7-x))) { - int usedSigNum = getUsedSignalNum(bit); + usedSigNum = getUsedSignalNum(bit); if (usedSigNum == -1) { grayBrush = QBrush(QColor(0xB6, 0xB6, 0xB6), Qt::BDiagPattern); @@ -241,8 +253,9 @@ void CANDataGrid::paintEvent(QPaintEvent *event) painter.drawRect(viewport.left() + (x+1) * xSector, viewport.top() + (y+1) * ySector, xSector, ySector); switch (textStates[x][y]) { - case GridTextState::NORMAL: - painter.setPen(QPen(Qt::gray)); + case GridTextState::NORMAL: + //if (thisBit && prevBit) painter.setPen(QPen(Qt::gray)); + /*else*/ painter.setPen(QPen(Qt::black)); painter.setFont(mainFont); break; case GridTextState::BOLD_BLUE: @@ -256,14 +269,56 @@ void CANDataGrid::paintEvent(QPaintEvent *event) break; } //change style of bit number output for current signal - if (thisBit) painter.setFont(boldFont); - else painter.setFont(mainFont); + //if (thisBit) painter.setFont(boldFont); + // else painter.setFont(mainFont); + painter.setFont(smallFont); + + painter.drawText(viewport.left() + (x+1) * xSector + (xSector / 8), viewport.top() + (y + 2) * ySector - (ySector * 0.7), QString::number(bit)); - painter.drawText(viewport.left() + (x+1) * xSector + (xSector / 8), viewport.top() + (y + 2) * ySector - (ySector / 3), QString::number(bit)); painter.setFont(mainFont); - painter.setPen(QPen(Qt::gray)); + painter.setPen(QPen(Qt::black)); } } + + //now if signal names are loaded we'll go through all the bits again and try to label over top of the grid + if (signalNames.count() > 0) + { + painter.setFont(sigNameFont); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + bit = (y * 8) + (7 - x); + usedSigNum = -1; + if ((usedData[y] & (1 << (7-x))) == (1 << (7-x))) + { + usedSigNum = getUsedSignalNum(bit); + if (prevSigName != signalNames[usedSigNum]) + { + prevSigName = signalNames[usedSigNum]; + + int textWidth = smallMetric.horizontalAdvance(prevSigName); + + if (textWidth > xSector) //signal name is too long for a single cell. Try to wrap it + { + int numAvgChars = xSector / smallMetric.averageCharWidth(); + painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.4), prevSigName.left(numAvgChars - 1)); + QString remainder = prevSigName.mid(numAvgChars - 1, -1); + textWidth = smallMetric.horizontalAdvance(prevSigName); + if (textWidth > xSector) + { + painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.2), remainder.left(numAvgChars - 1)); + + } + else painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.2), remainder); + } + else painter.drawText(viewport.left() + (x+1) * xSector, viewport.top() + (y + 2) * ySector - (ySector * 0.4), prevSigName); + } + } + } + } + } + upperLeft.setX(viewport.left() + 1 * xSector); upperLeft.setY(viewport.top() + 1 * ySector); gridSize.setX(xSector); diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index 06668ec..3bbfe01 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -1717,6 +1717,176 @@ DBCFile* DBCHandler::loadDBCFile(int idx) return nullptr; } +DBCFile* DBCHandler::loadSecretCSVFile(QString filename) +{ + DBCFile *thisFile; + DBC_MESSAGE *pMsg; + DBC_SIGNAL *pSig; + QByteArray line; + int lineCounter = 0; + createBlankFile(); + thisFile = &loadedFiles.last(); + + QFile *inFile = new QFile(filename); + + if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) + { + delete inFile; + return nullptr; + } + + //burn first two lines. contains header + line = inFile->readLine().simplified().toUpper(); + line = inFile->readLine().simplified().toUpper(); + + while (!inFile->atEnd()) + { + lineCounter++; + if (lineCounter > 100) + { + qApp->processEvents(); + lineCounter = 0; + } + line = inFile->readLine().simplified().toUpper(); + qDebug() << line; + + QList tokens = line.split(','); + if (tokens.length() == 10) + { + //Message,CAN ID,Signal,Short Name,Start Byte,Start Bit,Len,Data,Range,Conversion + //Whl_Rotational_Stat_CheckVal_CE,$0C0,Wheel Rotational Status Check Data,WhlRotatStatChkData, 0, 7, 40,PKT,N/A,N/A + // 0 1 2 3 4 5 6 7 8 9 + if (tokens[0].length() > 2) //start of a signal def that starts a new message + { + DBC_MESSAGE msg; + msg.name = tokens[0]; + msg.ID = tokens[1].mid(1).toLong(nullptr, 16); + msg.comment = ""; + msg.len = 8; + msg.sender = thisFile->findNodeByIdx(0); + msg.bgColor = QColor(thisFile->findAttributeByName("GenMsgBackgroundColor")->defaultValue.toString()); + msg.fgColor = QColor(thisFile->findAttributeByName("GenMsgForegroundColor")->defaultValue.toString()); + thisFile->messageHandler->addMessage(msg); + pMsg = thisFile->messageHandler->findMsgByID(msg.ID); + + DBC_SIGNAL sig; + sig.parentMessage = pMsg; + sig.name = tokens[3]; + sig.comment = tokens[2]; + int startBit = (tokens[4].toInt() * 8) + tokens[5].toInt(); + sig.startBit = startBit; + sig.signalSize = tokens[6].toInt(); + sig.intelByteOrder = false; //always for global-a? + sig.receiver = thisFile->findNodeByIdx(0); + QList rangeToks = tokens[8].split('-'); + if (rangeToks.length() == 2) + { + sig.min = rangeToks[0].simplified().toDouble(); + sig.max = rangeToks[1].simplified().toDouble(); + } + if (tokens[9].startsWith("E = N")) //not a value table, instead do scaling and bias + { + QList scalingToks = tokens[9].simplified().split(' '); + sig.factor = scalingToks[4].toDouble(); + if (scalingToks.count() > 5) + { + if (scalingToks[5] == "+") + { + sig.bias = scalingToks[6].toDouble(); + } + if (scalingToks[5] == "-") + { + sig.bias = scalingToks[6].toDouble() * 1.0; + } + } + else + { + sig.factor = 1; + sig.bias = 0; + } + } + else if (tokens[9].startsWith("$")) //one or more values table entries + { + //$0=Inactive + QList valToks = tokens[9].simplified().mid(1).split('='); + DBC_VAL_ENUM_ENTRY entry; + entry.value = valToks[0].toInt(); + entry.descript = valToks[1]; + sig.valList.append(entry); + } + pMsg->sigHandler->addSignal(sig); + pSig = pMsg->sigHandler->findSignalByIdx(pMsg->sigHandler->getCount()-1); + } + // 0 1 2 3 4 5 6 7 8 9 + //Message,CAN ID,Signal,Short Name,Start Byte,Start Bit,Len,Data,Range,Conversion + //,,Wheel Rotational Status Check Data : Left Driven Sequence Number,WRSCD_LftDrvnSqNm, 0, 7, 2,UNM,0 - 3 ,E = N * 1 + // 2 3 4 5 6 7 8 9 + else if (tokens[2].length() > 2) //signal definition continuation of previous message + { + DBC_SIGNAL sig; + sig.parentMessage = pMsg; + sig.name = tokens[3]; + sig.comment = tokens[2]; + int startBit = (tokens[4].toInt() * 8) + tokens[5].toInt(); + sig.startBit = startBit; + sig.signalSize = tokens[6].toInt(); + sig.intelByteOrder = false; //always for global-a? + sig.receiver = thisFile->findNodeByIdx(0); + QList rangeToks = tokens[8].split('-'); + if (rangeToks.length() == 2) + { + sig.min = rangeToks[0].simplified().toDouble(); + sig.max = rangeToks[1].simplified().toDouble(); + } + if (tokens[9].startsWith("E = N")) //not a value table, instead do scaling and bias + { + QList scalingToks = tokens[9].simplified().split(' '); + sig.factor = scalingToks[4].toDouble(); + if (scalingToks.count() > 5) + { + if (scalingToks[5] == "+") + { + sig.bias = scalingToks[6].toDouble(); + } + if (scalingToks[5] == "-") + { + sig.bias = scalingToks[6].toDouble() * 1.0; + } + } + else + { + sig.bias = 0; + sig.factor = 1; + } + } + else if (tokens[9].startsWith("$")) //one or more values table entries + { + //$0=Inactive + QList valToks = tokens[9].simplified().mid(1).split('='); + DBC_VAL_ENUM_ENTRY entry; + entry.value = valToks[0].toInt(); + entry.descript = valToks[1]; + sig.valList.append(entry); + } + pMsg->sigHandler->addSignal(sig); + pSig = pMsg->sigHandler->findSignalByIdx(pMsg->sigHandler->getCount()-1); + } + else if (tokens[9].length() > 2) //additional values + { + //$0=Inactive + QList valToks = tokens[9].simplified().mid(1).split('='); + DBC_VAL_ENUM_ENTRY entry; + entry.value = valToks[0].toInt(); + entry.descript = valToks[1]; + pSig->valList.append(entry); + } + } + } + + thisFile->setDirtyFlag(); + return thisFile; +} + DBCFile* DBCHandler::loadJSONFile(QString filename) { QSettings settings; @@ -1886,7 +2056,6 @@ DBCFile* DBCHandler::loadJSONFile(QString filename) } } - thisFile->setDirtyFlag(); return thisFile; } diff --git a/dbc/dbchandler.h b/dbc/dbchandler.h index 60b8ff9..304a7a8 100644 --- a/dbc/dbchandler.h +++ b/dbc/dbchandler.h @@ -125,6 +125,7 @@ public: DBCFile* getFileByName(QString name); int createBlankFile(); DBCFile* loadJSONFile(QString); + DBCFile* loadSecretCSVFile(QString); static DBCHandler *getReference(); private: diff --git a/dbc/dbcloadsavewindow.cpp b/dbc/dbcloadsavewindow.cpp index c2cbec2..7136379 100644 --- a/dbc/dbcloadsavewindow.cpp +++ b/dbc/dbcloadsavewindow.cpp @@ -161,6 +161,7 @@ void DBCLoadSaveWindow::loadFile() QStringList filters; filters.append(QString(tr("DBC File (*.dbc)"))); filters.append(QString(tr("Tesla JSON File (*.json)"))); + filters.append(QString(tr("Secret CSV Signal Defs (*.csv)"))); dialog.setDirectory(settings.value("DBC/LoadSaveDirectory", dialog.directory().path()).toString()); dialog.setFileMode(QFileDialog::ExistingFile); @@ -183,6 +184,11 @@ void DBCLoadSaveWindow::loadFile() if (!filename.contains('.')) filename += ".json"; file = dbcHandler->loadJSONFile(filename); } + if (dialog.selectedNameFilter() == filters[2]) + { + if (!filename.contains('.')) filename += ".csv"; + file = dbcHandler->loadSecretCSVFile(filename); + } } if(file) { diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index cc0bac0..98b8728 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -663,7 +663,7 @@ void DBCMainEditor::deleteCurrentTreeItem() } else { - qDebug() << "WTF, could not find the node in the map. That should not happen."; + qDebug() << "Could not find the node in the map. That should not happen."; } } @@ -685,7 +685,7 @@ void DBCMainEditor::deleteCurrentTreeItem() } else { - qDebug() << "WTF, could not find the message in the map. That should not happen."; + qDebug() << "Could not find the message in the map. That should not happen."; } } break; diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index d506c79..0c33ecb 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -376,7 +376,12 @@ void DBCSignalEditor::showEvent(QShowEvent* event) for (int x = 0; x < dbcMessage->sigHandler->getCount(); x++) { DBC_SIGNAL *sig = dbcMessage->sigHandler->findSignalByIdx(x); - ui->bitfield->setSignalNames(x, sig->name); + //only set a signal name for signals which match multiplexparent with our currentsignal + if (!sig->multiplexParent || ((sig->multiplexParent == currentSignal->multiplexParent) && (sig->multiplexHighValue == currentSignal->multiplexHighValue)) ) + { + ui->bitfield->setSignalNames(x, sig->name); + qDebug() << sig->name << sig->multiplexParent; + } } } @@ -640,8 +645,16 @@ void DBCSignalEditor::generateUsedBits() for (int x = 0; x < dbcMessage->sigHandler->getCount(); x++) { - DBC_SIGNAL *sig = dbcMessage->sigHandler->findSignalByIdx(x); + DBC_SIGNAL *sig = dbcMessage->sigHandler->findSignalByIdx(x); + //only pay attention to this signal if it's multiplexParent matches currentSignal or is null + + 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; + } startBit = sig->startBit; if (sig->intelByteOrder)