diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 57d34d2..64cbc55 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -20,6 +20,7 @@ QMAKE_INFO_PLIST = Info.plist.template ICON = icons/SavvyIcon.icns SOURCES += main.cpp\ + canbridgewindow.cpp \ connections/canserver.cpp \ connections/lawicel_serial.cpp \ connections/mqtt_bus.cpp \ @@ -101,6 +102,7 @@ SOURCES += main.cpp\ HEADERS += mainwindow.h \ can_structs.h \ + canbridgewindow.h \ canframemodel.h \ connections/canserver.h \ connections/lawicel_serial.h \ @@ -191,6 +193,7 @@ HEADERS += mainwindow.h \ pcaplite.h FORMS += ui/candatagrid.ui \ + ui/canbridgewindow.ui \ ui/dbcnodeduplicateeditor.ui \ ui/dbccomparatorwindow.ui \ ui/dbcmessageeditor.ui \ @@ -220,7 +223,7 @@ FORMS += ui/candatagrid.ui \ ui/udsscanwindow.ui \ ui/bisectwindow.ui \ ui/signalviewerwindow.ui \ - helpwindow.ui \ + ui/helpwindow.ui \ ui/newconnectiondialog.ui \ ui/temporalgraphwindow.ui diff --git a/canbridgewindow.cpp b/canbridgewindow.cpp new file mode 100644 index 0000000..cb4ffb4 --- /dev/null +++ b/canbridgewindow.cpp @@ -0,0 +1,143 @@ +#include "canbridgewindow.h" +#include "helpwindow.h" +#include "qevent.h" +#include "ui_canbridgewindow.h" +#include "filterutility.h" +#include "mainwindow.h" + +CANBridgeWindow::CANBridgeWindow(const QVector *frames, QWidget *parent) : + QDialog(parent), + ui(new Ui::CANBridgeWindow) +{ + ui->setupUi(this); + + modelFrames = frames; + + side1BusNum = 0; + side2BusNum = 0; + + connect(ui->cbSide1, &QComboBox::currentTextChanged, this, &CANBridgeWindow::recalcSides); + connect(ui->cbSide2, &QComboBox::currentTextChanged, this, &CANBridgeWindow::recalcSides); + connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &CANBridgeWindow::updatedFrames); + connect(ui->listSide1, &QListWidget::itemChanged, + [this] (QListWidgetItem *item) + { + bool checked = item->checkState() == Qt::Checked ? true:false; + int IDval = FilterUtility::getIdAsInt(item); + qDebug() << "ID " << IDval << " set to " << checked; + foundIDSide1[IDval] = checked; + }); + connect(ui->listSide2, &QListWidget::itemChanged, + [this] (QListWidgetItem *item) + { + bool checked = item->checkState() == Qt::Checked ? true:false; + int IDval = FilterUtility::getIdAsInt(item); + foundIDSide2[IDval] = checked; + }); +} + +CANBridgeWindow::~CANBridgeWindow() +{ + delete ui; +} + + +void CANBridgeWindow::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + //stuff to do every time this form is shown. + ui->cbSide1->clear(); + ui->cbSide2->clear(); + int numBuses = CANConManager::getInstance()->getNumBuses(); + for (int i = 0; i < numBuses; i++) + { + ui->cbSide1->addItem(QString::number(i)); + ui->cbSide2->addItem(QString::number(i)); + } +} + +bool CANBridgeWindow::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::KeyRelease) { + QKeyEvent *keyEvent = static_cast(event); + switch (keyEvent->key()) + { + case Qt::Key_F1: + HelpWindow::getRef()->showHelp("canbridge.md"); + break; + } + return true; + } else { + // standard event processing + return QObject::eventFilter(obj, event); + } +} + +void CANBridgeWindow::recalcSides() +{ + side1BusNum = ui->cbSide1->currentText().toInt(); + side2BusNum = ui->cbSide2->currentText().toInt(); +} + + +void CANBridgeWindow::updatedFrames(int numFrames) +{ + bool addedSide1 = false; + bool addedSide2 = false; + + if (numFrames == -1) //all frames deleted. Kill the display + { + } + else if (numFrames == -2) //all new set of frames. Reset + { + } + else //just got some new frames. See if they are relevant. + { + if (numFrames > modelFrames->count()) return; + + for (int x = modelFrames->count() - numFrames; x < modelFrames->count(); x++) + { + CANFrame thisFrame = modelFrames->at(x); + int32_t id = static_cast(thisFrame.frameId()); + + if (thisFrame.bus == side1BusNum) + { + if (!foundIDSide1.contains(id)) + { + foundIDSide1.insert(id, true); + FilterUtility::createCheckableFilterItem(id, true, ui->listSide1); + addedSide1 = true; + } + if (ui->ckEnableSide1->isChecked()) //if we're enabled to forward traffic on this bus to the other one + { + if (foundIDSide1[id]) //and the checkbox for this particular ID is checked + { + thisFrame.bus = side2BusNum; + CANConManager::getInstance()->sendFrame(thisFrame); + } + } + } + else if (thisFrame.bus == side2BusNum) + { + if (!foundIDSide2.contains(id)) + { + foundIDSide2.insert(id, true); + FilterUtility::createCheckableFilterItem(id, true, ui->listSide2); + addedSide2 = true; + } + if (ui->ckEnableSide2->isChecked()) //if we're enabled to forward traffic on this bus to the other one + { + if (foundIDSide2[id]) //and the checkbox for this particular ID is checked + { + thisFrame.bus = side1BusNum; + CANConManager::getInstance()->sendFrame(thisFrame); + } + } + } + } + //default is to sort in ascending order + if (addedSide1) ui->listSide1->sortItems(); + if (addedSide2) ui->listSide2->sortItems(); + } +} + diff --git a/canbridgewindow.h b/canbridgewindow.h new file mode 100644 index 0000000..40304a2 --- /dev/null +++ b/canbridgewindow.h @@ -0,0 +1,38 @@ +#ifndef CANBRIDGEWINDOW_H +#define CANBRIDGEWINDOW_H + +#include +#include "connections/canconmanager.h" + +namespace Ui { +class CANBridgeWindow; +} + +class CANBridgeWindow : public QDialog +{ + Q_OBJECT + +public: + explicit CANBridgeWindow(const QVector *frames, QWidget *parent = nullptr); + ~CANBridgeWindow(); + void showEvent(QShowEvent*); + + +private slots: + void updatedFrames(int); + void recalcSides(); + +private: + Ui::CANBridgeWindow *ui; + const QVector *modelFrames; + QMap foundIDSide1; + QMap foundIDSide2; + int side1BusNum; + int side2BusNum; + + void processIncomingFrame(CANFrame *frame); + bool eventFilter(QObject *obj, QEvent *event); + +}; + +#endif // CANBRIDGEWINDOW_H diff --git a/help/canbridge.md b/help/canbridge.md new file mode 100644 index 0000000..5055d02 --- /dev/null +++ b/help/canbridge.md @@ -0,0 +1,13 @@ +CAN Bridge Window +================= + +![Bridge Window](images/CANBridge.png) + +Using the Bridge Window +========================== + +The purpose of this window is simple, to allow one to forward traffic from one bus to another. Any two buses you have connected could be bridged in this way, even if they originate on different hardware adapters. By default neither side will forward to the other. You must select different buses for Side 1 and Side 2 then enable forwarding from one to the other. You can enable bi-directional forwarding. However, this can be problematic. If you are not careful you can create an infinite loop where traffic from one side gets forwarded to the other side which then forwards to the first side, and so on. + +If you'd like to only forward some traffic then uncheck the boxes next to IDs you do not want to forward. + +At the moment this window is in the preliminary stages and, as mentioned above, could be prone to allowing infinite loops in some circumstances. \ No newline at end of file diff --git a/help/images/CANBridge.png b/help/images/CANBridge.png new file mode 100644 index 0000000..91207e0 Binary files /dev/null and b/help/images/CANBridge.png differ diff --git a/mainwindow.cpp b/mainwindow.cpp index 27a3ea3..a9f5ed2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -95,6 +95,7 @@ MainWindow::MainWindow(QWidget *parent) : signalViewerWindow = nullptr; temporalGraphWindow = nullptr; dbcComparatorWindow = nullptr; + canBridgeWindow = nullptr; dbcHandler = DBCHandler::getReference(); bDirty = false; inhibitFilterUpdate = false; @@ -136,6 +137,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionSignal_Viewer, &QAction::triggered, this, &MainWindow::showSignalViewer); connect(ui->actionSave_Continuous_Logfile, &QAction::triggered, this, &MainWindow::handleContinousLogging); connect(ui->actionTemporal_Graph, &QAction::triggered, this, &MainWindow::showTemporalGraphWindow); + connect(ui->actionCAN_Bridge, &QAction::triggered, this, &MainWindow::showCANBridgeWindow); //handlers fror interactions with the main can frame view table connect(ui->canFramesView, &QAbstractItemView::clicked, this, &MainWindow::gridClicked); @@ -262,8 +264,11 @@ void MainWindow::killEmAll() killWindow(firmwareUploaderWindow); killWindow(motorctrlConfigWindow); killWindow(signalViewerWindow); - killWindow(connectionWindow); killWindow(temporalGraphWindow); + killWindow(canBridgeWindow); + + //trying to kill this window can cause a fault to happen. It's closed last just in case. + killWindow(connectionWindow); } //forcefully close the window, kill it, and salt the earth @@ -1442,6 +1447,15 @@ void MainWindow::showBisectWindow() bisectWindow->show(); } +void MainWindow::showCANBridgeWindow() +{ + if (!canBridgeWindow) + { + canBridgeWindow = new CANBridgeWindow(model->getListReference()); + } + canBridgeWindow->show(); +} + void MainWindow::showFrameSenderWindow() { if (!frameSenderWindow) diff --git a/mainwindow.h b/mainwindow.h index e76ec3f..24eb2da 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -33,6 +33,7 @@ #include "signalviewerwindow.h" #include "re/temporalgraphwindow.h" #include "re/dbccomparatorwindow.h" +#include "canbridgewindow.h" class CANConnection; class ConnectionWindow; @@ -89,6 +90,7 @@ private slots: void showSignalViewer(); void showTemporalGraphWindow(); void showDBCComparisonWindow(); + void showCANBridgeWindow(); void exitApp(); void handleSaveDecoded(); void handleSaveDecodedCsv(); @@ -183,6 +185,7 @@ private: SignalViewerWindow *signalViewerWindow; TemporalGraphWindow *temporalGraphWindow; DBCComparatorWindow *dbcComparatorWindow; + CANBridgeWindow *canBridgeWindow; //various private storage QLabel lbStatusConnected; diff --git a/ui/canbridgewindow.ui b/ui/canbridgewindow.ui new file mode 100644 index 0000000..3818efa --- /dev/null +++ b/ui/canbridgewindow.ui @@ -0,0 +1,89 @@ + + + CANBridgeWindow + + + + 0 + 0 + 640 + 480 + + + + CAN Bridger + + + false + + + + + + + + Side 1 + + + + + + + + + + Enable forwarding + + + false + + + + + + + IDs to forward to side 2 + + + + + + + + + + + + + + Side 2 + + + + + + + + + + Enable forwarding + + + + + + + IDs to forward to side 1 + + + + + + + + + + + + + diff --git a/helpwindow.ui b/ui/helpwindow.ui similarity index 100% rename from helpwindow.ui rename to ui/helpwindow.ui diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 0136c80..3b71991 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -32,7 +32,6 @@ 11 - 50 false @@ -81,7 +80,6 @@ - 50 false @@ -138,7 +136,6 @@ 11 - 75 true true @@ -338,6 +335,9 @@ 16777215 + + false + @@ -368,7 +368,7 @@ 0 0 800 - 21 + 26 @@ -399,6 +399,7 @@ + @@ -621,6 +622,11 @@ Save Decoded Frames CSV + + + CAN Bridge + +