From f272a26dcd6b24840b41971e848c61e85df5b487 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 31 May 2015 19:25:11 -0400 Subject: [PATCH] First version of DBC code that functions. There are questions about some functionality but it mostly works. --- canframemodel.cpp | 14 ++++- dbchandler.cpp | 152 ++++++++++++++++++++++++++++++++++++++++------ dbchandler.h | 4 +- mainwindow.cpp | 38 +++++++++++- mainwindow.h | 4 ++ 5 files changed, 190 insertions(+), 22 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index 77d94ca..92f7fa0 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -26,7 +26,14 @@ void CANFrameModel::setDBCHandler(DBCHandler *handler) void CANFrameModel::setInterpetMode(bool mode) { - interpretFrames = mode; + //if the state of interpretFrames changes then we need to reset the model + //so that QT will refresh the view properly + if (interpretFrames != mode) + { + this->beginResetModel(); + interpretFrames = mode; + this->endResetModel(); + } } void CANFrameModel::setOverwriteMode(bool mode) @@ -70,14 +77,17 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const tempString.append(" "); } //now, if we're supposed to interpret the data and the DBC handler is loaded then use it - if (dbcHandler != NULL) + if (dbcHandler != NULL && interpretFrames) { DBC_MESSAGE *msg = dbcHandler->findMsgByID(thisFrame.ID); if (msg != NULL) { + tempString.append("\r\n"); for (int j = 0; j < msg->msgSignals.length(); j++) { + tempString.append(dbcHandler->processSignal(thisFrame, msg->msgSignals.at(j))); + tempString.append("\r\n"); } } } diff --git a/dbchandler.cpp b/dbchandler.cpp index 239640a..13dffd5 100644 --- a/dbchandler.cpp +++ b/dbchandler.cpp @@ -320,42 +320,158 @@ void DBCHandler::listDebugging() } -//DBC files use what I'd consider a completely stupid way to count bits. The lowest bit -//in a byte is 7 while the highest is 0. So, the counting for a byte goes like this: -//0 1 2 3 4 5 6 7. That only makes sense if you write it out like that. In reality bits are stored -//7 6 5 4 3 2 1 0. So, plan accordingly. It's confusing when you're used to bit 7 being the highest, not lowest -//But, bytes are still in order. Byte 0 is the first byte, byte 7 would be the last byte in a frame. -//So, the lowest bit of the last byte is 63. The upshot is that, if you took all the bytes in a canbus -//frame and started labeling from left to right you would really number 0 to 63 in complete order. It's -//just that computers don't store data like that. Have I mentioned that already? Screw Vector. Go away on a CANoe. +//Vector uses a special format for bit ordering. It pretends that the bits are numbered +//0 to 63 in ascending order of bits as if a 64 bit integer were stored lowest first +//and highest bit last. //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Vector bit ordering -//7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 Bitwise ordering within bytes -//0 1 2 3 Byte ordering +//7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 Normal bitwise ordering within bytes +//0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 Reversed bit order used by Vector +//0 1 2 3 Byte ordering (same either way) +//A 16 bit integer would be stored Low first high second for intel format and high first, low second for motorola + //For intel format invert the starting bit within a byte. -//Otherwise, iterate over the bytes that it encompasses and -void DBCHandler::processSignal(CANFrame *frame, DBC_SIGNAL *sig) +//Otherwise, iterate over the bytes that it encompasses +//For intel format this works nicely as it means you can just go through the list getting higher and higher +//values for each bit as you go. +//For motorola it is backwards but only partially. For each byte you can go through and it's higher as you go +//but, at each byte boundary the next byte is lower than the multiplier for the last. +QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig) { int startBit, endBit, startByte, endByte, bitWithinByteStart, bitWithinByteEnd; + int result = 0; + int multiplier; + int bitsToGo; - startBit = sig->startBit; + startBit = sig.startBit; startByte = startBit / 8; bitWithinByteStart = startBit % 8; - if (sig->intelByteOrder) + if (sig.intelByteOrder) { bitWithinByteStart = 7 - bitWithinByteStart; startBit = (startByte * 8) + bitWithinByteStart; } - endBit = startBit + sig->signalSize - 1; + if (sig.valType == STRING) + { + QString buildString; + int bytes = sig.signalSize / 8; + for (int x = 0; x < bytes; x++) buildString.append(frame.data[startByte + x]); + return buildString; + } + + endBit = startBit + sig.signalSize - 1; endByte = endBit / 8; bitWithinByteEnd = endBit % 8; + bitsToGo = sig.signalSize - 1; - if (sig->intelByteOrder) //little endian - startBit is least sig. bit + multiplier = 1; + if (sig.intelByteOrder) { - + for (int y = startByte; y < endByte; y++) multiplier *= 256; } - else //motorola / big endian - startBit is most sig. bit + + //qDebug() << "Signal Name: " << sig.name; + //qDebug() << "Intel Order: " << sig.intelByteOrder; + //qDebug() << "start byte: " << startByte; + //qDebug() << "End Byte: " << endByte; + + int sBit, eBit; + sBit = bitWithinByteStart; + eBit = sBit + bitsToGo; + if (eBit > 7) eBit = 7; + bitsToGo -= (eBit - sBit + 1); + for (int b = startByte; b <= endByte; b++) { + //qDebug() << "Byte: " << frame.data[b]; + //qDebug() << "S: " << sBit; + //qDebug() << "E: " << eBit; + //process this byte + result += processByte(frame.data[b], sBit, eBit) * multiplier; + //add to multiplier + if (!sig.intelByteOrder) + multiplier = multiplier << 8; + else + multiplier = multiplier >> 8; + + //Prepare sBit and eBit for next byte + sBit = 0; //fresh byte so we start at the beginning now + eBit = sBit + bitsToGo; + if (eBit > 7) eBit = 7; + bitsToGo -= (eBit - sBit + 1); } + + if (sig.valType == SIGNED_INT) + { + int mask = (1 << (sig.signalSize - 1)); + if ((result & mask) == mask) //is the highest bit possible for this signal size set? + { + /* + * if so we need to also set every bit higher in the result int too. + * This leads to the below two lines that are nasty. Here's the theory behind that... + * If the value is signed and the highest bit is set then it is negative. To create + * a negative value out of this even though the variable result is 64 bit we have to + * run 1's all of the way up to bit 63 in result. -1 is all ones for whatever size integer + * you have. So, it's 64 1's in this case. + * signedMask is done this way: + * first you take the signal size and shift 1 up that far. Then subtract one. Lets + * see that for a 16 bit signal: + * (1 << 16) - 1 = the first 16 bits set as 1's. So far so good. We then negate the whole + * thing which flips all bits. Thus signedMask ends up with 1's everwhere that the signal + * doesn't take up in the 64 bit signed integer result. Then, result has an OR operation on + * it with the old value and -1 masked so that the the 1 bits from -1 don't overwrite bits from the + * actual signal. This extends the sign bits out so that the integer result reads as the proper negative + * value. We dont need to do any of this if the sign bit wasn't set. + */ + int signedMask = ~((1 << sig.signalSize) - 1); + result = (-1 & signedMask) | result; + } + } + + double endResult = ((double)result * sig.factor) + sig.bias; + result = (int) endResult; + + //qDebug() << "Result: " << result; + + QString outputString; + + outputString = sig.name + ": "; + + if (sig.valList.count() > 0) //if this is a value list type then look it up and display the proper string + { + for (int x = 0; x < sig.valList.count(); x++) + { + if (sig.valList.at(x).value == result) outputString += sig.valList.at(x).descript; + } + } + else //otherwise display the actual number and unit (if it exists) + { + outputString += QString::number(endResult) + sig.unitName; + } + + return outputString; } + +//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; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + +unsigned char DBCHandler::processByte(unsigned char input, int start, int end) +{ + unsigned char output = 0, size = end - start + 1; + //first knock it down so that bottom is is start + output = input >> start; + //then mask off all bits above the proper ending + output &= ((1 << size) - 1); + return output; +} + +/* + SG_ NLG5_E_B_P : 15|1@0+ (1,0) [0|1] "" Control + SG_ NLG5_S_MC_M_PI : 23|8@0+ (0.1,0) [0|20] "A" Control + SG_ NLG5_S_MC_M_CP : 7|16@0+ (0.1,0) [0|100] "A" Control +*/ diff --git a/dbchandler.h b/dbchandler.h index 90b125e..37780b2 100644 --- a/dbchandler.h +++ b/dbchandler.h @@ -17,7 +17,7 @@ public: explicit DBCHandler(QObject *parent = 0); void loadDBCFile(QString); void listDebugging(); - void processSignal(CANFrame *frame, DBC_SIGNAL *sig); + QString processSignal(const CANFrame &frame, const DBC_SIGNAL &sig); DBC_NODE *findNodeByName(QString name); DBC_MESSAGE *findMsgByID(int id); DBC_SIGNAL *findSignalByName(DBC_MESSAGE *msg, QString name); @@ -30,6 +30,8 @@ private: QList dbc_nodes; QList dbc_messages; + unsigned char reverseBits(unsigned char); + unsigned char processByte(unsigned char, int, int); }; #endif // DBCHANDLER_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 3c0b3ef..5f459f5 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -50,6 +50,8 @@ MainWindow::MainWindow(QWidget *parent) : ui->canFramesView->setColumnWidth(5, 275); QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader(); HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview + //enabling the below line kills performance in every way imaginable. Left here as a warning. Do not do this. + //ui->canFramesView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); ports = QSerialPortInfo::availablePorts(); @@ -106,6 +108,9 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionLoad_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleLoadDBC())); connect(ui->actionEdit_Messages_Signals, SIGNAL(triggered(bool)), this, SLOT(showEditSignalsWindow())); connect(ui->actionSave_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveDBC())); + connect(ui->canFramesView, SIGNAL(clicked(QModelIndex)), this, SLOT(gridClicked(QModelIndex))); + connect(ui->cbInterpret, SIGNAL(toggled(bool)), this, SLOT(interpretToggled(bool))); + connect(ui->cbOverwrite, SIGNAL(toggled(bool)), this, SLOT(overwriteToggled(bool))); lbStatusConnected.setText(tr("Not connected")); updateBaudLabel(0,0); @@ -118,6 +123,16 @@ MainWindow::MainWindow(QWidget *parent) : ui->lbNumFrames->setText("0"); isConnected = false; + + //create a temporary frame to be able to capture the correct + //default height of an item in the table. Need to do this in case + //of scaling or font differences between different computers. + CANFrame temp; + model->addFrame(temp, true); + normalRowHeight = ui->canFramesView->rowHeight(0); + qDebug() << "normal row height = " << normalRowHeight; + model->clearFrames(); + } MainWindow::~MainWindow() @@ -135,6 +150,27 @@ MainWindow::~MainWindow() delete dbcHandler; } +void MainWindow::gridClicked(QModelIndex idx) +{ + if (ui->canFramesView->rowHeight(idx.row()) > normalRowHeight) + { + ui->canFramesView->setRowHeight(idx.row(), normalRowHeight); + } + else { + ui->canFramesView->resizeRowToContents(idx.row()); + } +} + +void MainWindow::interpretToggled(bool state) +{ + model->setInterpetMode(state); +} + +void MainWindow::overwriteToggled(bool state) +{ + model->setOverwriteMode(state); +} + void MainWindow::updateBaudLabel(int baud0, int baud1) { QString labelText; @@ -638,7 +674,7 @@ void MainWindow::handleLoadDBC() //right now there is only one file type that can be loaded here so just do it. dbcHandler->loadDBCFile(filename); - dbcHandler->listDebugging(); + //dbcHandler->listDebugging(); QStringList fileList = filename.split('/'); lbStatusDatabase.setText(fileList[fileList.length() - 1] + tr(" loaded.")); } diff --git a/mainwindow.h b/mainwindow.h index c3e8677..456fde1 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -44,6 +44,9 @@ private slots: void connectionFailed(); void gotDeviceInfo(int, int); void connectionSucceeded(int, int); + void gridClicked(QModelIndex); + void interpretToggled(bool); + void overwriteToggled(bool); public slots: void gotFrames(int, int); @@ -70,6 +73,7 @@ private: QLabel lbStatusConnected; QLabel lbStatusBauds; QLabel lbStatusDatabase; + int normalRowHeight; bool isConnected; void loadCRTDFile(QString); void loadNativeCSVFile(QString);