diff --git a/candatagrid.cpp b/candatagrid.cpp index ce15ea1..8091452 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -9,6 +9,9 @@ CANDataGrid::CANDataGrid(QWidget *parent) : ui(new Ui::CANDataGrid) { ui->setupUi(this); + + memset(data, 0, 8); + memset(refData, 0, 8); } CANDataGrid::~CANDataGrid() @@ -19,6 +22,9 @@ CANDataGrid::~CANDataGrid() void CANDataGrid::paintEvent(QPaintEvent *event) { int x, y; + unsigned char prevByte, thisByte; + bool thisBit, prevBit; + QBrush blackBrush, whiteBrush, redBrush, greenBrush; QPainter painter(this); QRect viewport = painter.viewport(); @@ -29,6 +35,11 @@ void CANDataGrid::paintEvent(QPaintEvent *event) int xSector = xSpan / 10; int ySector = ySpan / 10; + blackBrush = QBrush(Qt::black); + whiteBrush = QBrush(Qt::white); + redBrush = QBrush(Qt::red); + greenBrush = QBrush(Qt::green); + //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" //The next row down skips two columns and then has 7 6 5 4 3 2 1 0 @@ -58,12 +69,59 @@ void CANDataGrid::paintEvent(QPaintEvent *event) painter.drawText(viewport.left() + 10, viewport.top() + ySector * 7, "E"); painter.drawText(viewport.left() + 10, viewport.top() + ySector * 8, "S"); + //now, color the bitfield by seeing if a given bit is freshly set/unset in the new data + //compared to the old. Bits that are not set in either are white, bits set in both are black + //bits that used to be set but now are unset are red, bits that used to be unset but now are set + //are green + for (y = 0; y < 8; y++) { + thisByte = data[y]; + prevByte = refData[y]; for (x = 0; x < 8; x++) { - painter.drawRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector); + thisBit = false; + prevBit = false; + if ((thisByte & (1 << x)) == (1 << x)) thisBit = true; + if ((prevByte & (1 << x)) == (1 << x)) prevBit = true; + if (thisBit) + { + if (prevBit) + { + painter.setBrush(blackBrush); + } + else + { + painter.setBrush(greenBrush); + } + } + else + { + if (prevBit) + { + painter.setBrush(redBrush); + } + else + { + painter.setBrush(whiteBrush); + } + } + + //painter.fillRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector, redBrush); + painter.drawRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector); } - } + } +} + +void CANDataGrid::setReference(unsigned char *newRef, bool bUpdate = true) +{ + memcpy(refData, newRef, 8); + if (bUpdate) this->update(); +} + +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(); } diff --git a/candatagrid.h b/candatagrid.h index 10b1e32..1881951 100644 --- a/candatagrid.h +++ b/candatagrid.h @@ -15,9 +15,13 @@ public: explicit CANDataGrid(QWidget *parent = 0); ~CANDataGrid(); void paintEvent(QPaintEvent *event); + void setReference(unsigned char *, bool); + void updateData(unsigned char *, bool); private: Ui::CANDataGrid *ui; + unsigned char refData[8]; + unsigned char data[8]; }; #endif // CANDATAGRID_H diff --git a/flowviewwindow.cpp b/flowviewwindow.cpp index fa11e76..f7041e6 100644 --- a/flowviewwindow.cpp +++ b/flowviewwindow.cpp @@ -1,14 +1,220 @@ #include "flowviewwindow.h" #include "ui_flowviewwindow.h" -FlowViewWindow::FlowViewWindow(QWidget *parent) : +FlowViewWindow::FlowViewWindow(QList *frames, QWidget *parent) : QDialog(parent), ui(new Ui::FlowViewWindow) { ui->setupUi(this); + + modelFrames = frames; + + playbackTimer = new QTimer(); + + currentPosition = 0; + playbackActive = false; + playbackForward = true; + + memset(refBytes, 0, 8); + memset(currBytes, 0, 8); + + refreshIDList(); + + updateFrameLabel(); + + connect(ui->btnBackOne, SIGNAL(clicked(bool)), this, SLOT(btnBackOneClick())); + connect(ui->btnPause, SIGNAL(clicked(bool)), this, SLOT(btnPauseClick())); + connect(ui->btnReverse, SIGNAL(clicked(bool)), this, SLOT(btnReverseClick())); + connect(ui->btnStop, SIGNAL(clicked(bool)), this, SLOT(btnStopClick())); + connect(ui->btnPlay, SIGNAL(clicked(bool)), this, SLOT(btnPlayClick())); + connect(ui->btnForwardOne, SIGNAL(clicked(bool)), this, SLOT(btnFwdOneClick())); + connect(ui->spinPlayback, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int))); + connect(ui->cbLoopPlayback, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool))); + connect(ui->listFrameID, SIGNAL(currentTextChanged(QString)), this, SLOT(changeID(QString))); + connect(playbackTimer, SIGNAL(timeout()), this, SLOT(timerTriggered())); + + playbackTimer->setInterval(ui->spinPlayback->value()); //set the timer to the default value of the control + } FlowViewWindow::~FlowViewWindow() { delete ui; + + playbackTimer->stop(); + delete playbackTimer; } + +void FlowViewWindow::refreshIDList() +{ + int id; + for (int i = 0; i < modelFrames->count(); i++) + { + id = modelFrames->at(i).ID; + if (!foundID.contains(id)) + { + foundID.append(id); + QListWidgetItem* item = new QListWidgetItem(QString::number(id, 16).toUpper().rightJustified(4,'0'), ui->listFrameID); + } + } + //default is to sort in ascending order + ui->listFrameID->sortItems(); +} + +void FlowViewWindow::updateFrameLabel() +{ + ui->lblNumFrames->setText(QString::number(currentPosition) + tr(" of ") + QString::number(frameCache.count())); +} + +void FlowViewWindow::changeID(QString newID) +{ + //parse the ID and then load up the frame cache with just messages with that ID. + int id = newID.toInt(NULL, 16); + frameCache.clear(); + playbackTimer->stop(); + playbackActive = false; + for (int x = 0; x < modelFrames->count(); x++) + { + CANFrame thisFrame = modelFrames->at(x); + if (thisFrame.ID == id) + { + frameCache.append(thisFrame); + } + } + currentPosition = 0; + + updateFrameLabel(); +} + +void FlowViewWindow::btnBackOneClick() +{ + playbackTimer->stop(); //pushing this button halts automatic playback + playbackActive = false; + + updatePosition(false); + updateDataView(); +} + +void FlowViewWindow::btnPauseClick() +{ + playbackActive = false; + playbackTimer->stop(); + updateDataView(); +} + +void FlowViewWindow::btnReverseClick() +{ + playbackActive = true; + playbackForward = false; + playbackTimer->start(); +} + +void FlowViewWindow::btnStopClick() +{ + playbackTimer->stop(); //pushing this button halts automatic playback + playbackActive = false; + currentPosition = 0; + updateFrameLabel(); +} + +void FlowViewWindow::btnPlayClick() +{ + playbackActive = true; + playbackForward = true; + playbackTimer->start(); +} + +void FlowViewWindow::btnFwdOneClick() +{ + playbackTimer->stop(); + playbackActive = false; + updatePosition(true); + updateDataView(); +} + +void FlowViewWindow::changePlaybackSpeed(int newSpeed) +{ + playbackTimer->setInterval(newSpeed); +} + +void FlowViewWindow::changeLooping(bool check) +{ + +} + +void FlowViewWindow::timerTriggered() +{ + if (!playbackActive) + { + playbackTimer->stop(); + return; + } + if (playbackForward) + { + updatePosition(true); + } + else + { + updatePosition(false); + } + + updateDataView(); + + if (!ui->cbLoopPlayback->isChecked()) + { + if (currentPosition == 0) playbackActive = false; + if (currentPosition == (frameCache.count() - 1)) playbackActive = false; + } +} + +void FlowViewWindow::updateDataView() +{ + ui->txtCurr1->setText(QString::number(currBytes[0], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr2->setText(QString::number(currBytes[1], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr3->setText(QString::number(currBytes[2], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr4->setText(QString::number(currBytes[3], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr5->setText(QString::number(currBytes[4], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr6->setText(QString::number(currBytes[5], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr7->setText(QString::number(currBytes[6], 16).toUpper().rightJustified(2, '0')); + ui->txtCurr8->setText(QString::number(currBytes[7], 16).toUpper().rightJustified(2, '0')); + + ui->txtRef1->setText(QString::number(refBytes[0], 16).toUpper().rightJustified(2, '0')); + ui->txtRef2->setText(QString::number(refBytes[1], 16).toUpper().rightJustified(2, '0')); + ui->txtRef3->setText(QString::number(refBytes[2], 16).toUpper().rightJustified(2, '0')); + ui->txtRef4->setText(QString::number(refBytes[3], 16).toUpper().rightJustified(2, '0')); + ui->txtRef5->setText(QString::number(refBytes[4], 16).toUpper().rightJustified(2, '0')); + ui->txtRef6->setText(QString::number(refBytes[5], 16).toUpper().rightJustified(2, '0')); + ui->txtRef7->setText(QString::number(refBytes[6], 16).toUpper().rightJustified(2, '0')); + ui->txtRef8->setText(QString::number(refBytes[7], 16).toUpper().rightJustified(2, '0')); + + ui->flowView->setReference(refBytes, false); + ui->flowView->updateData(currBytes, true); + + updateFrameLabel(); + +} + +void FlowViewWindow::updatePosition(bool forward) +{ + + if (forward) + { + if (currentPosition < (frameCache.count() - 1)) currentPosition++; + else if (ui->cbLoopPlayback->isChecked()) currentPosition = 0; + } + else + { + if (currentPosition > 0) currentPosition--; + else if (ui->cbLoopPlayback->isChecked()) currentPosition = frameCache.count() - 1; + } + + if (ui->cbAutoRef->isChecked()) + { + memcpy(refBytes, currBytes, 8); + } + + memcpy(currBytes, frameCache.at(currentPosition).data, 8); + +} + + diff --git a/flowviewwindow.h b/flowviewwindow.h index b4ffd78..9705c23 100644 --- a/flowviewwindow.h +++ b/flowviewwindow.h @@ -2,6 +2,7 @@ #define FLOWVIEWWINDOW_H #include +#include "can_structs.h" namespace Ui { class FlowViewWindow; @@ -12,11 +13,37 @@ class FlowViewWindow : public QDialog Q_OBJECT public: - explicit FlowViewWindow(QWidget *parent = 0); + explicit FlowViewWindow(QList *frames, QWidget *parent = 0); ~FlowViewWindow(); +private slots: + void btnBackOneClick(); + void btnPauseClick(); + void btnReverseClick(); + void btnStopClick(); + void btnPlayClick(); + void btnFwdOneClick(); + void changePlaybackSpeed(int newSpeed); + void changeLooping(bool check); + void timerTriggered(); + void changeID(QString); + private: Ui::FlowViewWindow *ui; + QList foundID; + QList frameCache; + QList *modelFrames; + unsigned char refBytes[8]; + unsigned char currBytes[8]; + int currentPosition; + QTimer *playbackTimer; + bool playbackActive; + bool playbackForward; + + void refreshIDList(); + void updateFrameLabel(); + void updatePosition(bool forward); + void updateDataView(); }; #endif // FLOWVIEWWINDOW_H diff --git a/flowviewwindow.ui b/flowviewwindow.ui index bb3b555..1d04761 100644 --- a/flowviewwindow.ui +++ b/flowviewwindow.ui @@ -32,7 +32,7 @@ - + 0 @@ -62,7 +62,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -84,7 +84,7 @@ - + @@ -99,7 +99,7 @@ - + @@ -110,7 +110,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -147,10 +147,20 @@ - + + + 5000 + + + 10 + + + 25 + + - + Loop Playback @@ -170,7 +180,7 @@ - + 0 @@ -186,7 +196,7 @@ - + 0 @@ -216,7 +226,7 @@ - + Auto Reference @@ -269,7 +279,7 @@ - + 0 @@ -297,7 +307,7 @@ - + 0 @@ -325,7 +335,7 @@ - + 0 @@ -353,7 +363,7 @@ - + 0 @@ -417,7 +427,7 @@ - + 0 @@ -439,7 +449,7 @@ - + 0 @@ -461,7 +471,7 @@ - + 0 @@ -483,7 +493,7 @@ - + 0 @@ -556,7 +566,7 @@ - + 0 @@ -578,7 +588,7 @@ - + 0 @@ -600,7 +610,7 @@ - + 0 @@ -622,7 +632,7 @@ - + 0 @@ -680,7 +690,7 @@ - + 0 @@ -702,7 +712,7 @@ - + 0 @@ -724,7 +734,7 @@ - + 0 @@ -746,7 +756,7 @@ - + 0 diff --git a/mainwindow.cpp b/mainwindow.cpp index bcd1ffb..9c2cb2f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -626,7 +626,7 @@ void MainWindow::showFlowViewWindow() { if (!flowViewWindow) { - flowViewWindow = new FlowViewWindow(); + flowViewWindow = new FlowViewWindow(model->getListReference()); } flowViewWindow->show();