diff --git a/can_structs.h b/can_structs.h index f230964..92e4491 100644 --- a/can_structs.h +++ b/can_structs.h @@ -9,6 +9,7 @@ public: int ID; int bus; bool extended; + bool isReceived; //did we receive this or send it? int len; unsigned char data[8]; uint64_t timestamp; diff --git a/canframemodel.cpp b/canframemodel.cpp index bd2d578..beb978a 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -17,7 +17,7 @@ int CANFrameModel::totalFrameCount() int CANFrameModel::columnCount(const QModelIndex &index) const { Q_UNUSED(index); - return 6; + return 7; } CANFrameModel::CANFrameModel(QObject *parent) @@ -159,7 +159,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - if (index.row() >= filteredFrames.count()) + if (index.row() >= (filteredFrames.count())) return QVariant(); if (role == Qt::DisplayRole) { @@ -168,7 +168,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const { case 0: //timestamp if (!timeSeconds) return QString::number(thisFrame.timestamp); - else return QString::number(thisFrame.timestamp / 1000000.0f); + else return QString::number((double)thisFrame.timestamp / 1000000.0, 'f', 6); break; case 1: //id return Utility::formatNumber(thisFrame.ID); @@ -176,13 +176,17 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const case 2: //ext return QString::number(thisFrame.extended); break; - case 3: //bus + case 3: //direction + if (thisFrame.isReceived) return QString(tr("Rx")); + else return QString(tr("Tx")); + break; + case 4: //bus return QString::number(thisFrame.bus); break; - case 4: //len + case 5: //len return QString::number(thisFrame.len); break; - case 5: //data + case 6: //data for (int i = 0; i < thisFrame.len; i++) { tempString.append(Utility::formatNumber(thisFrame.data[i])); @@ -234,12 +238,15 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation, return QString(tr("Ext")); break; case 3: - return QString(tr("Bus")); + return QString(tr("Dir")); break; case 4: - return QString(tr("Len")); + return QString(tr("Bus")); break; case 5: + return QString(tr("Len")); + break; + case 6: return QString(tr("Data")); break; } @@ -385,6 +392,11 @@ void CANFrameModel::clearFrames() */ void CANFrameModel::insertFrames(const QVector &newFrames) { + //not resetting the model here because the serial worker automatically does a bulk refresh every 1/4 second + //and that refresh will cause the view to update. If you do both it usually ends up thinking you have + //double the number of frames. + //beginResetModel(); + mutex.lock(); int insertedFiltered = 0; for (int i = 0; i < newFrames.count(); i++) { @@ -400,9 +412,10 @@ void CANFrameModel::insertFrames(const QVector &newFrames) filteredFrames.append(newFrames[i]); } } - - beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + insertedFiltered); - endInsertRows(); + mutex.unlock(); + //endResetModel(); + //beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + insertedFiltered); + //endInsertRows(); if (needFilterRefresh) emit updatedFiltersList(); } diff --git a/config.h b/config.h index dba170f..b3e533a 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 142 +#define VERSION 143 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/framefileio.cpp b/framefileio.cpp index c2fad71..38bd344 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -94,7 +94,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector* frames) return false; } - line = inFile->readLine(); //read out the header first and discard it. + line = inFile->readLine().toUpper(); //read out the header first and discard it. while (!inFile->atEnd()) { lineCounter++; @@ -121,11 +121,14 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector* frames) } //qDebug() << "decimal places " << decimalPlaces; thisFrame.timestamp = (int64_t)(tokens[0].toDouble() * multiplier); - if (tokens[1] == "R11" || tokens[1] == "R29") + char firstChar = tokens[1].left(1)[0]; + if (firstChar == 'R' || firstChar == 'T') { thisFrame.ID = tokens[2].toInt(NULL, 16); - if (tokens[1] == "R29") thisFrame.extended = true; + if (tokens[1] == "R29" || tokens[1] == "T29") thisFrame.extended = true; else thisFrame.extended = false; + if (firstChar == 'T') thisFrame.isReceived = false; + else thisFrame.isReceived = true; thisFrame.bus = 0; thisFrame.len = tokens.length() - 3; for (int d = 0; d < thisFrame.len; d++) @@ -171,11 +174,15 @@ bool FrameFileIO::saveCRTDFile(QString filename, const QVector* frames outFile->write(QString::number(frames->at(c).timestamp / 1000000.0, 'f', 6).toUtf8()); outFile->putChar(' '); + + if (frames->at(c).isReceived) outFile->putChar('R'); + else outFile->putChar('T'); + if (frames->at(c).extended) { - outFile->write("R29 "); + outFile->write("29 "); } - else outFile->write("R11 "); + else outFile->write("11 "); outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); outFile->putChar(' '); @@ -199,6 +206,7 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) QFile *inFile = new QFile(filename); CANFrame thisFrame; QByteArray line; + int fileVersion = 1; long long timeStamp = Utility::GetTimeMS(); int lineCounter = 0; @@ -208,7 +216,8 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) return false; } - line = inFile->readLine(); //read out the header first and discard it. + line = inFile->readLine().toUpper(); //read out the header first and discard it. + if (line.at(23) == 'D') fileVersion = 2; //Dir is found starting at position 23 if this is a V2 file while (!inFile->atEnd()) { lineCounter++; @@ -236,11 +245,27 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) thisFrame.ID = tokens[1].toInt(NULL, 16); if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1; else thisFrame.extended = 0; - thisFrame.bus = tokens[3].toInt(); - thisFrame.len = tokens[4].toInt(); - for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; - for (int d = 0; d < thisFrame.len; d++) - thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16); + + if (fileVersion == 1) + { + thisFrame.isReceived = true; + thisFrame.bus = tokens[3].toInt(); + thisFrame.len = tokens[4].toInt(); + for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; + for (int d = 0; d < thisFrame.len; d++) + thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16); + } + else if (fileVersion == 2) + { + if (tokens[3].at(0) == 'R') thisFrame.isReceived = true; + else thisFrame.isReceived = false; + thisFrame.bus = tokens[4].toInt(); + thisFrame.len = tokens[5].toInt(); + for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; + for (int d = 0; d < thisFrame.len; d++) + thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16); + } + frames->append(thisFrame); } } @@ -260,7 +285,7 @@ bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector* f return false; } - outFile->write("Time Stamp,ID,Extended,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8"); + outFile->write("Time Stamp,ID,Extended,Dir,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8"); outFile->write("\n"); for (int c = 0; c < frames->count(); c++) @@ -281,6 +306,9 @@ bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector* f if (frames->at(c).extended) outFile->write("true,"); else outFile->write("false,"); + if (frames->at(c).isReceived) outFile->write("Rx,"); + else outFile->write("Tx,"); + outFile->write(QString::number(frames->at(c).bus).toUtf8()); outFile->putChar(44); @@ -449,7 +477,7 @@ bool FrameFileIO::loadLogFile(QString filename, QVector* frames) lineCounter = 0; } - line = inFile->readLine(); + line = inFile->readLine().toUpper(); if (line.startsWith("***")) continue; if (line.length() > 1) { @@ -458,6 +486,8 @@ bool FrameFileIO::loadLogFile(QString filename, QVector* frames) timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul)) + (timeToks[2].toInt() * (1000ul * 1000ul)) + (timeToks[3].toInt() * 100ul); thisFrame.timestamp = timeStamp; + if (tokens[1].at(0) == 'R') thisFrame.isReceived = true; + else thisFrame.isReceived = false; thisFrame.ID = tokens[3].right(tokens[3].length() - 2).toInt(NULL, 16); if (tokens[4] == "s") thisFrame.extended = false; else thisFrame.extended = true; @@ -513,7 +543,8 @@ bool FrameFileIO::saveLogFile(QString filename, const QVector* frames) tempStamp = timestamp.addMSecs(frames->at(c).timestamp / 1000); outFile->write(tempStamp.toString("h:m:s:z").toUtf8()); - outFile->write(" Rx "); + if (frames->at(c).isReceived) outFile->write(" Rx "); + else outFile->write(" Tx "); outFile->write(QString::number(frames->at(c).bus).toUtf8() + " "); outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); if (frames->at(c).extended) outFile->write(" x "); @@ -549,7 +580,7 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector* frames) CANFrame thisFrame; QByteArray line; bool inComment = false; - long long timeStamp = Utility::GetTimeMS(); + long long timeStamp; int lineCounter = 0; if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) @@ -580,9 +611,10 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector* frames) if (!inComment) { QList tokens = line.split(';'); - timeStamp += 5; + timeStamp = tokens[0].toInt() * 1000; thisFrame.timestamp = timeStamp; - + if (tokens[1].at(0) == 'R') thisFrame.isReceived = true; + else thisFrame.isReceived = false; thisFrame.ID = Utility::ParseStringToNum(tokens[2]); if (thisFrame.ID <= 0x7FF) thisFrame.extended = false; else thisFrame.extended = true; @@ -643,7 +675,8 @@ bool FrameFileIO::saveMicrochipFile(QString filename, const QVector* f } outFile->write(QString::number((int)(frames->at(c).timestamp / 1000)).toUtf8()); - outFile->write(";RX;"); + if (frames->at(c).isReceived) outFile->write(";RX;"); + else outFile->write(";TX;"); outFile->write("0x" + QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8() + ";"); outFile->write(QString::number(frames->at(c).len).toUtf8() + ";"); diff --git a/mainwindow.cpp b/mainwindow.cpp index e57d5ea..f656310 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -49,15 +49,13 @@ MainWindow::MainWindow(QWidget *parent) : readSettings(); - QStringList headers; - headers << "Timestamp" << "ID" << "Ext" << "Bus" << "Len" << "Data"; - //model->setHorizontalHeaderLabels(headers); ui->canFramesView->setColumnWidth(0, 110); ui->canFramesView->setColumnWidth(1, 70); ui->canFramesView->setColumnWidth(2, 40); ui->canFramesView->setColumnWidth(3, 40); ui->canFramesView->setColumnWidth(4, 40); - ui->canFramesView->setColumnWidth(5, 275); + ui->canFramesView->setColumnWidth(5, 40); + ui->canFramesView->setColumnWidth(6, 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. @@ -500,7 +498,6 @@ void MainWindow::handleLoadFile() if (result) { model->insertFrames(tempFrames); - QStringList fileList = filename.split('/'); loadedFileName = fileList[fileList.length() - 1]; diff --git a/scriptcontainer.cpp b/scriptcontainer.cpp index c146800..5fb658f 100644 --- a/scriptcontainer.cpp +++ b/scriptcontainer.cpp @@ -58,8 +58,14 @@ void ScriptContainer::setErrorWidget(QListWidget *list) void ScriptContainer::setFilter(QJSValue id, QJSValue mask, QJSValue bus) { + uint32_t idVal = id.toUInt(); + uint32_t maskVal = mask.toUInt(); + int busVal = bus.toInt(); qDebug() << "Called set filter"; - qDebug() << id.toInt() << "*" << mask.toInt() << "*" << bus.toInt(); + qDebug() << idVal << "*" << maskVal << "*" << busVal; + CANFilter filter; + filter.setFilter(idVal, maskVal, busVal); + filters.append(filter); } void ScriptContainer::setTickInterval(QJSValue interval) @@ -77,6 +83,7 @@ void ScriptContainer::setTickInterval(QJSValue interval) void ScriptContainer::clearFilters() { qDebug() << "Called clear filters"; + filters.clear(); } void ScriptContainer::sendFrame(QJSValue id, QJSValue length, QJSValue data) @@ -84,6 +91,18 @@ void ScriptContainer::sendFrame(QJSValue id, QJSValue length, QJSValue data) qDebug() << "called send frame"; } +void ScriptContainer::gotFrame(const CANFrame &frame) +{ + for (int i = 0; i < filters.length(); i++) + { + if (filters[i].checkFilter(frame.ID, frame.bus)) + { + + return; //as soon as one filter matches we jump out + } + } +} + void ScriptContainer::tick() { if (tickFunction.isCallable()) diff --git a/scriptcontainer.h b/scriptcontainer.h index 09c4f90..fc354ba 100644 --- a/scriptcontainer.h +++ b/scriptcontainer.h @@ -1,6 +1,9 @@ #ifndef SCRIPTCONTAINER_H #define SCRIPTCONTAINER_H +#include "can_structs.h" +#include "canfilter.h" + #include #include #include @@ -11,6 +14,8 @@ class ScriptContainer : public QObject public: ScriptContainer(); + void gotFrame(const CANFrame &frame); + QString fileName; QString filePath; QString scriptText; @@ -34,6 +39,7 @@ private: QJSValue tickFunction; QTimer timer; QListWidget *errorWidget; + QList filters; }; #endif // SCRIPTCONTAINER_H diff --git a/serialworker.cpp b/serialworker.cpp index 9586c74..4b4ad23 100644 --- a/serialworker.cpp +++ b/serialworker.cpp @@ -155,11 +155,13 @@ void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0) QByteArray buffer; int c; int ID; + CANFrame tempFrame = *frame; + tempFrame.isReceived = false; //qDebug() << "Sending out frame with id " << frame->ID; - //show our sent frames in the list too. This happens even if we're not connected. - canModel->addFrame(*frame, false); + //show our sent frames in the list too. This happens even if we're not connected. + canModel->addFrame(tempFrame, false); gotFrames++; if (!connected) return; @@ -310,6 +312,7 @@ void SerialWorker::procRXChar(unsigned char c) //qDebug() << "emit from serial handler to main form id: " << buildFrame->ID; if (capturing) { + buildFrame->isReceived = true; canModel->addFrame(*buildFrame, false); gotFrames++; if (buildFrame->ID == targetID) emit gotTargettedFrame(canModel->rowCount() - 1); @@ -445,7 +448,7 @@ void SerialWorker::handleTick() emit frameUpdateTick(framesPerSec / 4, gotFrames); //sends stats to interested parties canModel->sendBulkRefresh(gotFrames); gotFrames = 0; - if (doValidation && connected) sendCommValidation(); + if (doValidation && serial) sendCommValidation(); } void SerialWorker::handleReconnect()