diff --git a/candatagrid.cpp b/candatagrid.cpp index 8327608..25c4262 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -14,6 +14,9 @@ CANDataGrid::CANDataGrid(QWidget *parent) : memset(data, 0, 8); memset(refData, 0, 8); memset(usedData, 0, 8); + for (int x = 0; x < 8; x++) + for (int y = 0; y < 8; y++) + textStates[x][y] = GridTextState::NORMAL; } CANDataGrid::~CANDataGrid() @@ -40,6 +43,25 @@ void CANDataGrid::mousePressEvent(QMouseEvent *event) } } +void CANDataGrid::setCellTextState(int x, int y, GridTextState state) +{ + if (x < 0) return; + if (x > 7) return; + if (y < 0) return; + if (y > 7) return; + textStates[x][y] = state; + this->update(); +} + +GridTextState CANDataGrid::geCellTextState(int x, int y) +{ + if (x < 0) return GridTextState::NORMAL; + if (x > 7) return GridTextState::NORMAL; + if (y < 0) return GridTextState::NORMAL; + if (y > 7) return GridTextState::NORMAL; + return textStates[x][y]; +} + void CANDataGrid::paintEvent(QPaintEvent *event) { Q_UNUSED(event); @@ -50,6 +72,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush; QPainter painter(this); + QRect viewport = painter.viewport(); int xSpan = viewport.right() - viewport.left(); @@ -79,6 +102,9 @@ void CANDataGrid::paintEvent(QPaintEvent *event) painter.setFont(mainFont); QFont smallFont; smallFont.setPixelSize(qMin(xSector, ySector) - 15); + QFont boldFont; + boldFont.setPixelSize(qMin(xSector, ySector) - 10); + boldFont.setBold(true); painter.drawText(QRect(viewport.left(), viewport.top(), xSpan, ySector), Qt::AlignCenter, tr("BITS")); @@ -142,7 +168,25 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //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); + switch (textStates[x][y]) + { + case GridTextState::NORMAL: + painter.setPen(QPen(Qt::gray)); + painter.setFont(mainFont); + break; + case GridTextState::BOLD_BLUE: + painter.setPen(QPen(Qt::blue)); + painter.setFont(boldFont); + break; + case GridTextState::INVERT: + painter.setFont(mainFont); + QColor brushColor = painter.brush().color(); + painter.setPen(QColor(255-brushColor.red(), 255-brushColor.green(), 255-brushColor.blue())); + break; + } + painter.drawText(viewport.left() + (x+2) * xSector + (xSector / 8), viewport.top() + (y + 3) * ySector - (ySector / 3), QString::number(y * 8 + (7-x))); + painter.setPen(QPen(Qt::gray)); } } upperLeft.setX(viewport.left() + 2 * xSector); diff --git a/candatagrid.h b/candatagrid.h index f1710fe..e3162c8 100644 --- a/candatagrid.h +++ b/candatagrid.h @@ -7,6 +7,27 @@ namespace Ui { class CANDataGrid; } +/* + * CANDataGrid is a custom QT widget that proves that it's possible to shoehorn 12x too much crap into one widget. The purported + * goal of the widget was to show an 8x8 grid of bits that show whether each bit in a given message is set or not. It allows one to quickly + * visualize the bits within a CAN frame's data bytes. From there it evolved to also show whether a given bit was freshly set recently, freshly + * unset recently, or has stayed set or unset for a while. It can also gray out bytes that don't exist in the current CAN frame. + * This is handled by the calling code. + * + * After that functionality was added so it could also emit a signal when it is clicked. The signal will tell you which "bit" cell was clicked. + * + * Then, support was added for modifying the text color of each cell. This can be used for whatever the calling code wants. An example is + * FlowView that uses all of the above functionality plus this functionality in order to show which bits are set as triggers for stopping + * the flowview playback. + */ + +enum GridTextState +{ + NORMAL, + BOLD_BLUE, + INVERT +}; + class CANDataGrid : public QWidget { Q_OBJECT @@ -19,6 +40,8 @@ public: void updateData(unsigned char *, bool); void setUsed(unsigned char *, bool); void saveImage(QString filename, int width, int height); + void setCellTextState(int x, int y, GridTextState state); + GridTextState geCellTextState(int x, int y); protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; @@ -31,6 +54,7 @@ private: unsigned char refData[8]; unsigned char data[8]; unsigned char usedData[8]; + GridTextState textStates[8][8]; QPoint upperLeft, gridSize; }; diff --git a/re/flowviewwindow.cpp b/re/flowviewwindow.cpp index 99f206a..a728d9a 100644 --- a/re/flowviewwindow.cpp +++ b/re/flowviewwindow.cpp @@ -27,6 +27,7 @@ FlowViewWindow::FlowViewWindow(const QVector *frames, QWidget *parent) memset(refBytes, 0, 8); memset(currBytes, 0, 8); memset(triggerValues, -1, sizeof(int) * 8); + triggerBits = 0; //ui->graphView->setInteractions(); @@ -102,6 +103,7 @@ FlowViewWindow::FlowViewWindow(const QVector *frames, QWidget *parent) connect(ui->graphView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequestGraph(QPoint))); ui->flowView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->flowView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequestFlow(QPoint))); + connect(ui->flowView, SIGNAL(gridClicked(int,int)), this, SLOT(gotCellClick(int, int))); playbackTimer->setInterval(ui->spinPlayback->value()); //set the timer to the default value of the control } @@ -207,6 +209,15 @@ bool FlowViewWindow::eventFilter(QObject *obj, QEvent *event) } } +void FlowViewWindow::gotCellClick(int x, int y) +{ + int bitnum = (7-x) + (8 * y); + triggerBits = triggerBits ^ (1ull << bitnum); + if (triggerBits & (1ull << bitnum)) ui->flowView->setCellTextState(x, y, GridTextState::BOLD_BLUE); + else ui->flowView->setCellTextState(x, y, GridTextState::NORMAL); + qDebug() << "Bit Num: " << bitnum << " Hex of trigger bits: " << QString::number(triggerBits, 16); +} + void FlowViewWindow::updateTriggerValues() { triggerValues[0] = Utility::ParseStringToNum(ui->txtTrigger0->text()); @@ -725,6 +736,26 @@ void FlowViewWindow::updatePosition(bool forward) memcpy(refBytes, currBytes, 8); } + //figure out which bits changed since the previous frame and then AND that with the trigger bits. If any bits + //get through that then they're changed and a trigger so we stop playback at this frame. + uint64_t changedBits = 0; + uint8_t cngByte; + for (int i = 0; i < 8; i++) + { + cngByte = currBytes[i] ^ frameCache.at(currentPosition).data[i]; + changedBits |= (uint64_t)cngByte << (8ull * i); + } + + qDebug() << "ChangedBits: " << QString::number(changedBits, 16); + qDebug() << "TriggerBits: " << QString::number(triggerBits, 16); + changedBits &= triggerBits; + qDebug() << "Final ChangedBits: " << QString::number(changedBits, 16); + if (changedBits) + { + playbackActive = false; + playbackTimer->stop(); + } + memcpy(currBytes, frameCache.at(currentPosition).data, 8); if (ui->cbSync->checkState() == Qt::Checked) emit sendCenterTimeID(frameCache[currentPosition].ID, frameCache[currentPosition].timestamp / 1000000.0); diff --git a/re/flowviewwindow.h b/re/flowviewwindow.h index 4b4d662..fa07799 100644 --- a/re/flowviewwindow.h +++ b/re/flowviewwindow.h @@ -37,6 +37,7 @@ private slots: void plottableDoubleClick(QCPAbstractPlottable* plottable, QMouseEvent* event); void gotCenterTimeID(int32_t ID, double timestamp); void updateTriggerValues(); + void gotCellClick(int x, int y); signals: void sendCenterTimeID(int32_t ID, double timestamp); @@ -49,6 +50,7 @@ private: unsigned char refBytes[8]; unsigned char currBytes[8]; int triggerValues[8]; + uint64_t triggerBits; int currentPosition; QTimer *playbackTimer; bool playbackActive;