From 81e97e8803f1b038de61453957735faa9beb9651 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 10 Jan 2016 20:34:32 -0500 Subject: [PATCH] Added ability for candatagrid to show the currently used bits in gray. Used in signal editor to help make it easier to know what bits are used. Added single and double precision float code where appropriate. They weren't supported at all before. But, that code isn't really tested yet. Added support for multiplexed signals. Most all the code for the UI is done and some of the backend but it isn't hooked into the actual signal processing code just yet. Updated program version number. --- candatagrid.cpp | 15 ++++-- candatagrid.h | 2 + config.h | 2 +- dbc_classes.h | 4 ++ dbchandler.cpp | 124 +++++++++++++++++++++++++++++++++++++------- dbchandler.h | 1 + dbcsignaleditor.cpp | 116 +++++++++++++++++++++++++++++++++++++++-- dbcsignaleditor.h | 1 + dbcsignaleditor.ui | 48 +++++++++++++++-- mainwindow.cpp | 4 +- 10 files changed, 286 insertions(+), 31 deletions(-) diff --git a/candatagrid.cpp b/candatagrid.cpp index 11e8a8e..12c4675 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -13,6 +13,7 @@ CANDataGrid::CANDataGrid(QWidget *parent) : memset(data, 0, 8); memset(refData, 0, 8); + memset(usedData, 0, 8); } CANDataGrid::~CANDataGrid() @@ -45,7 +46,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) int x, y; unsigned char prevByte, thisByte; bool thisBit, prevBit; - QBrush blackBrush, whiteBrush, redBrush, greenBrush; + QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush; QPainter painter(this); QRect viewport = painter.viewport(); @@ -60,6 +61,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) whiteBrush = QBrush(Qt::white); redBrush = QBrush(Qt::red); greenBrush = QBrush(Qt::green); + grayBrush = QBrush(QColor(230,230,230)); //the whole thing is broken up into 100 chunks which are allocated as such: //The entirety of the upper row is taken up by "BITS" @@ -109,7 +111,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) thisBit = false; prevBit = false; if ((thisByte & (1 << (7-x))) == (1 << (7-x))) thisBit = true; - if ((prevByte & (1 << (7-x))) == (1 << (7-x))) prevBit = true; + if ((prevByte & (1 << (7-x))) == (1 << (7-x))) prevBit = true; if (thisBit) { @@ -130,7 +132,8 @@ void CANDataGrid::paintEvent(QPaintEvent *event) } else { - painter.setBrush(whiteBrush); + if ((usedData[y] & (1 << (7-x))) == (1 << (7-x))) painter.setBrush(grayBrush); + else painter.setBrush(whiteBrush); } } @@ -180,3 +183,9 @@ void CANDataGrid::updateData(unsigned char *newData, bool bUpdate = true) memcpy(data, newData, 8); //on a 64 bit processor this is probably optimized to a single instruction if (bUpdate) this->update(); } + +void CANDataGrid::setUsed(unsigned char *newData, bool bUpdate = false) +{ + memcpy(usedData, newData, 8); + if (bUpdate) this->update(); +} diff --git a/candatagrid.h b/candatagrid.h index 126ad5a..f1710fe 100644 --- a/candatagrid.h +++ b/candatagrid.h @@ -17,6 +17,7 @@ public: void paintEvent(QPaintEvent *event); void setReference(unsigned char *, bool); void updateData(unsigned char *, bool); + void setUsed(unsigned char *, bool); void saveImage(QString filename, int width, int height); protected: @@ -29,6 +30,7 @@ private: Ui::CANDataGrid *ui; unsigned char refData[8]; unsigned char data[8]; + unsigned char usedData[8]; QPoint upperLeft, gridSize; }; diff --git a/config.h b/config.h index 4c832a0..c1d2878 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 145 +#define VERSION 146 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/dbc_classes.h b/dbc_classes.h index 7cbde33..0a43bbf 100644 --- a/dbc_classes.h +++ b/dbc_classes.h @@ -61,6 +61,9 @@ public: int startBit; int signalSize; bool intelByteOrder; //true is obviously little endian. False is big endian + bool isMultiplexor; + bool isMultiplexed; + int multiplexValue; DBC_SIG_VAL_TYPE valType; double factor; double bias; @@ -83,6 +86,7 @@ public: DBC_NODE *sender; QList attributes; QList msgSignals; + DBC_SIGNAL* multiplexorSignal; }; diff --git a/dbchandler.cpp b/dbchandler.cpp index fea369f..bf3f2d3 100644 --- a/dbchandler.cpp +++ b/dbchandler.cpp @@ -62,10 +62,42 @@ void DBCHandler::loadDBCFile(QString filename) } if (line.startsWith("SG_ ")) //defines a signal { + int offset = 0; + bool isMultiplexor = false; + bool isMultiplexed = false; + DBC_SIGNAL sig; + qDebug() << "Found a SG line"; - 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+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); + match = regex.match(line); + if (match.hasMatch()) + { + qDebug() << "Multiplexor signal"; + isMultiplexor = true; + sig.isMultiplexor = true; + } + else + { + regex.setPattern("^SG\\_ *(\\w+) *m(\\d+) *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); + match = regex.match(line); + if (match.hasMatch()) + { + qDebug() << "Multiplexed signal"; + isMultiplexed = true; + sig.isMultiplexed = true; + sig.multiplexValue = match.captured(2).toInt(); + offset = 1; + } + else + { + regex.setPattern("^SG\\_ *(\\w+) *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)"); + match = regex.match(line); + } + } + //captured 1 is the signal name + //captured 2 would be multiplex value if this is a multiplex signal. Then offset the rest of these by 1 //captured 2 is the starting bit //captured 3 is the length in bits //captured 4 is the byte order / value type @@ -78,15 +110,14 @@ void DBCHandler::loadDBCFile(QString filename) //captured 11 is the receiving node if (match.hasMatch()) - { - DBC_SIGNAL sig; + { sig.name = match.captured(1); - sig.startBit = match.captured(2).toInt(); - sig.signalSize = match.captured(3).toInt(); - int val = match.captured(4).toInt(); + sig.startBit = match.captured(2 + offset).toInt(); + sig.signalSize = match.captured(3 + offset).toInt(); + int val = match.captured(4 + offset).toInt(); if (val < 2) { - if (match.captured(5) == "+") sig.valType = UNSIGNED_INT; + if (match.captured(5 + offset) == "+") sig.valType = UNSIGNED_INT; else sig.valType = SIGNED_INT; } switch (val) @@ -107,18 +138,19 @@ void DBCHandler::loadDBCFile(QString filename) sig.valType = STRING; break; } - sig.factor = match.captured(6).toDouble(); - sig.bias = match.captured(7).toDouble(); - sig.min = match.captured(8).toDouble(); - sig.max = match.captured(9).toDouble(); - sig.unitName = match.captured(10); - if (match.captured(11).contains(',')) + sig.factor = match.captured(6 + offset).toDouble(); + sig.bias = match.captured(7 + offset).toDouble(); + sig.min = match.captured(8 + offset).toDouble(); + sig.max = match.captured(9 + offset).toDouble(); + sig.unitName = match.captured(10 + offset); + if (match.captured(11 + offset).contains(',')) { QString tmp = match.captured(11).split(',')[0]; sig.receiver = findNodeByName(tmp); } - else sig.receiver = findNodeByName(match.captured(11)); + else sig.receiver = findNodeByName(match.captured(11 + offset)); currentMessage->msgSignals.append(sig); + if (isMultiplexor) currentMessage->multiplexorSignal = ¤tMessage->msgSignals.last(); } else numSigFaults++; } @@ -357,7 +389,16 @@ void DBCHandler::saveDBCFile(QString filename) for (int s = 0; s < msg.msgSignals.count(); s++) { DBC_SIGNAL sig = msg.msgSignals[s]; - msgOutput.append(" SG_ " + sig.name + " : " + QString::number(sig.startBit) + "|" + QString::number(sig.signalSize) + "@"); + msgOutput.append(" SG_ " + sig.name); + + if (sig.isMultiplexor) msgOutput.append(" M"); + if (sig.isMultiplexed) + { + msgOutput.append(" m" + QString::number(sig.multiplexValue)); + } + + msgOutput.append(" : " + QString::number(sig.startBit) + "|" + QString::number(sig.signalSize) + "@"); + switch (sig.valType) { case UNSIGNED_INT: @@ -554,6 +595,8 @@ QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig) int64_t result = 0; bool isSigned = false; + double endResult; + if (sig.valType == STRING) { QString buildString; @@ -564,10 +607,29 @@ QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig) } if (sig.valType == SIGNED_INT) isSigned = true; - result = Utility::processIntegerSignal(frame.data, sig.startBit, sig.signalSize, sig.intelByteOrder, isSigned); - - double endResult = ((double)result * sig.factor) + sig.bias; - result = (int) endResult; + if (sig.valType == SIGNED_INT || sig.valType == UNSIGNED_INT) + { + result = Utility::processIntegerSignal(frame.data, sig.startBit, sig.signalSize, sig.intelByteOrder, isSigned); + endResult = ((double)result * sig.factor) + sig.bias; + result = (int64_t)endResult; + } + else if (sig.valType == SP_FLOAT) + { + //The theory here is that we force the integer signal code to treat this as + //a 32 bit unsigned integer. This integer is then cast into a float in such a way + //that the bytes that make up the integer are instead treated as having made up + //a 32 bit single precision float. That's evil incarnate but it is very fast and small + //in terms of new code. + result = Utility::processIntegerSignal(frame.data, sig.startBit, 32, false, false); + endResult = (*((float *)(&result)) * sig.factor) + sig.bias; + } + else //double precision float + { + //like the above, this is rotten and evil and wrong in so many ways. Force + //calculation of a 64 bit integer and then cast it into a double. + result = Utility::processIntegerSignal(frame.data, 0, 64, false, false); + endResult = (*((double *)(&result)) * sig.factor) + sig.bias; + } QString outputString; @@ -581,13 +643,35 @@ QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig) } } else //otherwise display the actual number and unit (if it exists) - { + { outputString += QString::number(endResult) + sig.unitName; } return outputString; } +//Works quite a bit like the above version but this one is cut down and only will return int32_t which is perfect for +//uses like calculating a multiplexor value or if you know you are going to get an integer returned +//from a signal and you want to use it as-is and not have to convert back from a string. Use with caution though +//as this basically assumes the signal is an integer. If it isn't you get -1 back. +int32_t processSignalInt(const CANFrame &frame, const DBC_SIGNAL &sig) +{ + int32_t result = 0; + bool isSigned = false; + if (sig.valType == STRING || sig.valType == SP_FLOAT || sig.valType == DP_FLOAT) + { + return -1; //I warned you! + } + + if (sig.valType == SIGNED_INT) isSigned = true; + result = Utility::processIntegerSignal(frame.data, sig.startBit, sig.signalSize, sig.intelByteOrder, isSigned); + + double endResult = ((double)result * sig.factor) + sig.bias; + result = (int32_t)endResult; + + return result; +} + //given a byte it will reverse the bit order in that byte unsigned char DBCHandler::reverseBits(unsigned char b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; diff --git a/dbchandler.h b/dbchandler.h index b49645c..8bb6f07 100644 --- a/dbchandler.h +++ b/dbchandler.h @@ -19,6 +19,7 @@ public: void saveDBCFile(QString); void listDebugging(); QString processSignal(const CANFrame &frame, const DBC_SIGNAL &sig); + int32_t processSignalInt(const CANFrame &frame, const DBC_SIGNAL &sig); DBC_NODE *findNodeByName(QString name); DBC_NODE *findNodeByIdx(int idx); diff --git a/dbcsignaleditor.cpp b/dbcsignaleditor.cpp index 6f439f7..1c0b098 100644 --- a/dbcsignaleditor.cpp +++ b/dbcsignaleditor.cpp @@ -52,6 +52,8 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) : { if (currentSignal == NULL) return; currentSignal->intelByteOrder = ui->cbIntelFormat->isChecked(); + if (currentSignal->valType == SP_FLOAT || currentSignal->valType == DP_FLOAT) + currentSignal->intelByteOrder = false; fillSignalForm(currentSignal); }); @@ -75,14 +77,21 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) : break; case 2: currentSignal->valType = SP_FLOAT; + currentSignal->intelByteOrder = false; + if (currentSignal->startBit > 39) currentSignal->startBit = 39; + currentSignal->signalSize = 32; break; case 3: currentSignal->valType = DP_FLOAT; + currentSignal->intelByteOrder = false; + currentSignal->startBit = 7; //has to be! + currentSignal->signalSize = 64; break; case 4: currentSignal->valType = STRING; - break; + break; } + fillSignalForm(currentSignal); }); connect(ui->txtBias, &QLineEdit::editingFinished, [=]() @@ -143,7 +152,8 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) : temp = Utility::ParseStringToNum(ui->txtBitLength->text()); if (temp < 0) return; if (temp > 63) return; - currentSignal->signalSize = temp; + if (currentSignal->valType != SP_FLOAT && currentSignal->valType != DP_FLOAT) + currentSignal->signalSize = temp; fillSignalForm(currentSignal); }); connect(ui->txtName, &QLineEdit::editingFinished, @@ -154,6 +164,45 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) : //need to update the list too. ui->signalsList->currentItem()->setText(currentSignal->name); }); + + connect(ui->txtMultiplexValue, &QLineEdit::editingFinished, + [=]() + { + if (currentSignal == NULL) return; + int temp; + temp = Utility::ParseStringToNum(ui->txtMultiplexValue->text()); + //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->rbMultiplexed, &QRadioButton::toggled, + [=](bool state) + { + if (state) //signal is now set as a multiplexed signal + { + currentSignal->isMultiplexed = true; + currentSignal->isMultiplexor = false; + } + }); + + connect(ui->rbMultiplexor, &QRadioButton::toggled, + [=](bool state) + { + if (state) //signal is now set as a multiplexed signal + { + currentSignal->isMultiplexed = false; + currentSignal->isMultiplexor = true; + } + }); + + connect(ui->rbNotMulti, &QRadioButton::toggled, + [=](bool state) + { + if (state) //signal is now set as a multiplexed signal + { + currentSignal->isMultiplexed = false; + currentSignal->isMultiplexor = false; + } + }); } DBCSignalEditor::~DBCSignalEditor() @@ -274,8 +323,12 @@ void DBCSignalEditor::addNewSignal() newSig.signalSize = 1; newSig.startBit = 0; newSig.valType = UNSIGNED_INT; + newSig.isMultiplexed = false; + newSig.isMultiplexor = false; + newSig.multiplexValue = 0; ui->signalsList->addItem(newName); dbcMessage->msgSignals.append(newSig); + if (dbcMessage->msgSignals.count() == 1) clickSignalList(0); } void DBCSignalEditor::deleteCurrentSignal() @@ -317,6 +370,8 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) { unsigned char bitpattern[8]; + generateUsedBits(); + if (sig == NULL) { ui->txtName->setText(""); @@ -327,6 +382,10 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) ui->txtMinVal->setText(""); ui->txtScale->setText(""); ui->txtUnitName->setText(""); + ui->txtMultiplexValue->setText(""); + ui->rbMultiplexed->setChecked(false); + ui->rbMultiplexor->setChecked(false); + ui->rbNotMulti->setChecked(true); memset(bitpattern, 0, 8); //clear it out ui->bitfield->setReference(bitpattern, false); ui->bitfield->updateData(bitpattern, true); @@ -338,11 +397,15 @@ 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->txtMultiplexValue->setText(QString::number(sig->multiplexValue)); ui->txtComment->setText(sig->comment); ui->txtMaxVal->setText(QString::number(sig->max)); 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) ); memset(bitpattern, 0, 8); //clear it out first. @@ -379,7 +442,6 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) } } - ui->bitfield->updateData(bitpattern, true); ui->cbIntelFormat->setChecked(sig->intelByteOrder); @@ -446,6 +508,7 @@ void DBCSignalEditor::clickSignalList(int row) { if (row < 0) return; //qDebug() << ui->signalsList->item(row)->text(); + DBC_SIGNAL *thisSig = dbcHandler->findSignalByName(dbcMessage, ui->signalsList->item(row)->text()); if (thisSig == NULL) return; currentSignal = thisSig; @@ -459,5 +522,52 @@ void DBCSignalEditor::bitfieldClicked(int x, int y) int bit = (7 - x) + (y * 8); if (currentSignal == NULL) return; currentSignal->startBit = bit; + if (currentSignal->valType == SP_FLOAT) + { + if (currentSignal->startBit > 31) currentSignal->startBit = 39; + } + + if (currentSignal->valType == DP_FLOAT) + currentSignal->startBit = 7; fillSignalForm(currentSignal); } + +void DBCSignalEditor::generateUsedBits() +{ + uint8_t usedBits[8] = {0,0,0,0,0,0,0,0}; + int startBit, endBit; + + for (int x = 0; x < dbcMessage->msgSignals.count(); x++) + { + DBC_SIGNAL sig = dbcMessage->msgSignals.at(x); + + startBit = sig.startBit; + + if (sig.intelByteOrder) + { + endBit = startBit + sig.signalSize - 1; + if (startBit < 0) startBit = 0; + if (endBit > 63) endBit = 63; + for (int y = startBit; y <= endBit; y++) + { + int byt = y / 8; + usedBits[byt] |= 1 << (y % 8); + } + } + else //big endian / motorola format + { + //much more irritating than the intel version... + int size = sig.signalSize; + while (size > 0) + { + int byt = startBit / 8; + usedBits[byt] |= 1 << (startBit % 8); + size--; + if ((startBit % 8) == 0) startBit += 15; + else startBit--; + if (startBit > 63) startBit = 63; + } + } + } + ui->bitfield->setUsed(usedBits, false); +} diff --git a/dbcsignaleditor.h b/dbcsignaleditor.h index 139b0d6..beef97b 100644 --- a/dbcsignaleditor.h +++ b/dbcsignaleditor.h @@ -39,6 +39,7 @@ private: void refreshSignalsList(); void fillSignalForm(DBC_SIGNAL *sig); void fillValueTable(DBC_SIGNAL *sig); + void generateUsedBits(); void closeEvent(QCloseEvent *event); void readSettings(); diff --git a/dbcsignaleditor.ui b/dbcsignaleditor.ui index 8f46097..9348c7b 100644 --- a/dbcsignaleditor.ui +++ b/dbcsignaleditor.ui @@ -7,7 +7,7 @@ 0 0 884 - 791 + 915 @@ -118,7 +118,7 @@ - + Comment: @@ -153,9 +153,51 @@ - + + + + + Multiplexing + + + + + + + + + Not multiplexed + + + + + + + Multiplexed + + + + + + + Multiplexor + + + + + + + + + Multiplex Value + + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index ff4d6e5..3596f8e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -15,6 +15,8 @@ Single / Multi state - The goal is to find bits that change based on toggles or fuzzy scope - Try to find potential places where a given value might be stored - offer guesses and the program tries to find candidates for you or, try to find things that appear to be multi-byte integers + +Change dbc editor to be able to do multiplexed signals */ QString MainWindow::loadedFileName = ""; @@ -820,7 +822,7 @@ void MainWindow::handleSaveDecoded() void MainWindow::saveDecodedTextFile(QString filename) { QFile *outFile = new QFile(filename); - const QVector *frames = model->getListReference(); + const QVector *frames = model->getFilteredListReference(); if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) return;