diff --git a/README.md b/README.md index ff088d2c..0c190216 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SavvyCAN QT based cross platform canbus tool -(C) 2015-2016 EVTV and Collin Kidder +(C) 2015-2017 EVTV and Collin Kidder A QT5 based cross platform tool which can be used to load, save, and capture canbus frames. This tool is designed to help with visualization, reverse engineering, debugging, and @@ -14,7 +14,7 @@ You are highly recommended to use the CANDue board from EVTV: The CANDue board must be running the GVRET firmware which can also be found within the collin80 repos. -It is very soon to be possible to use any SocketCAN compatible device +It is now possible to use any SocketCAN compatible device under LINUX. There may, however, be some loss of some functionality as some functions of SavvyCAN are designed for use directly with the EVTVDue and CANDue 2.0 boards. @@ -40,6 +40,10 @@ of this program. It can load and save in several formats: 9. Vehicle Spy log files +10. CANDump / Kayak (Read only) + +11. PCAN Viewer (Read Only) + Requires QScintilla library available at: https://www.riverbankcomputing.com/software/qscintilla/download @@ -50,18 +54,20 @@ http://www.qcustomplot.com/ However, this source code is integrated into the source for SavvyCAN and one isn't required to download it separately. -This project will soon require 5.6.0 or higher because of an upcoming dependency on QSerialBus but currently -should compile with QT 5.5 +This project requires 5.6.0 or higher because of a dependency on QSerialBus which is an optional download +with QT 5.6 (so, be sure to select it) -Instructions for compiling with Ubuntu: +Instructions for compiling: -sudo apt-get install qt5-default qtdeclarative5-dev libqt5serialport5-dev libudev-dev +Download the newest stable version of Qt directly from qt.io (You need 5.6.x or newer) download and extract QScintilla (see above for link), assume it is extracted in QScintilla-gpl-2.9.1 cd ~/QScintilla-gpl-2.9.1/Qt4Qt5 -qmake qscintilla.pro +You will need to either put your copy of QT into your path or specify the path to qmake directly + +~/Qt/5.7/gcc_64/bin/qmake qscintilla.pro make @@ -75,7 +81,7 @@ git clone https://github.com/collin80/SavvyCAN.git cd SavvyCAN -qmake +~/Qt/5.7/gcc_64/bin/qmake make diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 705df29a..784936ab 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui +QT += core gui serialbus greaterThan(QT_MAJOR_VERSION, 4): QT += widgets serialport printsupport qml @@ -17,99 +17,122 @@ TEMPLATE = app SOURCES += main.cpp\ - mainwindow.cpp \ + mainwindow.cpp \ canframemodel.cpp \ utility.cpp \ qcustomplot.cpp \ - graphingwindow.cpp \ - frameinfowindow.cpp \ - newgraphdialog.cpp \ frameplaybackwindow.cpp \ - serialworker.cpp \ candatagrid.cpp \ - flowviewwindow.cpp \ framesenderwindow.cpp \ - dbchandler.cpp \ - dbcmaineditor.cpp \ - dbcsignaleditor.cpp \ framefileio.cpp \ - filecomparatorwindow.cpp \ mainsettingsdialog.cpp \ firmwareuploaderwindow.cpp \ - discretestatewindow.cpp \ - connectionwindow.cpp \ scriptingwindow.cpp \ scriptcontainer.cpp \ canfilter.cpp \ - rangestatewindow.cpp \ - dbc_classes.cpp \ - dbcloadsavewindow.cpp \ - fuzzingwindow.cpp \ - udsscanwindow.cpp \ can_structs.cpp \ - isotp_interpreterwindow.cpp \ - isotp_handler.cpp \ - motorcontrollerconfigwindow.cpp + motorcontrollerconfigwindow.cpp \ + connections/canconnection.cpp \ + connections/socketcan.cpp \ + connections/canconfactory.cpp \ + connections/gvretserial.cpp \ + connections/canconmanager.cpp \ + re/sniffer/snifferitem.cpp \ + re/sniffer/sniffermodel.cpp \ + re/sniffer/snifferwindow.cpp \ + dbc/dbc_classes.cpp \ + dbc/dbchandler.cpp \ + dbc/dbcloadsavewindow.cpp \ + dbc/dbcmaineditor.cpp \ + dbc/dbcsignaleditor.cpp \ + re/discretestatewindow.cpp \ + re/filecomparatorwindow.cpp \ + re/flowviewwindow.cpp \ + re/frameinfowindow.cpp \ + re/fuzzingwindow.cpp \ + re/isotp_handler.cpp \ + re/isotp_interpreterwindow.cpp \ + re/rangestatewindow.cpp \ + re/udsscanwindow.cpp \ + connections/canbus.cpp \ + connections/canconnectionmodel.cpp \ + connections/connectionwindow.cpp \ + re/graphingwindow.cpp \ + re/newgraphdialog.cpp \ + bisectwindow.cpp HEADERS += mainwindow.h \ can_structs.h \ canframemodel.h \ utility.h \ qcustomplot.h \ - graphingwindow.h \ - frameinfowindow.h \ - newgraphdialog.h \ frameplaybackwindow.h \ - serialworker.h \ candatagrid.h \ - flowviewwindow.h \ framesenderwindow.h \ can_trigger_structs.h \ - dbc_classes.h \ - dbchandler.h \ - dbcmaineditor.h \ - dbcsignaleditor.h \ framefileio.h \ config.h \ - filecomparatorwindow.h \ mainsettingsdialog.h \ firmwareuploaderwindow.h \ - discretestatewindow.h \ - connectionwindow.h \ scriptingwindow.h \ scriptcontainer.h \ canfilter.h \ - rangestatewindow.h \ - dbcloadsavewindow.h \ - fuzzingwindow.h \ - udsscanwindow.h \ - isotp_interpreterwindow.h \ - isotp_handler.h \ - motorcontrollerconfigwindow.h + utils/lfqueue.h \ + motorcontrollerconfigwindow.h \ + connections/canconnection.h \ + connections/socketcan.h \ + connections/canconconst.h \ + connections/canconfactory.h \ + connections/gvretserial.h \ + connections/canconmanager.h \ + re/sniffer/snifferitem.h \ + re/sniffer/sniffermodel.h \ + re/sniffer/snifferwindow.h \ + dbc/dbc_classes.h \ + dbc/dbchandler.h \ + dbc/dbcloadsavewindow.h \ + dbc/dbcmaineditor.h \ + dbc/dbcsignaleditor.h \ + re/discretestatewindow.h \ + re/filecomparatorwindow.h \ + re/flowviewwindow.h \ + re/frameinfowindow.h \ + re/fuzzingwindow.h \ + re/isotp_handler.h \ + re/isotp_interpreterwindow.h \ + re/rangestatewindow.h \ + re/udsscanwindow.h \ + connections/canbus.h \ + connections/canconnectionmodel.h \ + connections/connectionwindow.h \ + re/graphingwindow.h \ + re/newgraphdialog.h \ + bisectwindow.h -FORMS += mainwindow.ui \ - graphingwindow.ui \ - frameinfowindow.ui \ - newgraphdialog.ui \ - frameplaybackwindow.ui \ - candatagrid.ui \ - flowviewwindow.ui \ - framesenderwindow.ui \ - dbcmaineditor.ui \ - dbcsignaleditor.ui \ - filecomparatorwindow.ui \ - mainsettingsdialog.ui \ - firmwareuploaderwindow.ui \ - discretestatewindow.ui \ - connectionwindow.ui \ - scriptingwindow.ui \ - rangestatewindow.ui \ - dbcloadsavewindow.ui \ - fuzzingwindow.ui \ - udsscanwindow.ui \ - isotp_interpreterwindow.ui \ - deltawindow.ui \ - motorcontrollerconfigwindow.ui +FORMS += ui/candatagrid.ui \ + ui/connectionwindow.ui \ + ui/dbcloadsavewindow.ui \ + ui/dbcmaineditor.ui \ + ui/dbcsignaleditor.ui \ + ui/discretestatewindow.ui \ + ui/filecomparatorwindow.ui \ + ui/firmwareuploaderwindow.ui \ + ui/flowviewwindow.ui \ + ui/frameinfowindow.ui \ + ui/frameplaybackwindow.ui \ + ui/framesenderwindow.ui \ + ui/fuzzingwindow.ui \ + ui/graphingwindow.ui \ + ui/isotp_interpreterwindow.ui \ + ui/mainsettingsdialog.ui \ + ui/mainwindow.ui \ + ui/motorcontrollerconfigwindow.ui \ + ui/newgraphdialog.ui \ + ui/rangestatewindow.ui \ + ui/scriptingwindow.ui \ + ui/snifferwindow.ui \ + ui/udsscanwindow.ui \ + ui/bisectwindow.ui DISTFILES += diff --git a/bisectwindow.cpp b/bisectwindow.cpp new file mode 100644 index 00000000..bbf9324d --- /dev/null +++ b/bisectwindow.cpp @@ -0,0 +1,154 @@ +#include "bisectwindow.h" +#include "ui_bisectwindow.h" + +#include "mainwindow.h" +#include "framefileio.h" + +#include +#include + +BisectWindow::BisectWindow(const QVector *frames, QWidget *parent) : + QDialog(parent), + ui(new Ui::BisectWindow) +{ + ui->setupUi(this); + + modelFrames = frames; + + connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); + connect(ui->btnCalculate, &QAbstractButton::clicked, this, &BisectWindow::handleCalculateButton); + connect(ui->btnReplaceFrames, &QAbstractButton::clicked, this, &BisectWindow::handleReplaceButton); + connect(ui->btnSaveFrames, &QAbstractButton::clicked, this, &BisectWindow::handleSaveButton); + connect(ui->slideFrameNumber, &QSlider::sliderReleased, this, &BisectWindow::updateFrameNumText); + connect(ui->slidePercentage, &QSlider::sliderReleased, this, &BisectWindow::updatePercentText); + connect(ui->editFrameNumber, &QLineEdit::editingFinished, this, &BisectWindow::updateFrameNumSlider); + connect(ui->editPercentage, &QLineEdit::editingFinished, this, &BisectWindow::updatePercentSlider); +} + +BisectWindow::~BisectWindow() +{ + delete ui; +} + +void BisectWindow::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + refreshIDList(); + refreshFrameNumbers(); + updateFrameNumText(); + updatePercentText(); +} + +void BisectWindow::refreshIDList() +{ + int id; + for (int i = 0; i < modelFrames->count(); i++) + { + id = modelFrames->at(i).ID; + if (!foundID.contains(id)) + { + foundID.append(id); + } + } + + std::sort(foundID.begin(), foundID.end()); + + foreach (int id, foundID) { + ui->cbIDLower->addItem(Utility::formatNumber(id)); + ui->cbIDUpper->addItem(Utility::formatNumber(id)); + } +} + +void BisectWindow::refreshFrameNumbers() +{ + ui->labelMainListNum->setText(QString::number(modelFrames->count())); + ui->labelSplitNum->setText(QString::number(splitFrames.count())); + ui->slideFrameNumber->setMaximum(modelFrames->count()); +} + +void BisectWindow::updatedFrames(int numFrames) +{ + if (numFrames == -1) //all frames deleted + { + refreshFrameNumbers(); + } + else if (numFrames == -2) //all new set of frames. Reset + { + refreshFrameNumbers(); + refreshIDList(); + } + else //just got some new frames. See if they are relevant. + { + + } +} + +void BisectWindow::handleCalculateButton() +{ + splitFrames.clear(); + bool saveLower = ui->rbLowerSection->isChecked(); + int targetFrameNum; + if (ui->rbFrameNumber->isChecked() || ui->rbPercentage->isChecked()) + { + if (ui->rbFrameNumber->isChecked()) targetFrameNum = ui->slideFrameNumber->value(); + else targetFrameNum = modelFrames->count() * ui->slidePercentage->value() / 10000; + if (saveLower) + { + for (int i = 0; i < targetFrameNum; i++) splitFrames.append(modelFrames->at(i)); + } + else + { + for (int i = targetFrameNum; i < modelFrames->count(); i++) splitFrames.append(modelFrames->at(i)); + } + } + else if (ui->rbIDRange->isChecked()) + { + uint32_t lowerID = Utility::ParseStringToNum2(ui->cbIDLower->currentText()); + uint32_t upperID = Utility::ParseStringToNum2(ui->cbIDUpper->currentText()); + for (int i = 0; i < modelFrames->count(); i++) + { + if (modelFrames->at(i).ID >= lowerID && modelFrames->at(i).ID <= upperID) splitFrames.append(modelFrames->at(i)); + } + } + refreshFrameNumbers(); +} + +void BisectWindow::handleReplaceButton() +{ + +} + +void BisectWindow::handleSaveButton() +{ + QMessageBox msg; + QString filename; + if (FrameFileIO::saveFrameFile(filename, &splitFrames)) + { + msg.setText(tr("Successfully saved file")); + } + else + { + msg.setText(tr("Error while attempting to save.")); + } + msg.exec(); +} + +void BisectWindow::updateFrameNumSlider() +{ + ui->slideFrameNumber->setValue(ui->editFrameNumber->text().toInt()); +} + +void BisectWindow::updatePercentSlider() +{ + ui->slidePercentage->setValue(ui->editPercentage->text().toFloat() * 100); +} + +void BisectWindow::updateFrameNumText() +{ + ui->editFrameNumber->setText(QString::number(ui->slideFrameNumber->value())); +} + +void BisectWindow::updatePercentText() +{ + ui->editPercentage->setText(QString::number(ui->slidePercentage->value() / 100.0f)); +} diff --git a/bisectwindow.h b/bisectwindow.h new file mode 100644 index 00000000..77f3ebcc --- /dev/null +++ b/bisectwindow.h @@ -0,0 +1,46 @@ +#ifndef BISECTWINDOW_H +#define BISECTWINDOW_H + +#include +#include "can_structs.h" + +namespace Ui { +class BisectWindow; +} + +class BisectWindow : public QDialog +{ + Q_OBJECT + +public: + explicit BisectWindow(const QVector *frames, QWidget *parent = 0); + ~BisectWindow(); + void showEvent(QShowEvent*); + +signals: + void sendCANFrame(const CANFrame *, int); + void sendFrameBatch(const QList *); + +private slots: + void updatedFrames(int numFrames); + void handleSaveButton(); + void handleReplaceButton(); + void handleCalculateButton(); + void updateFrameNumSlider(); + void updatePercentSlider(); + void updateFrameNumText(); + void updatePercentText(); + +private: + Ui::BisectWindow *ui; + const QVector *modelFrames; + QVector splitFrames; + QList foundID; + + void refreshIDList(); + void refreshFrameNumbers(); +}; + +#endif // BISECTWINDOW_H + + diff --git a/can_structs.h b/can_structs.h index 03269471..40428b5b 100644 --- a/can_structs.h +++ b/can_structs.h @@ -1,21 +1,37 @@ #ifndef CAN_STRUCTS_H #define CAN_STRUCTS_H +#include #include #include -class CANFrame +struct CANFrame { public: - int ID; - int bus; + uint32_t ID; + uint32_t bus; bool extended; bool isReceived; //did we receive this or send it? - int len; + uint32_t len; unsigned char data[8]; uint64_t timestamp; }; +class CANFlt +{ +public: + quint32 id; + quint32 mask; + QObject * observer; //used to target the specific object that setup this filter + + bool operator ==(const CANFlt &b) const + { + if ( (id == b.id) && (mask == b.mask) && (observer == b.observer) ) return true; + + return false; + } +}; + struct J1939ID { public: @@ -32,7 +48,7 @@ struct J1939ID struct ISOTP_MESSAGE { public: - int ID; + uint32_t ID; int bus; bool extended; bool isReceived; diff --git a/canfilter.h b/canfilter.h index 91a84e34..c2cb71bc 100644 --- a/canfilter.h +++ b/canfilter.h @@ -10,7 +10,7 @@ class CANFilter void setFilter(uint32_t id, uint32_t mask, int bus); bool checkFilter(uint32_t id, int bus); -private: +public: uint32_t ID; uint32_t mask; int bus; diff --git a/canframemodel.cpp b/canframemodel.cpp index ae289c28..5e9c8163 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -3,6 +3,15 @@ #include #include "utility.h" + +CANFrameModel::~CANFrameModel() +{ + frames.clear(); + filteredFrames.clear(); + filters.clear(); +} + + int CANFrameModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); @@ -38,12 +47,12 @@ CANFrameModel::CANFrameModel(QObject *parent) if (QSysInfo::WordSize > 32) { qDebug() << "64 bit OS detected. Requesting a large preallocation"; - preallocSize = 50000000; + preallocSize = 20000000; } else //if compiling for 32 bit you can't ask for gigabytes of preallocation so tone it down. { qDebug() << "32 bit OS detected. Requesting a much restricted prealloc"; - preallocSize = 5000000; + preallocSize = 4000000; } frames.reserve(preallocSize); @@ -122,7 +131,7 @@ void CANFrameModel::setOverwriteMode(bool mode) endResetModel(); } -void CANFrameModel::setFilterState(int ID, bool state) +void CANFrameModel::setFilterState(unsigned int ID, bool state) { if (!filters.contains(ID)) return; filters[ID] = state; @@ -235,15 +244,15 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame); if (msg != NULL) { - tempString.append("\r\n"); - tempString.append(msg->name + " " + msg->comment + "\r\n"); + tempString.append("\n"); + tempString.append(msg->name + " " + msg->comment + "\n"); for (int j = 0; j < msg->sigHandler->getCount(); j++) { QString sigString; if (msg->sigHandler->findSignalByIdx(j)->processAsText(thisFrame, sigString)) { tempString.append(sigString); - tempString.append("\r\n"); + tempString.append("\n"); } } } @@ -254,8 +263,8 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const return QVariant(); } } - else - return QVariant(); + + return QVariant(); } QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation, @@ -298,8 +307,10 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation, return QVariant(); } -void CANFrameModel::addFrame(const CANFrame &frame, bool autoRefresh = false) + +void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false) { + /*TODO: remove mutex */ mutex.lock(); CANFrame tempFrame; tempFrame = frame; @@ -361,6 +372,15 @@ void CANFrameModel::addFrame(const CANFrame &frame, bool autoRefresh = false) mutex.unlock(); } + +void CANFrameModel::addFrames(const CANConnection*, const QVector& pFrames) +{ + foreach(const CANFrame& frame, pFrames) + { + addFrame(frame); + } +} + void CANFrameModel::sendRefresh() { qDebug() << "Sending mass refresh"; @@ -392,38 +412,22 @@ void CANFrameModel::sendRefresh(int pos) //issue a refresh for the last num entries in the model. //used by the serial worker to do batch updates so it doesn't //have to send thousands of messages per second -void CANFrameModel::sendBulkRefresh(int num) +int CANFrameModel::sendBulkRefresh() { - //yes, num was sent to us by the serial worker but we actually have a better idea - //of how many by tracking the number we last knew about as opposed to how many rows there - //are now. - num = filteredFrames.count() - lastUpdateNumFrames; + int num = filteredFrames.count() - lastUpdateNumFrames; + if (num <= 0) return 0; - if (num < 0) return; - - //qDebug() << "Num: " << num; - - if (num == 0 && !overwriteDups) return; - if (filteredFrames.count() == 0) return; + if (num == 0 && !overwriteDups) return 0; + if (filteredFrames.count() == 0) return 0; lastUpdateNumFrames += num; //done this way to avoid asking for filteredFrames.count() again qDebug() << "Bulk refresh of " << num; - if (!overwriteDups) - { - //if (num > filteredFrames.count()) num = filteredFrames.count(); - //qDebug() << "From " << (filteredFrames.count() - num) << " to " << (filteredFrames.count() - 1); - //beginInsertRows(QModelIndex(), filteredFrames.count() - num, filteredFrames.count() - 1); - //endInsertRows(); - beginResetModel(); - endResetModel(); - } - else - { - beginResetModel(); - endResetModel(); - } + beginResetModel(); + endResetModel(); + + return num; } void CANFrameModel::clearFrames() @@ -476,7 +480,7 @@ void CANFrameModel::insertFrames(const QVector &newFrames) if (needFilterRefresh) emit updatedFiltersList(); } -int CANFrameModel::getIndexFromTimeID(int ID, double timestamp) +int CANFrameModel::getIndexFromTimeID(unsigned int ID, double timestamp) { int bestIndex = -1; uint64_t intTimeStamp = timestamp * 1000000l; diff --git a/canframemodel.h b/canframemodel.h index a994857c..5099e7cd 100644 --- a/canframemodel.h +++ b/canframemodel.h @@ -7,7 +7,8 @@ #include #include #include "can_structs.h" -#include "dbchandler.h" +#include "dbc/dbchandler.h" +#include "connections/canconnection.h" class CANFrameModel: public QAbstractTableModel { @@ -15,6 +16,7 @@ class CANFrameModel: public QAbstractTableModel public: CANFrameModel(QObject *parent = 0); + virtual ~CANFrameModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; @@ -23,16 +25,15 @@ class CANFrameModel: public QAbstractTableModel int columnCount(const QModelIndex &) const; int totalFrameCount(); - void addFrame(const CANFrame &, bool); void sendRefresh(); void sendRefresh(int); - void sendBulkRefresh(int); + int sendBulkRefresh(); void clearFrames(); void setDBCHandler(DBCHandler *); void setInterpetMode(bool); void setOverwriteMode(bool); void setHexMode(bool); - void setFilterState(int ID, bool state); + void setFilterState(unsigned int ID, bool state); void setAllFilters(bool state); void setSecondsMode(bool); void loadFilterFile(QString filename); @@ -41,11 +42,15 @@ class CANFrameModel: public QAbstractTableModel void recalcOverwrite(); bool needsFilterRefresh(); void insertFrames(const QVector &newFrames); - int getIndexFromTimeID(int ID, double timestamp); + int getIndexFromTimeID(unsigned int ID, double timestamp); const QVector *getListReference() const; //thou shalt not modify these frames externally! const QVector *getFilteredListReference() const; //Thus saith the Lord, NO. const QMap *getFiltersReference() const; //this neither +public slots: + void addFrame(const CANFrame&, bool); + void addFrames(const CANConnection*, const QVector&); + signals: void updatedFiltersList(); diff --git a/config.h b/config.h index de0d42ca..92d05f32 100644 --- a/config.h +++ b/config.h @@ -1,12 +1,12 @@ #ifndef CONFIG #define CONFIG -#define VERSION 157 +#define VERSION 161 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision //less than this number. -#define CURRENT_GVRET_VER 331 +#define CURRENT_GVRET_VER 334 #endif // CONFIG diff --git a/connections/canbus.cpp b/connections/canbus.cpp new file mode 100644 index 00000000..d0f46463 --- /dev/null +++ b/connections/canbus.cpp @@ -0,0 +1,76 @@ +#include +#include "canbus.h" + +CANBus::CANBus() +{ + speed = 250000; + listenOnly = false; + singleWire = false; + active = false; +} + + +CANBus::CANBus(const CANBus& pBus) : + speed(pBus.speed), + listenOnly(pBus.listenOnly), + singleWire(pBus.singleWire), + active(pBus.active) {} + + +bool CANBus::operator==(const CANBus& bus) const{ + return speed == bus.speed && + listenOnly == bus.listenOnly && + singleWire == bus.singleWire && + active == bus.active; +} + +void CANBus::setSpeed(int newSpeed){ + speed = newSpeed; +} + +void CANBus::setListenOnly(bool mode){ + listenOnly = mode; +} + +void CANBus::setSingleWire(bool mode){ + singleWire = mode; +} + +void CANBus::setEnabled(bool mode){ + active = mode; +} + +int CANBus::getSpeed(){ + return speed; +} + +bool CANBus::isListenOnly(){ + return listenOnly; +} + +bool CANBus::isSingleWire(){ + return singleWire; +} + +bool CANBus::isActive(){ + return active; +} + + +QDataStream& operator<<( QDataStream & pStream, const CANBus& pCanBus ) +{ + pStream << pCanBus.speed; + pStream << pCanBus.listenOnly; + pStream << pCanBus.singleWire; + pStream << pCanBus.active; + return pStream; +} + +QDataStream & operator>>(QDataStream & pStream, CANBus& pCanBus) +{ + pStream >> pCanBus.speed; + pStream >> pCanBus.listenOnly; + pStream >> pCanBus.singleWire; + pStream >> pCanBus.active; + return pStream; +} diff --git a/connections/canbus.h b/connections/canbus.h new file mode 100644 index 00000000..9b39358d --- /dev/null +++ b/connections/canbus.h @@ -0,0 +1,34 @@ +#ifndef CANBus_H +#define CANBus_H +#include + +class CANBus +{ +public: + CANBus(); + CANBus(const CANBus&); + bool operator==(const CANBus&) const; + virtual ~CANBus(){}; + + int speed; + bool listenOnly; + bool singleWire; + bool active; //is this bus turned on? + + + void setSpeed(int); // new speed + void setListenOnly(bool); //bool for whether to only listen + void setSingleWire(bool); //bool for whether to use single wire mode + void setEnabled(bool); //whether this bus should be enabled or not. + int getSpeed(); + bool isListenOnly(); + bool isSingleWire(); + bool isActive(); +}; + +QDataStream& operator<<( QDataStream & pStream, const CANBus& pCanBus ); +QDataStream & operator>>(QDataStream & pStream, CANBus& pCanBus); + +Q_DECLARE_METATYPE(CANBus); + +#endif // CANBus_H diff --git a/connections/canconconst.h b/connections/canconconst.h new file mode 100644 index 00000000..707355d9 --- /dev/null +++ b/connections/canconconst.h @@ -0,0 +1,24 @@ +#ifndef CANCONCONST_H +#define CANCONCONST_H + +namespace CANCon { + + /** + * @brief The status enum + */ + enum status + { + NOT_CONNECTED, /*!< device is not connected */ + CONNECTED /*!< device is connected */ + }; + + enum type + { + GVRET_SERIAL, + KVASER, + SOCKETCAN, + NONE + }; +} + +#endif // CANCONCONST_H diff --git a/connections/canconfactory.cpp b/connections/canconfactory.cpp new file mode 100644 index 00000000..79260017 --- /dev/null +++ b/connections/canconfactory.cpp @@ -0,0 +1,19 @@ +#include +#include "canconfactory.h" +#include "socketcan.h" +#include "gvretserial.h" + +using namespace CANCon; + +CANConnection* CanConFactory::create(type pType, QString pPortName) +{ + switch(pType) { + case SOCKETCAN: + return new SocketCan(pPortName); + case GVRET_SERIAL: + return new GVRetSerial(pPortName); + default: {} + } + + return NULL; +} diff --git a/connections/canconfactory.h b/connections/canconfactory.h new file mode 100644 index 00000000..2b482f53 --- /dev/null +++ b/connections/canconfactory.h @@ -0,0 +1,13 @@ +#ifndef CANCONFACTORY_H +#define CANCONFACTORY_H + +#include "canconconst.h" +#include "canconnection.h" + +class CanConFactory +{ +public: + static CANConnection* create(CANCon::type, QString pPortName); +}; + +#endif // CANCONFACTORY_H diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp new file mode 100644 index 00000000..5cc5a1ff --- /dev/null +++ b/connections/canconmanager.cpp @@ -0,0 +1,234 @@ +#include + +#include "canconmanager.h" + + +CANConManager* CANConManager::mInstance = NULL; + +CANConManager* CANConManager::getInstance() +{ + if(!mInstance) + mInstance = new CANConManager(); + + return mInstance; +} + + +CANConManager::CANConManager(QObject *parent): QObject(parent) +{ + connect(&mTimer, SIGNAL(timeout()), this, SLOT(refreshCanList())); + mTimer.setInterval(125); /*tick 8 times a second */ + mTimer.setSingleShot(false); + mTimer.start(); + + resetTimeBasis(); +} + +void CANConManager::resetTimeBasis() +{ + mTimestampBasis = QDateTime::currentMSecsSinceEpoch() * 1000; +} + +CANConManager::~CANConManager() +{ + mTimer.stop(); + mInstance = NULL; +} + + +void CANConManager::add(CANConnection* pConn_p) +{ + mConns.append(pConn_p); + emit connectionStatusUpdated(getNumBuses()); +} + + +void CANConManager::remove(CANConnection* pConn_p) +{ + //disconnect(pConn_p, 0, this, 0); + mConns.removeOne(pConn_p); + emit connectionStatusUpdated(getNumBuses()); +} + +//Get total number of buses currently registered with the program +int CANConManager::getNumBuses() +{ + int buses = 0; + foreach(CANConnection* conn_p, mConns) + { + buses += conn_p->getNumBuses(); + } + return buses; +} + +void CANConManager::refreshCanList() +{ + QObject* sender_p = QObject::sender(); + + if( sender_p != &mTimer) + { + /* if we are not the sender, the signal is coming from a connection */ + /* refresh only the given connection */ + if(mConns.contains((CANConnection*) sender_p)) + refreshConnection((CANConnection*)sender_p); + } + else + { + foreach (CANConnection* conn_p, mConns) + refreshConnection((CANConnection*)conn_p); + } +} + +uint64_t CANConManager::getTimeBasis() +{ + return mTimestampBasis; +} + +QList& CANConManager::getConnections() +{ + return mConns; +} + + +CANConnection* CANConManager::getByName(const QString& pName) const +{ + foreach(CANConnection* conn_p, mConns) + { + if(conn_p->getPort() == pName) + return conn_p; + } + + return NULL; +} + + +void CANConManager::refreshConnection(CANConnection* pConn_p) +{ + if (pConn_p->getQueue().peek() == NULL) return; + + CANFrame* frame_p = NULL; + QVector frames; + + //Each connection only knows about its own bus numbers + //so this variable is used to fix that up to turn local bus numbers + //into system global bus numbers for display. + int busBase = 0; + + foreach (CANConnection* conn, mConns) + { + if (conn != pConn_p) busBase += conn->getNumBuses(); + else break; + } + + //qDebug() << "Bus fixup number: " << busBase; + + while( (frame_p = pConn_p->getQueue().peek() ) ) { + frame_p->bus += busBase; + //qDebug() << "Rx of frame from bus: " << frame_p->bus; + frames.append(*frame_p); + pConn_p->getQueue().dequeue(); + } + + if(frames.size()) + emit framesReceived(pConn_p, frames); +} + +/* + * Uses the requested bus to look up which CANConnection object handles this bus based on the order of + * the objects and how many buses they implement. For instance, if the request is to send on bus 2 + * and there is a GVRET object first then a socketcan object it'll send on the socketcan object as + * gvret will have claimed buses 0 and 1 and socketcan bus 2. But, each actual CANConnection expects + * its own bus numbers to start at zero so the frame bus number has to be offset accordingly. + * Also keep in mind that the CANConnection "sendFrame" function uses a blocking queued connection + * and so will force the frame to be delivered before it keeps going. This allows on the stack variables + * to be used but is slow. This function uses an on the stack copy of the frame so the way it works + * is a good thing but performance will suffer. TODO: Investigate a way to use non-blocking calls. +*/ +bool CANConManager::sendFrame(const CANFrame& pFrame) +{ + int busBase = 0; + CANFrame workingFrame = pFrame; + CANFrame *txFrame; + + foreach (CANConnection* conn, mConns) + { + //check if this CAN connection is supposed to handle the requested bus + if (pFrame.bus < (uint32_t)(busBase + conn->getNumBuses())) + { + workingFrame.bus -= busBase; + workingFrame.isReceived = false; + workingFrame.timestamp = ((QDateTime::currentMSecsSinceEpoch() * 1000) - mTimestampBasis); + txFrame = conn->getQueue().get(); + *txFrame = workingFrame; + conn->getQueue().queue(); + return conn->sendFrame(workingFrame); + } + busBase += conn->getNumBuses(); + } + return false; +} + +bool CANConManager::sendFrames(const QList& pFrames) +{ + foreach(const CANFrame& frame, pFrames) + { + if(!sendFrame(frame)) + return false; + } + + return true; +} + +//For each device associated with buses go through and see if that device has a bus +//that the filter should apply to. If so forward the data on but fudge +//the bus numbers if bus wasn't -1 so that they're local to the device +bool CANConManager::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver) +{ + int tempBusVal; + int busBase = 0; + + foreach (CANConnection* conn, mConns) + { + if (pBusId == -1) conn->addTargettedFrame(pBusId, ID, mask, receiver); + else + { + tempBusVal = pBusId >> busBase; + tempBusVal &= ((1 << conn->getNumBuses()) - 1); + if (tempBusVal) { + qDebug() << "Forwarding targetted frame setting to a connection object"; + conn->addTargettedFrame(tempBusVal, ID, mask, receiver); + } + } + busBase += conn->getNumBuses(); + } + return true; +} + +bool CANConManager::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver) +{ + int tempBusVal; + int busBase = 0; + + foreach (CANConnection* conn, mConns) + { + if (pBusId == -1) conn->removeTargettedFrame(pBusId, ID, mask, receiver); + else + { + tempBusVal = pBusId >> busBase; + tempBusVal &= ((1 << conn->getNumBuses()) - 1); + if (tempBusVal) conn->removeTargettedFrame(tempBusVal, ID, mask, receiver); + } + busBase += conn->getNumBuses(); + } + return true; +} + +bool CANConManager::removeAllTargettedFrames(QObject *receiver) +{ + foreach (CANConnection* conn, mConns) + { + conn->removeAllTargettedFrames(receiver); + } + + return true; +} diff --git a/connections/canconmanager.h b/connections/canconmanager.h new file mode 100644 index 00000000..dc85686f --- /dev/null +++ b/connections/canconmanager.h @@ -0,0 +1,79 @@ +#ifndef CANCONMANAGER_H +#define CANCONMANAGER_H + +#include +#include + +#include "canconnection.h" + +class CANConManager : public QObject +{ + Q_OBJECT + +public: + static CANConManager* getInstance(); + virtual ~CANConManager(); + + void add(CANConnection* pConn_p); + void remove(CANConnection* pConn_p); + QList& getConnections(); + + CANConnection* getByName(const QString& pName) const; + + uint64_t getTimeBasis(); + void resetTimeBasis(); + + int getNumBuses(); + + /** + * @brief sendFrame sends a single frame out the desired bus + * @param pFrame - reference to a CANFrame struct that has been filled out for sending + * @return bool specifying whether the send succeeded or not + * @note Finds which CANConnection object is responsible for this bus and automatically converts bus number to pass properly to CANConnection + */ + bool sendFrame(const CANFrame& pFrame); + + //just the multi-frame version of above function. + bool sendFrames(const QList& pFrames); + + /** + * @brief Add a new filter for the targetted frames. If a frame matches it will immediately be sent via the targettedFrameReceived signal + * @param pBusId - Which bus to bond to. -1 for any, otherwise a bitfield of buses (but 0 = first bus, etc) + * @param ID - 11 or 29 bit ID to match against + * @param mask - 11 or 29 bit mask used for filter + * @param receiver - Pointer to a QObject that wants to receive notification when filter is matched + * @return true if filter was able to be added, false otherwise. + */ + bool addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver); + + /** + * @brief Try to find a matching filter in the list and remove it, no longer targetting those frames + * @param pBusId - Which bus to bond to. Doesn't have to match the call to addTargettedFrame exactly. You could disconnect just one bus for instance. + * @param ID - 11 or 29 bit ID to match against + * @param mask - 11 or 29 bit mask used for filter + * @param receiver - Pointer to a QObject that wants to receive notification when filter is matched + * @return true if filter was found and deleted, false otherwise. + */ + bool removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver); + + bool removeAllTargettedFrames(QObject *receiver); + +signals: + void framesReceived(CANConnection* pConn_p, QVector& pFrames); + void connectionStatusUpdated(int conns); + +private slots: + void refreshCanList(); + +private: + explicit CANConManager(QObject *parent = 0); + void refreshConnection(CANConnection* pConn_p); + + static CANConManager* mInstance; + QList mConns; + QTimer mTimer; + uint64_t mTimestampBasis; +}; + +#endif // CANCONNECTIONMODEL_H + diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp new file mode 100644 index 00000000..41b6329f --- /dev/null +++ b/connections/canconnection.cpp @@ -0,0 +1,363 @@ +#include +#include "canconnection.h" + + +struct BusData { + CANBus mBus; + bool mConfigured; + QVector mTargettedFrames; +}; + + +CANConnection::CANConnection(QString pPort, + CANCon::type pType, + int pNumBuses, + int pQueueLen, + bool pUseThread) : + mQueue(), + mNumBuses(pNumBuses), + mPort(pPort), + mType(pType), + mIsCapSuspended(false), + mStatus(CANCon::NOT_CONNECTED), + mStarted(false), + mThread_p(NULL) +{ + /* register types */ + qRegisterMetaType("CANBus"); + qRegisterMetaType("CANFrame"); + qRegisterMetaType("CANCon::status"); + qRegisterMetaType("CANFlt"); + + /* set queue size */ + mQueue.setSize(pQueueLen); /*TODO add check on returned value */ + + /* allocate buses */ + /* TODO: change those tables for a vector */ + mBusData_p = new BusData[mNumBuses]; + for(int i=0 ; iquit(); + mThread_p->wait(); + delete mThread_p; + mThread_p = NULL; + } + + if(mBusData_p) { + delete[] mBusData_p; + mBusData_p = NULL; + } +} + + +void CANConnection::start() +{ + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + /* move ourself to the thread */ + moveToThread(mThread_p); /*TODO handle errors */ + /* connect started() */ + connect(mThread_p, SIGNAL(started()), this, SLOT(start())); + /* start the thread */ + mThread_p->start(QThread::HighPriority); + return; + } + + /* set started flag */ + mStarted = true; + + /* in multithread case, this will be called before entering thread event loop */ + return piStarted(); +} + + +void CANConnection::suspend(bool pSuspend) +{ + /* execute in mThread_p context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "suspend", + Qt::BlockingQueuedConnection, + Q_ARG(bool, pSuspend)); + return; + } + + return piSuspend(pSuspend); +} + + +void CANConnection::stop() +{ + /* 1) execute in mThread_p context */ + if( mThread_p && mStarted && (mThread_p != QThread::currentThread()) ) + { + /* if thread is finished, it means we call this function for the second time so we can leave */ + if( !mThread_p->isFinished() ) + { + /* we need to call piStop() */ + QMetaObject::invokeMethod(this, "stop", + Qt::BlockingQueuedConnection); + /* 3) stop thread */ + mThread_p->quit(); + if(!mThread_p->wait()) { + qDebug() << "can't stop thread"; + } + } + return; + } + + /* 2) call piStop in mThread context */ + return piStop(); +} + + +bool CANConnection::getBusSettings(int pBusIdx, CANBus& pBus) +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + bool ret; + QMetaObject::invokeMethod(this, "getBusSettings", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int , pBusIdx), + Q_ARG(CANBus& , pBus)); + return ret; + } + + return piGetBusSettings(pBusIdx, pBus); +} + + +void CANConnection::setBusSettings(int pBusIdx, CANBus pBus) +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + QMetaObject::invokeMethod(this, "setBusSettings", + Qt::BlockingQueuedConnection, + Q_ARG(int, pBusIdx), + Q_ARG(CANBus, pBus)); + return; + } + + return piSetBusSettings(pBusIdx, pBus); +} + + +bool CANConnection::sendFrame(const CANFrame& pFrame) +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + bool ret; + QMetaObject::invokeMethod(this, "sendFrame", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(const CANFrame&, pFrame)); + return ret; + } + + return piSendFrame(pFrame); +} + + +bool CANConnection::sendFrames(const QList& pFrames) +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + bool ret; + QMetaObject::invokeMethod(this, "sendFrames", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(const QList&, pFrames)); + return ret; + } + + return piSendFrames(pFrames); +} + + +int CANConnection::getNumBuses() const{ + return mNumBuses; +} + + +bool CANConnection::isConfigured(int pBusId) { + if( pBusId < 0 || pBusId >= getNumBuses()) + return false; + return mBusData_p[pBusId].mConfigured; +} + +void CANConnection::setConfigured(int pBusId, bool pConfigured) { + if( pBusId < 0 || pBusId >= getNumBuses()) + return; + mBusData_p[pBusId].mConfigured = pConfigured; +} + + +bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) { + if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId)) + return false; + + pBus = mBusData_p[pBusId].mBus; + return true; +} + + +void CANConnection::setBusConfig(int pBusId, CANBus& pBus) { + if( pBusId < 0 || pBusId >= getNumBuses()) + return; + + mBusData_p[pBusId].mConfigured = true; + mBusData_p[pBusId].mBus = pBus; +} + + +QString CANConnection::getPort() { + return mPort; +} + + +LFQueue& CANConnection::getQueue() { + return mQueue; +} + + +CANCon::type CANConnection::getType() { + return mType; +} + + +CANCon::status CANConnection::getStatus() { + return (CANCon::status) mStatus.load(); +} + +void CANConnection::setStatus(CANCon::status pStatus) { + mStatus.store(pStatus); +} + +bool CANConnection::isCapSuspended() { + return mIsCapSuspended; +} + +void CANConnection::setCapSuspended(bool pIsSuspended) { + mIsCapSuspended = pIsSuspended; +} + +bool CANConnection::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver) +{ +/* + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + bool ret; + QMetaObject::invokeMethod(this, "addTargettedFrame", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int, pBusId), + Q_ARG(uint32_t , ID), + Q_ARG(uint32_t , mask), + Q_ARG(QObject *, receiver)); + return ret; + } +*/ + /* sanity checks */ + if(pBusId < -1 || pBusId >= (1 << getNumBuses())) + return false; + + for (int i = 0; i < getNumBuses(); i++) + { + if ( (pBusId == -1) || (pBusId && (1 << i)) ) { + qDebug() << "Connection is registering a new targetted frame filter, local bus " << i; + CANFlt target; + target.id = ID; + target.mask = mask; + target.observer = receiver; + mBusData_p[i].mTargettedFrames.append(target); + } + } + + return true; +} + +bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver) +{ +/* + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + bool ret; + QMetaObject::invokeMethod(this, "removeTargettedFrame", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int, pBusId), + Q_ARG(uint32_t , ID), + Q_ARG(uint32_t , mask), + Q_ARG(QObject *, receiver)); + return ret; + } +*/ + /* sanity checks */ + if(pBusId < -1 || pBusId >= (1 << getNumBuses())) + return false; + + for (int i = 0; i < getNumBuses(); i++) + { + if (pBusId == -1 || (pBusId && (1 << i))) + { + CANFlt target; + target.id = ID; + target.mask = mask; + target.observer = receiver; + mBusData_p[i].mTargettedFrames.removeAll(target); + } + } + + return true; +} + +bool CANConnection::removeAllTargettedFrames(QObject *receiver) +{ + for (int i = 0; i < getNumBuses(); i++) { + foreach (const CANFlt filt, mBusData_p[i].mTargettedFrames) + { + if (filt.observer == receiver) mBusData_p[i].mTargettedFrames.removeOne(filt); + } + } + + return true; +} + +void CANConnection::checkTargettedFrame(CANFrame &frame) +{ + unsigned int maskedID; + qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus; + foreach (const CANFlt filt, mBusData_p[frame.bus].mTargettedFrames) + { + qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask; + maskedID = frame.ID & filt.mask; + if (maskedID == filt.id) { + qDebug() << "In connection object I got a targetted frame. Forwarding it."; + QMetaObject::invokeMethod(filt.observer, "gotTargettedFrame",Qt::QueuedConnection, Q_ARG(CANFrame, frame)); + } + } +} + +bool CANConnection::piSendFrames(const QList& pFrames) +{ + foreach(const CANFrame& frame, pFrames) + { + if(!piSendFrame(frame)) + return false; + } + + return true; +} diff --git a/connections/canconnection.h b/connections/canconnection.h new file mode 100644 index 00000000..c6471e2b --- /dev/null +++ b/connections/canconnection.h @@ -0,0 +1,296 @@ +#ifndef CANCONNECTION_H +#define CANCONNECTION_H + +#include +#include +#include "utils/lfqueue.h" +#include "can_structs.h" +#include "canbus.h" +#include "canconconst.h" + +struct BusData; + +class CANConnection : public QObject +{ + Q_OBJECT + +protected: + + /** + * @brief CANConnection constructor + * @param pPort: string containing port name + * @param pType: the type of connection @ref CANCon::type + * @param pNumBuses: the number of buses the device has + * @param pQueueLen: the length of the lock free queue to use + * @param pUseThread: if set to true, object will be execute in a dedicated thread + */ + CANConnection(QString pPort, + CANCon::type pType, + int pNumBuses, + int pQueueLen, + bool pUseThread); + +public: + + /** + * @brief CANConnection destructor + */ + + virtual ~CANConnection(); + + /** + * @brief getNumBuses + * @return returns the number of buses of the device + */ + int getNumBuses() const; + + /** + * @brief getPort + * @return returns the port name of the device + */ + QString getPort(); + + /** + * @brief getQueue + * @return the lock free queue of the device + */ + LFQueue& getQueue(); + + /** + * @brief getType + * @return the @ref CANCon::type of the device + */ + CANCon::type getType(); + + /** + * @brief getStatus + * @return the @ref CANCon::status of the device (either connected or not) + */ + CANCon::status getStatus(); + + +signals: + /*not implemented yet */ + void error(const QString &); + void deviceInfo(int, int); //First param = driver version (or version of whatever you want), second param a status byte + + //bus number, bus speed, status (bit 0 = enabled, 1 = single wire, 2 = listen only) + //3 = Use value stored for enabled, 4 = use value passed for single wire, 5 = use value passed for listen only + //6 = use value passed for speed. This allows bus status to be updated but set that some things aren't really + //being passed. Just set for things that really are being updated. + void busStatus(int, int, int); + + /** + * @brief event sent when a frame matching a filter is received + */ + void targettedFrameReceived(CANFrame frame); + + /** + * @brief event emitted when the CANCon::status of the connection changes (connected->not_connected or the other way round) + * @param pStatus: the new status of the device + */ + void status(CANCon::status pStatus); + + +public slots: + + /** + * @brief start the device. This calls piStarted + * @note starts the working thread if required (piStarted is called in the working thread context) + */ + void start(); + + /** + * @brief stop the device. This calls piStop + * @note if a working thread is used, piStop is called before exiting the working thread + */ + void stop(); + + /** + * @brief setBusSettings + * @param pBusIdx: the index of the bus for which settings have to be set + * @param pBus: the settings to set + * @note this calls piSetBusSettings in the working thread context (if one has been started) + */ + void setBusSettings(int pBusIdx, CANBus pBus); + + /** + * @brief getBusSettings + * @param pBusIdx: the index of the bus for which settings have to be retrieved + * @param pBus: the CANBus struct to fill with information + * @return true if operation succeeds, false if pBusIdx is invalid or bus has not been configured yet + * @note this calls piGetBusSettings in the working thread context (if one has been started) + */ + bool getBusSettings(int pBusIdx, CANBus& pBus); + + /** + * @brief suspends/restarts data capture + * @param pSuspend: suspends capture if true else restarts it + * @note this calls piSuspend (in the working thread context if one has been started) + * @note the caller shall not access the queue when capture is suspended, + * @note the callee is expected to flush the queue + */ + void suspend(bool pSuspend); + + /** + * @brief provides device with the frame to send + * @param pFrame: the frame to send + * @return false if parameter is invalid (bus id for instance) + * @note this calls piSendFrame (in the working thread context if one has been started) + */ + bool sendFrame(const CANFrame& pFrame); + + /** + * @brief provides device with a list of frames to send + * @param pFrame: the list of frames to send + * @return false if parameter is invalid (bus id for instance) + * @note this calls piSendFrameBatch (in the working thread context if one has been started) + */ + bool sendFrames(const QList& pFrames); + + /** + * @brief Add a new filter for the targetted frames. If a frame matches it will immediately be sent via the targettedFrameReceived signal + * @param pBusId - Which bus to bond to. -1 for any, otherwise a bitfield of buses (but 0 = first bus, etc) + * @param ID - 11 or 29 bit ID to match against + * @param mask - 11 or 29 bit mask used for filter + * @param receiver - Pointer to a QObject that wants to receive notification when filter is matched + * @return true if filter was able to be added, false otherwise. + */ + bool addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver); + + /** + * @brief Try to find a matching filter in the list and remove it, no longer targetting those frames + * @param pBusId - Which bus to bond to. Doesn't have to match the call to addTargettedFrame exactly. You could disconnect just one bus for instance. + * @param ID - 11 or 29 bit ID to match against + * @param mask - 11 or 29 bit mask used for filter + * @param receiver - Pointer to a QObject that wants to receive notification when filter is matched + * @return true if filter was found and deleted, false otherwise. + */ + bool removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver); + + /** + * @brief Removes all registered filters for the passed receiver + * @param receiver - Pointer to a QObject that registered one or more filters + * @return true if filter(s) was/were found and deleted, false otherwise. + */ + bool removeAllTargettedFrames(QObject *receiver); + +protected: + + //determine if the passed frame is part of a filter or not. + void checkTargettedFrame(CANFrame &frame); + + /** + * @brief setStatus + * @param pStatus: the status to set + */ + void setStatus(CANCon::status pStatus); + + /** + * @brief isConfigured + * @param pBusId + * @return true if bus is configured + */ + bool isConfigured(int pBusId); + + /** + * @brief setConfigured + * @param pBusId + * @param pConfigured + * @note it is not necessary to call this function to set pBusId configured, it is enough to call @ref setBusConfig + */ + void setConfigured(int pBusId, bool pConfigured); + + /** + * @brief getBusConfig + * @param pBusId + * @param pBus + * @return true if operation succeeds, false if pBusIdx is invalid or bus has not been configured yet + */ + bool getBusConfig(int pBusId, CANBus& pBus); + + /** + * @brief setBusConfig + * @param pBusId: the index of the bus for which settings have to be set + * @param pBus: the settings to set + */ + void setBusConfig(int pBusId, CANBus& pBus); + + /** + * @brief isCapSuspended + * @return true if the capture is suspended + */ + bool isCapSuspended(); + + /** + * @brief setCapSuspended + * @param pIsSuspended + */ + void setCapSuspended(bool pIsSuspended); + +protected: + + /**************************************************************/ + /*********** protected interface to implement *******/ + /**************************************************************/ + + /** + * @brief starts the device + */ + virtual void piStarted() = 0; + + /** + * @brief stops the device + */ + virtual void piStop() = 0; + + /** + * @brief piSetBusSettings + * @param pBusIdx: the index of the bus for which settings have to be set + * @param pBus: the settings to set + */ + virtual void piSetBusSettings(int pBusIdx, CANBus pBus) = 0; + + /** + * @brief piGetBusSettings + * @param pBusIdx: the index of the bus for which settings have to be retrieved + * @param pBus: the CANBus struct to fill with information + * @return true if operation succeeds, false if pBusIdx is invalid or bus has not been configured yet + */ + virtual bool piGetBusSettings(int pBusIdx, CANBus& pBus) = 0; + + /** + * @brief suspends/restarts data capture + * @param pSuspend: suspends capture if true else restarts it + * @note the caller will not access the queue when capture is suspended, so it is safe for callee to flush the queue + */ + virtual void piSuspend(bool pSuspend) = 0; + + /** + * @brief provides device with the frame to send + * @param pFrame: the frame to send + * @return false if parameter is invalid (bus id for instance) + */ + virtual bool piSendFrame(const CANFrame&) = 0; + + /** + * @brief provides device with a list of frames to send + * @param pFrame: the list of frames to send + * @return false if parameter is invalid (bus id for instance) + * @note implementing this function is optional + */ + virtual bool piSendFrames(const QList&); + +private: + LFQueue mQueue; + const int mNumBuses; + const QString mPort; + const CANCon::type mType; + bool mIsCapSuspended; + QAtomicInt mStatus; + bool mStarted; + BusData* mBusData_p; + QThread* mThread_p; +}; + +#endif // CANCONNECTION_H diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp new file mode 100644 index 00000000..726c3346 --- /dev/null +++ b/connections/canconnectionmodel.cpp @@ -0,0 +1,190 @@ +#include "canconnectionmodel.h" +#include "connections/canconnection.h" +#include "connections/canconmanager.h" + +CANConnectionModel::CANConnectionModel(QObject *parent) + : QAbstractTableModel(parent) +{ +} + +CANConnectionModel::~CANConnectionModel() +{ +} + + +QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + { + switch (section) + { + case 0: + return QString(tr("Bus")); + break; + case 1: + return QString(tr("Type")); + break; + case 2: + return QString(tr("Port")); + break; + case 3: + return QString(tr("Speed")); + break; + case 4: + return QString(tr("Listen Only")); + break; + case 5: + return QString(tr("Single Wire")); + break; + case 6: + return QString(tr("Status")); + break; + case 7: + return QString(tr("Active")); + break; + } + } + + else + return QString::number(section + 1); + + return QVariant(); +} + + +int CANConnectionModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 7; +} + + +int CANConnectionModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + int rows=0; + QList& conns = CANConManager::getInstance()->getConnections(); + + foreach(const CANConnection* conn_p, conns) + rows+=conn_p->getNumBuses(); + + return rows; +} + + +QVariant CANConnectionModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + + if (role == Qt::DisplayRole) { + int busId; + CANConnection *conn_p = getAtIdx(index.row(), busId); + if(!conn_p) + return QVariant(); + + CANBus bus; + bool ret; + ret = conn_p->getBusSettings(busId, bus); + if(!ret) return QVariant(); + + switch (index.column()) + { + case 0: //bus + //return QString::number(busId); + return QString::number(index.row()); + break; + case 1: //type + if (conn_p) + switch (conn_p->getType()) { + case CANCon::KVASER: return "KVASER"; + case CANCon::SOCKETCAN: return "SocketCAN"; + case CANCon::GVRET_SERIAL: return "GVRET"; + default: {} + } + else qDebug() << "Tried to show connection type but connection was NULL"; + break; + case 2: //port + if (conn_p) return conn_p->getPort(); + else qDebug() << "Tried to show connection port but connection was NULL"; + break; + case 3: //speed + return QString::number(bus.speed); + case 4: //Listen Only + return (bus.listenOnly) ? "True" : "False"; + case 5: //Single Wire + return (bus.singleWire) ? "True" : "False"; + case 6: //Status + return (conn_p->getStatus()==CANCon::CONNECTED) ? "Connected" : "Not Connected"; + case 7: //Active + return (bus.active) ? "True" : "False"; + default: {} + } + } + + return QVariant(); +} + + +void CANConnectionModel::add(CANConnection* pConn_p) +{ + CANConManager* manager = CANConManager::getInstance(); + + beginResetModel(); + manager->add(pConn_p); + endResetModel(); +} + + +void CANConnectionModel::remove(CANConnection* pConn_p) +{ + CANConManager* manager = CANConManager::getInstance(); + + beginResetModel(); + manager->remove(pConn_p); + endResetModel(); +} + + +CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const +{ + if (pIdx < 0) + return NULL; + + int i=0; + QList& conns = CANConManager::getInstance()->getConnections(); + + foreach(CANConnection* conn_p, conns) + { + if( i <= pIdx && pIdx < i+conn_p->getNumBuses() ) { + pBusId = pIdx - i; + return conn_p; + } + + i+= conn_p->getNumBuses(); + } + + return NULL; +} + + +void CANConnectionModel::refresh(int pIndex) +{ + QModelIndex begin; + QModelIndex end; + + if(pIndex>=0) { + begin = createIndex(pIndex, 0); + end = createIndex(pIndex, columnCount()-1); + } + else { + begin = createIndex(0, 0); + end = createIndex(rowCount()-1, columnCount()-1); + } + dataChanged(begin, end, QVector(Qt::DisplayRole)); +} diff --git a/connections/canconnectionmodel.h b/connections/canconnectionmodel.h new file mode 100644 index 00000000..68a8d453 --- /dev/null +++ b/connections/canconnectionmodel.h @@ -0,0 +1,33 @@ +#ifndef CANCONNECTIONMODEL_H +#define CANCONNECTIONMODEL_H + + +#include + +#include "canbus.h" +#include "connections/canconnection.h" +#include "connectionwindow.h" + + +class CANConnectionModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit CANConnectionModel(QObject *parent = 0); + virtual ~CANConnectionModel(); + + // from abstractmodel: + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + void add(CANConnection* pConn_p); + void remove(CANConnection* pConn_p); + + CANConnection* getAtIdx(int, int&) const; + void refresh(int pIndex=-1); +}; + +#endif // CANCONNECTIONMODEL_H diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp new file mode 100644 index 00000000..782385a4 --- /dev/null +++ b/connections/connectionwindow.cpp @@ -0,0 +1,512 @@ +#include +#include + +#include "connectionwindow.h" +#include "mainwindow.h" +#include "ui_connectionwindow.h" +#include "connections/canconfactory.h" +#include "connections/canconmanager.h" +#include "canbus.h" + + + +ConnectionWindow::ConnectionWindow(QWidget *parent) : + QDialog(parent), + ui(new Ui::ConnectionWindow) +{ + ui->setupUi(this); + + QSettings settings; + + qRegisterMetaType("CANBus"); + qRegisterMetaType("const CANFrame *"); + qRegisterMetaType *>("const QList *"); + + + connModel = new CANConnectionModel(this); + ui->tableConnections->setModel(connModel); + ui->tableConnections->setColumnWidth(0, 50); + ui->tableConnections->setColumnWidth(1, 110); + ui->tableConnections->setColumnWidth(2, 110); + ui->tableConnections->setColumnWidth(3, 110); + ui->tableConnections->setColumnWidth(4, 75); + ui->tableConnections->setColumnWidth(5, 75); + ui->tableConnections->setColumnWidth(6, 75); + ui->tableConnections->setColumnWidth(7, 75); + ui->ckSingleWire->setChecked(settings.value("Main/SingleWireMode", false).toBool()); + + ui->cbSpeed->addItem(tr("125000")); + ui->cbSpeed->addItem(tr("250000")); + ui->cbSpeed->addItem(tr("500000")); + ui->cbSpeed->addItem(tr("1000000")); + ui->cbSpeed->addItem(tr("33333")); + + /* load connection configuration */ + loadConnections(); + + ui->rbSocketCAN->setEnabled(isSocketCanAvailable()); +#ifdef Q_OS_WIN + ui->rbKvaser->setEnabled(true); +#endif + + connect(ui->btnOK, &QAbstractButton::clicked, this, &ConnectionWindow::handleOKButton); + connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); + connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); + connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); + connect(ui->btnRevert, &QPushButton::clicked, this, &ConnectionWindow::handleRevert); + connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged); + connect(ui->btnNewConn, &QPushButton::clicked, this, &ConnectionWindow::handleNewConn); + connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll); + connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll); + connect(ui->btnRemoveBus, &QPushButton::clicked, this, &ConnectionWindow::handleRemoveConn); +} + +ConnectionWindow::~ConnectionWindow() +{ + QList& conns = CANConManager::getInstance()->getConnections(); + CANConnection* conn_p; + + /* save configuration */ + saveConnections(); + + /* delete connections */ + while(!conns.isEmpty()) + { + conn_p = conns.takeFirst(); + conn_p->stop(); + delete conn_p; + } + + delete ui; +} + + +void ConnectionWindow::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + qDebug() << "Show connectionwindow"; + ui->tableConnections->selectRow(0); + currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); +} + + +void ConnectionWindow::setSuspendAll(bool pSuspend) +{ + QList& conns = CANConManager::getInstance()->getConnections(); + + foreach(CANConnection* conn_p, conns) + conn_p->suspend(pSuspend); + + connModel->refresh(); +} + + +void ConnectionWindow::setActiveAll(bool pActive) +{ + CANBus bus; + QList& conns = CANConManager::getInstance()->getConnections(); + + foreach(CANConnection* conn_p, conns) + { + for(int i=0 ; igetNumBuses() ; i++) { + if( conn_p->getBusSettings(i, bus) ) { + bus.active = pActive; + conn_p->setBusSettings(i, bus); + } + } + } + + connModel->refresh(); +} + + +void ConnectionWindow::handleNewConn() +{ + ui->tableConnections->setCurrentIndex(QModelIndex()); + currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); +} + + +void ConnectionWindow::handleEnableAll() +{ + setActiveAll(true); +} + +void ConnectionWindow::handleDisableAll() +{ + setActiveAll(false); +} + +void ConnectionWindow::handleConnTypeChanged() +{ + if (ui->rbGVRET->isChecked()) selectSerial(); + if (ui->rbKvaser->isChecked()) selectKvaser(); + if (ui->rbSocketCAN->isChecked()) selectSocketCan(); +} + + +/* status */ +void ConnectionWindow::connectionStatus(CANCon::status pStatus) +{ + Q_UNUSED(pStatus); + + qDebug() << "Connectionstatus changed"; + connModel->refresh(); +} + + +void ConnectionWindow::handleOKButton() +{ + int whichRow = ui->tableConnections->selectionModel()->currentIndex().row(); + + CANConnection* conn_p = NULL; + + if (whichRow > -1) + { + /* set information for selected connection */ + int busId; + CANBus bus; + bool ret; + + conn_p = connModel->getAtIdx(whichRow, busId); + if(!conn_p) return; + + ret = conn_p->getBusSettings(busId, bus); + if(!ret) return; + + + bus.setListenOnly(ui->ckListenOnly->isChecked()); + bus.setSingleWire(ui->ckSingleWire->isChecked()); + bus.setEnabled(ui->ckEnabled->isChecked()); + bus.setSpeed(ui->cbSpeed->currentText().toInt()); + /* update bus settings */ + conn_p->setBusSettings(busId, bus); + + connModel->refresh(whichRow); + } + else if( ! CANConManager::getInstance()->getByName(getPortName()) ) + { + /* create connection */ + conn_p = create(getConnectionType(), getPortName()); + if(!conn_p) + return; + + for (int i=0 ; igetNumBuses() ; i++) { + /* set bus configuration */ + CANBus bus; + bus.active = ui->ckEnabled->isChecked(); + bus.listenOnly = ui->ckListenOnly->isChecked(); + bus.singleWire = ui->ckSingleWire->isChecked(); + + bus.speed = ui->cbSpeed->currentText().toInt(); + + /* update bus settings */ + conn_p->setBusSettings(i, bus); + } + + /* add connection to model */ + connModel->add(conn_p); + } +} + + + +void ConnectionWindow::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous); + + int selIdx = current.row(); + + /* enable / diable connection type */ + ui->stPort->setEnabled(selIdx==-1); + ui->gbType->setEnabled(selIdx==-1); + ui->lPort->setEnabled(selIdx==-1); + + /* set parameters */ + if (selIdx == -1) + { + ui->btnOK->setText(tr("Create New Connection")); + ui->rbGVRET->setChecked(true); + ui->ckListenOnly->setChecked(false); + ui->ckSingleWire->setChecked(false); + ui->ckEnabled->setChecked(false); + setSpeed(0); + setPortName(CANCon::GVRET_SERIAL, ""); + } + else + { + int busId; + bool ret; + CANBus bus; + CANConnection* conn_p = connModel->getAtIdx(selIdx, busId); + if(!conn_p) return; + ret = conn_p->getBusSettings(busId, bus); + if(!ret) return; + + ui->btnOK->setText(tr("Update Connection Settings")); + ui->ckListenOnly->setChecked(bus.isListenOnly()); + ui->ckSingleWire->setChecked(bus.isSingleWire()); + ui->ckEnabled->setChecked(bus.isActive()); + setSpeed(bus.getSpeed()); + setPortName(conn_p->getType(), conn_p->getPort()); + } +} + + +void ConnectionWindow::selectSerial() +{ + /* set combobox page visible */ + ui->stPort->setCurrentWidget(ui->cbPage); + ui->cbSpeed->setEnabled(true); + + ui->cbPort->clear(); + ports = QSerialPortInfo::availablePorts(); + + for (int i = 0; i < ports.count(); i++) + ui->cbPort->addItem(ports[i].portName()); +} + +void ConnectionWindow::selectKvaser() +{ + /* set combobox page visible */ + ui->stPort->setCurrentWidget(ui->cbPage); + ui->cbSpeed->setEnabled(false); +} + +void ConnectionWindow::selectSocketCan() +{ + /* set edit text page visible */ + ui->stPort->setCurrentWidget(ui->etPage); +} + +void ConnectionWindow::setSpeed(int speed0) +{ + for (int i = 0; i < ui->cbSpeed->count(); i++) + { + if (ui->cbSpeed->itemText(i).toInt() == speed0) + { + ui->cbSpeed->setCurrentIndex(i); + return; + } + } + + /* add custom speed */ + ui->cbSpeed->addItem(QString::number(speed0)); + ui->cbSpeed->setCurrentIndex(ui->cbSpeed->count() - 1); +} + +void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName) +{ + switch(pType) + { + case CANCon::GVRET_SERIAL: + ui->rbGVRET->setChecked(true); + ui->cbSpeed->setEnabled(true); + ui->ckListenOnly->setEnabled(true); + ui->ckSingleWire->setEnabled(true); + break; + case CANCon::KVASER: + ui->rbKvaser->setChecked(true); + break; + case CANCon::SOCKETCAN: + ui->rbSocketCAN->setChecked(true); + //you can't configure any of the below three with socketcan so dim them out + ui->cbSpeed->setEnabled(false); + ui->ckListenOnly->setEnabled(false); + ui->ckSingleWire->setEnabled(false); + break; + default: {} + } + + /* refresh names whenever needed */ + handleConnTypeChanged(); + + switch(pType) + { + case CANCon::GVRET_SERIAL: + { + int idx = ui->cbPort->findText(pPortName); + if( idx<0 ) idx=0; + ui->cbPort->setCurrentIndex(idx); + break; + } + case CANCon::SOCKETCAN: + { + ui->lePort->setText(pPortName); + break; + } + default: {} + } +} + + +//-1 means leave it at whatever it booted up to. 0 means disable. Otherwise the actual rate we want. +int ConnectionWindow::getSpeed() +{ + switch (ui->cbSpeed->currentIndex()) + { + case -1: + case 0: + return -1; + case 1: + return 0; + default: + return (ui->cbSpeed->currentText().toInt()); + } +} + +QString ConnectionWindow::getPortName() +{ + switch( getConnectionType() ) { + case CANCon::GVRET_SERIAL: + case CANCon::KVASER: + return ui->cbPort->currentText(); + case CANCon::SOCKETCAN: + return ui->lePort->text(); + default: + qDebug() << "getPortName: can't get port"; + } + + return ""; +} + +CANCon::type ConnectionWindow::getConnectionType() +{ + if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL; + if (ui->rbKvaser->isChecked()) return CANCon::KVASER; + if (ui->rbSocketCAN->isChecked()) return CANCon::SOCKETCAN; + + qDebug() << "getConnectionType: error"; + return CANCon::NONE; +} + + +void ConnectionWindow::setSWMode(bool mode) +{ + ui->ckSingleWire->setChecked(mode); +} + +bool ConnectionWindow::getSWMode() +{ + if (ui->ckSingleWire->checkState() == Qt::Checked) return true; + return false; +} + +void ConnectionWindow::handleRemoveConn() +{ + int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); + if (selIdx <0) return; + + qDebug() << "remove connection at index: " << selIdx; + + int busId; + CANConnection* conn_p = connModel->getAtIdx(selIdx, busId); + if(!conn_p) return; + + /* remove connection from model & manager */ + connModel->remove(conn_p); + + /* stop and delete connection */ + conn_p->stop(); + delete conn_p; + + /* select first connection in list */ + ui->tableConnections->selectRow(0); +} + +void ConnectionWindow::handleRevert() +{ + +} + + +bool ConnectionWindow::isSocketCanAvailable() +{ +#ifdef Q_OS_LINUX + foreach (const QByteArray &backend, QCanBus::instance()->plugins()) { + if (backend == "socketcan") + return true; + } +#endif + return false; +} + + +CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName) +{ + CANConnection* conn_p; + + /* create connection */ + conn_p = CanConFactory::create(pTye, pPortName); + if(conn_p) + { + /* connect signal */ + connect(conn_p, SIGNAL(status(CANCon::status)), + this, SLOT(connectionStatus(CANCon::status))); + + /*TODO add return value and checks */ + conn_p->start(); + } + return conn_p; +} + + +void ConnectionWindow::loadConnections() +{ + qRegisterMetaTypeStreamOperators>(); + qRegisterMetaTypeStreamOperators>(); + qRegisterMetaTypeStreamOperators(); + qRegisterMetaTypeStreamOperators>(); + + QSettings settings; + + /* fill connection list */ + QVector portNames = settings.value("connections/portNames").value>(); + QVector devTypes = settings.value("connections/types").value>(); + QList busses = settings.value("connections/busses").value>(); + + + for(int i=0 ; igetNumBuses() ; j++) + conn_p->setBusSettings(j, busses.takeFirst()); + } + /* add connection to model */ + connModel->add(conn_p); + } + + if (connModel->rowCount() > 0) { + ui->tableConnections->selectRow(0); + } +} + +void ConnectionWindow::saveConnections() +{ + QList& conns = CANConManager::getInstance()->getConnections(); + + QSettings settings; + QVector portNames; + QVector devTypes; + QList busses; + + /* save connections */ + foreach(CANConnection* conn_p, conns) + { + portNames.append(conn_p->getPort()); + devTypes.append(conn_p->getType()); + + for(int i=0 ; igetNumBuses() ; i++) + { + CANBus bus; + conn_p->getBusSettings(i, bus); + busses.append(bus); + } + } + + settings.setValue("connections/portNames", QVariant::fromValue(portNames)); + settings.setValue("connections/types", QVariant::fromValue(devTypes)); + settings.setValue("connections/busses", QVariant::fromValue(busses)); +} diff --git a/connections/connectionwindow.h b/connections/connectionwindow.h new file mode 100644 index 00000000..56062da5 --- /dev/null +++ b/connections/connectionwindow.h @@ -0,0 +1,76 @@ +#ifndef CONNECTIONWINDOW_H +#define CONNECTIONWINDOW_H + + + +#include +#include +#include +#include +#include +#include +#include "canconnectionmodel.h" +#include "connections/canconnection.h" + + +class CANConnectionModel; + +namespace Ui { +class ConnectionWindow; +} + + +class ConnectionWindow : public QDialog +{ + Q_OBJECT + +public: + explicit ConnectionWindow(QWidget *parent = 0); + ~ConnectionWindow(); + void showEvent(QShowEvent *); + + CANCon::type getConnectionType(); + bool getSWMode(); + +signals: + void updateBusSettings(CANBus *bus); + void updatePortName(QString port); + +public slots: + void setSpeed(int speed0); + void setSWMode(bool mode); + + void setSuspendAll(bool pSuspend); + +private slots: + void handleOKButton(); + void handleConnTypeChanged(); + void currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); + void handleRemoveConn(); + void handleEnableAll(); + void handleDisableAll(); + void handleRevert(); + void handleNewConn(); + void connectionStatus(CANCon::status); + +private: + Ui::ConnectionWindow *ui; + QList ports; + QSettings *settings; + CANConnectionModel *connModel; + + void selectSerial(); + void selectKvaser(); + void selectSocketCan(); + bool isSocketCanAvailable(); + int getSpeed(); + QString getPortName(); + void setPortName(CANCon::type pType, QString pPortName); + + void setActiveAll(bool pActive); + CANConnection* create(CANCon::type pTye, QString pPortName); + void loadConnections(); + void saveConnections(); +}; + +#endif // CONNECTIONWINDOW_H diff --git a/serialworker.cpp b/connections/gvretserial.cpp similarity index 51% rename from serialworker.cpp rename to connections/gvretserial.cpp index 61a0b5fd..fbe1ba97 100644 --- a/serialworker.cpp +++ b/connections/gvretserial.cpp @@ -1,56 +1,190 @@ -#include "serialworker.h" - -#include +#include #include -#include +#include +#include #include -SerialWorker::SerialWorker(CANFrameModel *model, QObject *parent) : QObject(parent) -{ +#include "gvretserial.h" + +GVRetSerial::GVRetSerial(QString portName) : + CANConnection(portName, CANCon::GVRET_SERIAL, 2, 4000, true), + mTimer(this) /*NB: set this as parent of timer to manage it from working thread */ +{ + qDebug() << "GVRetSerial()"; + serial = NULL; rx_state = IDLE; rx_step = 0; - buildFrame = new CANFrame; - canModel = model; - ticker = NULL; - framesRapid = 0; - capturing = true; gotValidated = true; isAutoRestart = false; - targetID = -1; - txTimestampBasis = QDateTime::currentMSecsSinceEpoch(); + timeBasis = 0; + lastSystemTimeBasis = 0; + timeAtGVRETSync = 0; readSettings(); } -SerialWorker::~SerialWorker() + +GVRetSerial::~GVRetSerial() { - if (serial != NULL) + stop(); + qDebug() << "~GVRetSerial()"; +} + + +void GVRetSerial::piStarted() +{ + connectDevice(); + + /* start timer */ + connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick())); + mTimer.setInterval(250); //tick four times per second + mTimer.setSingleShot(false); //keep ticking + mTimer.start(); +} + + +void GVRetSerial::piSuspend(bool pSuspend) +{ + /* update capSuspended */ + setCapSuspended(pSuspend); + + /* flush queue if we are suspended */ + if(isCapSuspended()) + getQueue().flush(); +} + + +void GVRetSerial::piStop() +{ + mTimer.stop(); + disconnectDevice(); +} + + +bool GVRetSerial::piGetBusSettings(int pBusIdx, CANBus& pBus) +{ + return getBusConfig(pBusIdx, pBus); +} + + +void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus) +{ + /* sanity checks */ + if( (pBusIdx < 0) || pBusIdx >= getNumBuses()) + return; + + /* copy bus config */ + setBusConfig(pBusIdx, bus); + + qDebug() << "About to update bus " << pBusIdx << " on GVRET"; + if (pBusIdx == 0) { - if (serial->isOpen()) + can0Baud = bus.getSpeed(); + can0Baud |= 0x80000000; + if (bus.isActive()) { - serial->clear(); - serial->close(); + can0Baud |= 0x40000000; + can0Enabled = true; + } + else can0Enabled = false; + if (bus.isListenOnly()) + { + can0Baud |= 0x20000000; + can0ListenOnly = true; } - serial->disconnect(); //disconnect all signals - delete serial; + else can0ListenOnly = false; } - if (ticker != NULL) ticker->stop(); + else if (pBusIdx == 1) + { + can1Baud = bus.getSpeed(); + can1Baud |= 0x80000000; + if (bus.isActive()) + { + can1Baud |= 0x40000000; + can1Enabled = true; + } + else can1Enabled = false; + + if (bus.isListenOnly()) + { + can1Baud |= 0x20000000; + can1ListenOnly = true; + } + else can1ListenOnly = false; + + if (bus.isSingleWire()) + { + can1Baud |= 0x10000000; + deviceSingleWireMode = 1; + } + else deviceSingleWireMode = 0; + } + + /* update baud rates */ + QByteArray buffer; + qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud; + buffer[0] = (char)0xF1; //start of a command over serial + buffer[1] = 5; //setup canbus + buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first + buffer[3] = (unsigned char)(can0Baud >> 8); + buffer[4] = (unsigned char)(can0Baud >> 16); + buffer[5] = (unsigned char)(can0Baud >> 24); + buffer[6] = (unsigned char)(can1Baud & 0xFF); //four bytes of ID LSB first + buffer[7] = (unsigned char)(can1Baud >> 8); + buffer[8] = (unsigned char)(can1Baud >> 16); + buffer[9] = (unsigned char)(can1Baud >> 24); + buffer[10] = 0; + if (serial == NULL) return; + if (!serial->isOpen()) return; + serial->write(buffer); } -void SerialWorker::run() + +bool GVRetSerial::piSendFrame(const CANFrame& frame) { - ticker = new QTimer; - connect(ticker, SIGNAL(timeout()), this, SLOT(handleTick())); + QByteArray buffer; + unsigned int c; + int ID; - ticker->setInterval(250); //tick four times per second - ticker->setSingleShot(false); //keep ticking - ticker->start(); + //qDebug() << "Sending out GVRET frame with id " << frame.ID << " on bus " << frame.bus; + + framesRapid++; + + if (serial == NULL) return false; + if (!serial->isOpen()) return false; + //if (!isConnected) return false; + + ID = frame.ID; + if (frame.extended) ID |= 1 << 31; + + buffer[0] = (char)0xF1; //start of a command over serial + buffer[1] = 0; //command ID for sending a CANBUS frame + buffer[2] = (unsigned char)(ID & 0xFF); //four bytes of ID LSB first + buffer[3] = (unsigned char)(ID >> 8); + buffer[4] = (unsigned char)(ID >> 16); + buffer[5] = (unsigned char)(ID >> 24); + buffer[6] = (unsigned char)((frame.bus) & 1); + buffer[7] = (unsigned char)frame.len; + for (c = 0; c < frame.len; c++) + { + buffer[8 + c] = frame.data[c]; + } + buffer[8 + frame.len] = 0; + + //qDebug() << "writing " << buffer.length() << " bytes to serial port"; + serial->write(buffer); + + return true; } -void SerialWorker::readSettings() + + +/****************************************************************/ + +void GVRetSerial::readSettings() { QSettings settings; @@ -59,30 +193,25 @@ void SerialWorker::readSettings() doValidation = true; } else doValidation = false; - //doValidation=false; } -void SerialWorker::setSerialPort(QSerialPortInfo *port) + +void GVRetSerial::connectDevice() { QSettings settings; - currentPort = port; + /* disconnect device */ + if(serial) + disconnectDevice(); - if (serial != NULL) - { - if (serial->isOpen()) - { - serial->clear(); - serial->close(); - } - serial->disconnect(); //disconnect all signals - delete serial; + /* open new device */ + serial = new QSerialPort(QSerialPortInfo(getPort())); + if(!serial) { + qDebug() << "can't open serial port " << getPort(); + return; } - serial = new QSerialPort(*port); - - qDebug() << "Serial port name is " << port->portName(); - //serial->setBaudRate(10000000); //more speed! probably does nothing for USB serial + /* configure */ serial->setDataBits(serial->Data8); serial->setFlowControl(serial->HardwareControl); //this is important though if (!serial->open(QIODevice::ReadWrite)) @@ -91,6 +220,8 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port) } serial->setDataTerminalReady(true); //you do need to set these or the fan gets dirty serial->setRequestToSend(true); + + QByteArray output; output.append((char)0xE7); //this puts the device into binary comm mode output.append((char)0xE7); @@ -101,7 +232,7 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port) output.append((char)0xF1); //another command to the GVRET output.append((char)0x07); //request device information - output.append((char)0xF1); + /*output.append((char)0xF1); output.append((char)0x08); //setting singlewire mode if (settings.value("Main/SingleWireMode", false).toBool()) { @@ -110,7 +241,7 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port) else { output.append((char)0xFF); //signal we don't want single wire mode - } + }*/ output.append((char)0xF1); //yet another command output.append((char)0x09); //comm validation command @@ -121,26 +252,51 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port) continuousTimeSync = true; serial->write(output); - if (doValidation) connected = false; - else connected = true; + + if(doValidation) { + QTimer::singleShot(1000, this, SLOT(connectionTimeout())); + } + else { + setStatus(CANCon::CONNECTED); + emit status(getStatus()); + } + + /* connect reading event */ connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData())); - if (doValidation) QTimer::singleShot(1000, this, SLOT(connectionTimeout())); } -void SerialWorker::connectionTimeout() + +void GVRetSerial::disconnectDevice() { + if (serial != NULL) + { + if (serial->isOpen()) + { + serial->clear(); + serial->close(); + + } + serial->disconnect(); //disconnect all signals + delete serial; + serial = NULL; + } +} + + +void GVRetSerial::connectionTimeout() { //one second after trying to connect are we actually connected? - if (!connected) //no? + //if (CANCon::NOT_CONNECTED==getStatus()) //no? + if (!gotValidated) { //then emit the the failure signal and see if anyone cares qDebug() << "Failed to connect to GVRET at that com port"; - //ticker->stop(); - closeSerialPort(); //make sure it's properly closed anyway - emit connectionFailure(); + + disconnectDevice(); } } -void SerialWorker::readSerialData() + +void GVRetSerial::readSerialData() { QByteArray data = serial->readAll(); unsigned char c; @@ -148,86 +304,13 @@ void SerialWorker::readSerialData() for (int i = 0; i < data.length(); i++) { c = data.at(i); + //qDebug() << c << " " << QString::number(c, 16) << " " << QString(c); procRXChar(c); } - if (framesRapid > 0) - { - emit frameUpdateRapid(framesRapid); - framesRapid = 0; - } } -void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0) -{ - QByteArray buffer; - int c; - int ID; - CANFrame tempFrame = *frame; - tempFrame.isReceived = false; - tempFrame.timestamp = ((QDateTime::currentMSecsSinceEpoch() - txTimestampBasis) * 1000); - - //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(tempFrame, false); - framesRapid++; - - if (serial == NULL) return; - if (!serial->isOpen()) return; - if (!connected) return; - - ID = frame->ID; - if (frame->extended) ID |= 1 << 31; - buffer[0] = (char)0xF1; //start of a command over serial - buffer[1] = 0; //command ID for sending a CANBUS frame - buffer[2] = (unsigned char)(ID & 0xFF); //four bytes of ID LSB first - buffer[3] = (unsigned char)(ID >> 8); - buffer[4] = (unsigned char)(ID >> 16); - buffer[5] = (unsigned char)(ID >> 24); - buffer[6] = (unsigned char)(bus & 1); - buffer[7] = (unsigned char)frame->len; - for (c = 0; c < frame->len; c++) - { - buffer[8 + c] = frame->data[c]; - } - buffer[8 + frame->len] = 0; - - //qDebug() << "writing " << buffer.length() << " bytes to serial port"; - serial->write(buffer); -} - -//a simple way for another thread to pass us a bunch of frames to send. -//Don't get carried away here. The GVRET firmware only has finite -//buffers and besides, the other end will get buried in traffic. -void SerialWorker::sendFrameBatch(const QList *frames) -{ - sendBulkMutex.lock(); - for (int i = 0; i < frames->length(); i++) sendFrame(&frames->at(i), frames->at(i).bus); - sendBulkMutex.unlock(); -} - -void SerialWorker::updateBaudRates(int Speed1, int Speed2) -{ - QByteArray buffer; - qDebug() << "Got signal to update bauds. 1: " << Speed1 <<" 2: " << Speed2; - buffer[0] = (char)0xF1; //start of a command over serial - buffer[1] = 5; //setup canbus - buffer[2] = (unsigned char)(Speed1 & 0xFF); //four bytes of ID LSB first - buffer[3] = (unsigned char)(Speed1 >> 8); - buffer[4] = (unsigned char)(Speed1 >> 16); - buffer[5] = (unsigned char)(Speed1 >> 24); - buffer[6] = (unsigned char)(Speed2 & 0xFF); //four bytes of ID LSB first - buffer[7] = (unsigned char)(Speed2 >> 8); - buffer[8] = (unsigned char)(Speed2 >> 16); - buffer[9] = (unsigned char)(Speed2 >> 24); - buffer[10] = 0; - if (serial == NULL) return; - if (!serial->isOpen()) return; - serial->write(buffer); -} - -void SerialWorker::procRXChar(unsigned char c) +void GVRetSerial::procRXChar(unsigned char c) { switch (rx_state) { @@ -277,58 +360,70 @@ void SerialWorker::procRXChar(unsigned char c) switch (rx_step) { case 0: - buildFrame->timestamp = c; + buildFrame.timestamp = c; break; case 1: - buildFrame->timestamp |= (uint)(c << 8); + buildFrame.timestamp |= (uint)(c << 8); break; case 2: - buildFrame->timestamp |= (uint)c << 16; + buildFrame.timestamp |= (uint)c << 16; break; case 3: - buildFrame->timestamp |= (uint)c << 24; + buildFrame.timestamp |= (uint)c << 24; + + buildFrame.timestamp += timeBasis; break; case 4: - buildFrame->ID = c; + buildFrame.ID = c; break; case 5: - buildFrame->ID |= c << 8; + buildFrame.ID |= c << 8; break; case 6: - buildFrame->ID |= c << 16; + buildFrame.ID |= c << 16; break; case 7: - buildFrame->ID |= c << 24; - if ((buildFrame->ID & 1 << 31) == 1 << 31) + buildFrame.ID |= c << 24; + if ((buildFrame.ID & 1 << 31) == 1u << 31) { - buildFrame->ID &= 0x7FFFFFFF; - buildFrame->extended = true; + buildFrame.ID &= 0x7FFFFFFF; + buildFrame.extended = true; } - else buildFrame->extended = false; + else buildFrame.extended = false; break; case 8: - buildFrame->len = c & 0xF; - if (buildFrame->len > 8) buildFrame->len = 8; - buildFrame->bus = (c & 0xF0) >> 4; + buildFrame.len = c & 0xF; + if (buildFrame.len > 8) buildFrame.len = 8; + buildFrame.bus = (c & 0xF0) >> 4; break; default: - if (rx_step < buildFrame->len + 9) + if (rx_step < buildFrame.len + 9) { - buildFrame->data[rx_step - 9] = c; + buildFrame.data[rx_step - 9] = c; } else { rx_state = IDLE; rx_step = 0; - //qDebug() << "emit from serial handler to main form id: " << buildFrame->ID; - if (capturing) + buildFrame.isReceived = true; + + if (!isCapSuspended()) { - buildFrame->isReceived = true; - canModel->addFrame(*buildFrame, false); + /* get frame from queue */ + CANFrame* frame_p = getQueue().get(); + if(frame_p) { + //qDebug() << "GVRET got frame on bus " << frame_p->bus; + /* copy frame */ + *frame_p = buildFrame; + checkTargettedFrame(buildFrame); + /* enqueue frame */ + getQueue().queue(); + } + else + qDebug() << "can't get a frame, ERROR"; + //take the time the frame came in and try to resync the time base. - if (continuousTimeSync) txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - (buildFrame->timestamp / 1000); - framesRapid++; - if (buildFrame->ID == targetID) emit gotTargettedFrame(canModel->rowCount() - 1); + //if (continuousTimeSync) txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - (buildFrame.timestamp / 1000); } } break; @@ -350,7 +445,10 @@ void SerialWorker::procRXChar(unsigned char c) case 3: buildTimeBasis += ((uint32_t)c << 24); qDebug() << "GVRET firmware reports timestamp of " << buildTimeBasis; - txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - ((uint64_t)buildTimeBasis / (uint64_t)1000ull); + timeAtGVRETSync = QDateTime::currentMSecsSinceEpoch() * 1000; + + rebuildLocalTimeBasis(); + continuousTimeSync = false; rx_state = IDLE; break; @@ -381,7 +479,8 @@ void SerialWorker::procRXChar(unsigned char c) switch (rx_step) { case 0: - can0Enabled = c; + can0Enabled = (c & 0xF); + can0ListenOnly = (c >> 4); break; case 1: can0Baud = c; @@ -396,7 +495,9 @@ void SerialWorker::procRXChar(unsigned char c) can0Baud |= c << 24; break; case 5: - can1Enabled = c; + can1Enabled = (c & 0xF); + can1ListenOnly = (c >> 4); + deviceSingleWireMode = (c >> 6); break; case 6: can1Baud = c; @@ -412,10 +513,28 @@ void SerialWorker::procRXChar(unsigned char c) rx_state = IDLE; qDebug() << "Baud 0 = " << can0Baud; qDebug() << "Baud 1 = " << can1Baud; - if (!can1Enabled) can1Baud = 0; - if (!can0Enabled) can0Baud = 0; - connected = true; - emit connectionSuccess(can0Baud, can1Baud); + + can0Baud |= 0x80000000; + if (can0Enabled) can0Baud |= 0x40000000; + if (can0ListenOnly) can0Baud |= 0x20000000; + + can1Baud |= 0x80000000; + if (can1Enabled) can1Baud |= 0x40000000; + if (can1ListenOnly) can1Baud |= 0x20000000; + if (deviceSingleWireMode > 0) can1Baud |= 0x10000000; + + setStatus(CANCon::CONNECTED); + emit status(getStatus()); + + int can0Status = 0x78; //updating everything we can update + int can1Status = 0x78; + if (can0Enabled) can0Status +=1; + if (can0ListenOnly) can0Status += 4; + if (can1Enabled) can1Status += 1; + if (deviceSingleWireMode > 0) can1Status += 2; + if (can1ListenOnly) can1Status += 4; + //emit busStatus(busBase, can0Baud & 0xFFFFF, can0Status); + //emit busStatus(busBase + 1, can1Baud & 0xFFFFF, can1Status); break; } rx_step++; @@ -458,11 +577,29 @@ void SerialWorker::procRXChar(unsigned char c) } } -void SerialWorker::handleTick() +void GVRetSerial::rebuildLocalTimeBasis() { - //qDebug() << "Tick!"; + qDebug() << "Rebuilding GVRET time base. GVRET local base = " << buildTimeBasis; + + /* + our time basis is the value we have to modulate the main system basis by in order + to sync the GVRET timestamps to the rest of the system. + The rest of the system uses CANConManager::getInstance()->getTimeBasis as the basis. + GVRET returns to us the current time since boot up in microseconds. + timeAtGVRETSync stores the "system" timestamp when the GVRET timestamp was retrieved. + */ + lastSystemTimeBasis = CANConManager::getInstance()->getTimeBasis(); + int64_t systemDelta = timeAtGVRETSync - lastSystemTimeBasis; + int32_t localDelta = buildTimeBasis - systemDelta; + timeBasis = -localDelta; +} - if (connected) +void GVRetSerial::handleTick() +{ + if (lastSystemTimeBasis != CANConManager::getInstance()->getTimeBasis()) rebuildLocalTimeBasis(); + //qDebug() << "Tick!"; +/* + if( CANCon::CONNECTED == getStatus() ) { if (!gotValidated && doValidation) { @@ -470,24 +607,23 @@ void SerialWorker::handleTick() if (serial->isOpen()) //if it's still false we have a problem... { qDebug() << "Comm validation failed. "; - closeSerialPort(); //start by stopping everything. + + setStatus(CANCon::NOT_CONNECTED); + emit status(getStatus()); + + disconnectDevice(); //start by stopping everything. //Then wait 500ms and restart the connection automatically - QTimer::singleShot(500, this, SLOT(handleReconnect())); + QTimer::singleShot(500, this, SLOT(connectDevice())); return; } } } - +*/ if (doValidation && serial && serial->isOpen()) sendCommValidation(); } -void SerialWorker::handleReconnect() -{ - qDebug() << "Automatically reopening the connection"; - setSerialPort(currentPort); //then go back through the re-init -} -void SerialWorker::sendCommValidation() +void GVRetSerial::sendCommValidation() { QByteArray output; @@ -501,35 +637,5 @@ void SerialWorker::sendCommValidation() serial->write(output); } -//totally shuts down the whole thing -void SerialWorker::closeSerialPort() -{ - if (serial == NULL) return; - if (serial->isOpen()) - { - serial->clear(); - serial->close(); - } - serial->disconnect(); - //do not stop the ticker here. It always stays running now. - //ticker->stop(); - delete serial; - serial = NULL; -} - -void SerialWorker::stopFrameCapture() -{ - qDebug() << "Stopping frame capture"; - capturing = false; -} -void SerialWorker::startFrameCapture() -{ - qDebug() << "Starting up frame capture"; - capturing = true; -} -void SerialWorker::targetFrameID(int target) -{ - targetID = target; -} diff --git a/connections/gvretserial.h b/connections/gvretserial.h new file mode 100644 index 00000000..5180b274 --- /dev/null +++ b/connections/gvretserial.h @@ -0,0 +1,93 @@ +#ifndef GVRETSERIAL_H +#define GVRETSERIAL_H + +#include +#include +#include +#include + +/*************/ +#include +/*************/ + +#include "canframemodel.h" +#include "canconnection.h" +#include "canconmanager.h" + +namespace SERIALSTATE { + +enum STATE //keep this enum synchronized with the Arduino firmware project +{ + IDLE, + GET_COMMAND, + BUILD_CAN_FRAME, + TIME_SYNC, + GET_DIG_INPUTS, + GET_ANALOG_INPUTS, + SET_DIG_OUTPUTS, + SETUP_CANBUS, + GET_CANBUS_PARAMS, + GET_DEVICE_INFO, + SET_SINGLEWIRE_MODE +}; + +} + + +using namespace SERIALSTATE; +class GVRetSerial : public CANConnection +{ + Q_OBJECT + +public: + GVRetSerial(QString portName); + virtual ~GVRetSerial(); + +protected: + + virtual void piStarted(); + virtual void piStop(); + virtual void piSetBusSettings(int pBusIdx, CANBus pBus); + virtual bool piGetBusSettings(int pBusIdx, CANBus& pBus); + virtual void piSuspend(bool pSuspend); + virtual bool piSendFrame(const CANFrame&) ; + + void disconnectDevice(); + +private slots: + void connectDevice(); + void connectionTimeout(); + void readSerialData(); + void handleTick(); + +private: + void readSettings(); + void procRXChar(unsigned char); + void sendCommValidation(); + void rebuildLocalTimeBasis(); + +protected: + QTimer mTimer; + QThread mThread; + + bool doValidation; + bool gotValidated; + bool isAutoRestart; + bool continuousTimeSync; + QSerialPort *serial; + int framesRapid; + STATE rx_state; + uint32_t rx_step; + CANFrame buildFrame; + int can0Baud, can1Baud; + bool can0Enabled, can1Enabled; + bool can0ListenOnly, can1ListenOnly; + int deviceBuildNum; + int deviceSingleWireMode; + uint32_t buildTimeBasis; + int32_t timeBasis; + uint64_t lastSystemTimeBasis; + uint64_t timeAtGVRETSync; +}; + +#endif // GVRETSERIAL_H diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp new file mode 100644 index 00000000..7402a486 --- /dev/null +++ b/connections/socketcan.cpp @@ -0,0 +1,240 @@ +#include +#include +#include + +#include "socketcan.h" + + + +/***********************************/ +/**** class definition ****/ +/***********************************/ + +SocketCan::SocketCan(QString portName) : + CANConnection(portName, CANCon::SOCKETCAN, 1, 4000, true), + mDev_p(NULL), + mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */ +{ +} + + +SocketCan::~SocketCan() +{ + stop(); +} + + +void SocketCan::piStarted() +{ + connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection())); + mTimer.setInterval(1000); + mTimer.setSingleShot(false); //keep ticking + mTimer.start(); +} + + +void SocketCan::piSuspend(bool pSuspend) +{ + /* update capSuspended */ + setCapSuspended(pSuspend); + + /* flush queue if we are suspended */ + if(isCapSuspended()) + getQueue().flush(); +} + + +void SocketCan::piStop() { + mTimer.stop(); + disconnectDevice(); +} + + +bool SocketCan::piGetBusSettings(int pBusIdx, CANBus& pBus) +{ + return getBusConfig(pBusIdx, pBus); +} + + +void SocketCan::piSetBusSettings(int pBusIdx, CANBus bus) +{ + /* sanity checks */ + if(0 != pBusIdx) + return; + + /* disconnect device if we have one connected */ + if(mDev_p) + disconnectDevice(); + + /* copy bus config */ + setBusConfig(0, bus); + + /* if bus is not active we are done */ + if(!bus.active) + return; + + /* create device */ + mDev_p = QCanBus::instance()->createDevice("socketcan", getPort()); + if (!mDev_p) { + disconnectDevice(); + qDebug() << "can't create device"; + return; + } + + /* connect slots */ + connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SocketCan::errorReceived); + connect(mDev_p, &QCanBusDevice::framesWritten, this, &SocketCan::framesWritten); + connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCan::framesReceived); + + /* set configuration */ + /*if (p.useConfigurationEnabled) { + foreach (const SettingsDialog::ConfigurationItem &item, p.configurations) + mDev->setConfigurationParameter(item.first, item.second); + }*/ + + //You cannot set the speed of a socketcan interface, it has to be set with console commands. + //mDev_p->setConfigurationParameter(QCanBusDevice::BitRateKey, bus.speed); + + /* connect device */ + if (!mDev_p->connectDevice()) { + disconnectDevice(); + qDebug() << "can't connect device"; + } +} + + +bool SocketCan::piSendFrame(const CANFrame& pFrame) +{ + /* sanity checks */ + if(0 != pFrame.bus || pFrame.len>8) + return false; + + /* fill frame */ + QCanBusFrame frame; + frame.setFrameId(pFrame.ID); + frame.setExtendedFrameFormat(false); + frame.setPayload(QByteArray((const char*)pFrame.data, pFrame.len)); + + return mDev_p->writeFrame(frame); +} + + +/***********************************/ +/**** private methods ****/ +/***********************************/ + + +/* disconnect device */ +void SocketCan::disconnectDevice() { + if(mDev_p) { + mDev_p->disconnectDevice(); + delete mDev_p; + mDev_p = Q_NULLPTR; + } +} + + +void SocketCan::errorReceived(QCanBusDevice::CanBusError error) const +{ + switch (error) { + case QCanBusDevice::ReadError: + case QCanBusDevice::WriteError: + case QCanBusDevice::ConnectionError: + case QCanBusDevice::ConfigurationError: + case QCanBusDevice::UnknownError: + qWarning() << mDev_p->errorString(); + default: + break; + } +} + +void SocketCan::framesWritten(qint64 count) +{ + Q_UNUSED(count); + //qDebug() << "Number of frames written:" << count; +} + +void SocketCan::framesReceived() +{ + uint64_t timeBasis = CANConManager::getInstance()->getTimeBasis(); + + /* sanity checks */ + if(!mDev_p) + return; + + /* read frame */ + while(true) + { + const QCanBusFrame recFrame = mDev_p->readFrame(); + + /* exit case */ + if(!recFrame.isValid()) + break; + + /* drop frame if capture is suspended */ + if(isCapSuspended()) + continue; + + /* check frame */ + if( !recFrame.payload().isEmpty() && + recFrame.payload().length()<=8 ) + { + CANFrame* frame_p = getQueue().get(); + if(frame_p) { + frame_p->len = recFrame.payload().length(); + frame_p->bus = 0; + memcpy(frame_p->data, recFrame.payload().data(), frame_p->len); + frame_p->extended = false; + frame_p->ID = recFrame.frameId(); + frame_p->isReceived = true; + frame_p->timestamp = (recFrame.timeStamp().seconds()*1000000 + recFrame.timeStamp().microSeconds()) - timeBasis; + + checkTargettedFrame(*frame_p); + + /* enqueue frame */ + getQueue().queue(); + } +#if 0 + else + qDebug() << "can't get a frame, ERROR"; +#endif + } + } +} + + +void SocketCan::testConnection() { + QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort()); + + switch(getStatus()) + { + case CANCon::CONNECTED: + if (!dev_p || !dev_p->connectDevice()) { + /* we have lost connectivity */ + disconnectDevice(); + + setStatus(CANCon::NOT_CONNECTED); + emit status(getStatus()); + } + break; + case CANCon::NOT_CONNECTED: + if (dev_p && dev_p->connectDevice()) { + if(!mDev_p) { + /* try to reconnect */ + CANBus bus; + if(getBusConfig(0, bus)) + setBusSettings(0, bus); + } + /* disconnect test instance */ + dev_p->disconnectDevice(); + + setStatus(CANCon::CONNECTED); + emit status(getStatus()); + } + break; + default: {} + } + + if(dev_p) + delete dev_p; +} diff --git a/connections/socketcan.h b/connections/socketcan.h new file mode 100644 index 00000000..debd0916 --- /dev/null +++ b/connections/socketcan.h @@ -0,0 +1,45 @@ +#ifndef SocketCan_H +#define SocketCan_H + +#include +#include +#include +#include + +#include "canframemodel.h" +#include "canconnection.h" +#include "canconmanager.h" + + +class SocketCan : public CANConnection +{ + Q_OBJECT + +public: + SocketCan(QString portName); + virtual ~SocketCan(); + +protected: + + virtual void piStarted(); + virtual void piStop(); + virtual void piSetBusSettings(int pBusIdx, CANBus pBus); + virtual bool piGetBusSettings(int pBusIdx, CANBus& pBus); + virtual void piSuspend(bool pSuspend); + virtual bool piSendFrame(const CANFrame&); + + void disconnectDevice(); + +private slots: + void errorReceived(QCanBusDevice::CanBusError) const; + void framesWritten(qint64 count); + void framesReceived(); + void testConnection(); + +protected: + QCanBusDevice* mDev_p; + QTimer mTimer; +}; + + +#endif // SocketCan_H diff --git a/connectionwindow.cpp b/connectionwindow.cpp deleted file mode 100644 index 8a8ea45b..00000000 --- a/connectionwindow.cpp +++ /dev/null @@ -1,247 +0,0 @@ -#include "connectionwindow.h" -#include "ui_connectionwindow.h" -#include - -ConnectionWindow::ConnectionWindow(QWidget *parent) : - QDialog(parent), - ui(new Ui::ConnectionWindow) -{ - ui->setupUi(this); - - settings = new QSettings(); - - int temp = settings->value("Main/DefaultConnectionType", 0).toInt(); - - if (temp == 0) currentConnType = ConnectionType::GVRET_SERIAL; - if (temp == 1) currentConnType = ConnectionType::KVASER; - if (temp == 2) currentConnType = ConnectionType::SOCKETCAN; - - currentPortName = settings->value("Main/DefaultConnectionPort", "").toString(); - - currentSpeed1 = -1; - currentSpeed2 = -1; - - ui->ckSingleWire->setChecked(settings->value("Main/SingleWireMode", false).toBool()); - - ui->cbSpeed0->addItem(tr("")); - ui->cbSpeed0->addItem(tr("Disabled")); - ui->cbSpeed0->addItem(tr("125000")); - ui->cbSpeed0->addItem(tr("250000")); - ui->cbSpeed0->addItem(tr("500000")); - ui->cbSpeed0->addItem(tr("1000000")); - ui->cbSpeed0->addItem(tr("33333")); - - ui->cbSpeed1->addItem(tr("")); - ui->cbSpeed1->addItem(tr("Disabled")); - ui->cbSpeed1->addItem(tr("125000")); - ui->cbSpeed1->addItem(tr("250000")); - ui->cbSpeed1->addItem(tr("500000")); - ui->cbSpeed1->addItem(tr("1000000")); - ui->cbSpeed1->addItem(tr("33333")); - -#ifdef Q_OS_LINUX - ui->rbSocketCAN->setEnabled(true); -#endif - -#ifdef Q_OS_WIN - ui->rbKvaser->setEnabled(true); -#endif - - connect(ui->btnOK, SIGNAL(clicked(bool)), this, SLOT(handleOKButton())); - connect(ui->rbGVRET, SIGNAL(toggled(bool)), this, SLOT(handleConnTypeChanged())); - connect(ui->rbKvaser, SIGNAL(toggled(bool)), this, SLOT(handleConnTypeChanged())); - connect(ui->rbSocketCAN, SIGNAL(toggled(bool)), this, SLOT(handleConnTypeChanged())); -} - -ConnectionWindow::~ConnectionWindow() -{ - delete settings; - delete ui; -} - -void ConnectionWindow::showEvent(QShowEvent* event) -{ - QDialog::showEvent(event); - qDebug() << "Show connectionwindow"; - handleConnTypeChanged(); -} - -void ConnectionWindow::handleConnTypeChanged() -{ - if (ui->rbGVRET->isChecked()) getSerialPorts(); - if (ui->rbKvaser->isChecked()) getKvaserPorts(); - if (ui->rbSocketCAN->isChecked()) getSocketcanPorts(); -} - -void ConnectionWindow::handleOKButton() -{ - QString conn; - int connType = 0; - - if (ui->rbGVRET->isChecked()) - { - conn = "GVRET"; - connType = 0; - currentConnType = ConnectionType::GVRET_SERIAL; - } - - if (ui->rbKvaser->isChecked()) - { - conn = "KVASER"; - connType = 1; - currentConnType = ConnectionType::KVASER; - } - - if (ui->rbSocketCAN->isChecked()) - { - conn = "SOCKETCAN"; - connType = 2; - currentConnType = ConnectionType::SOCKETCAN; - } - - currentPortName = getPortName(); - currentSpeed1 = getSpeed0(); - currentSpeed2 = getSpeed1(); - - settings->setValue("Main/DefaultConnectionPort", currentPortName); - settings->setValue("Main/DefaultConnectionType", connType); - settings->setValue("Main/SingleWireMode", ui->ckSingleWire->isChecked()); - - emit updateConnectionSettings(conn, getPortName(), getSpeed0(), getSpeed1()); - - this->close(); -} - -void ConnectionWindow::getSerialPorts() -{ - ui->cbPort->clear(); - ports = QSerialPortInfo::availablePorts(); - - for (int i = 0; i < ports.count(); i++) - { - ui->cbPort->addItem(ports[i].portName()); - if (currentPortName == ports[i].portName()) ui->cbPort->setCurrentIndex(i); - } -} - -void ConnectionWindow::getKvaserPorts() -{ - -} - -void ConnectionWindow::getSocketcanPorts() -{ - QList interfaces = QNetworkInterface::allInterfaces(); - QString interfaceName; - - ui->cbPort->clear(); - - foreach (QNetworkInterface interface, interfaces) - { - interfaceName = interface.name().toLower(); - qDebug() << "Interface: " << interface.name(); - if (interfaceName.contains("can")) - { - ui->cbPort->addItem(interfaceName); - } - } -} - -void ConnectionWindow::setSpeeds(int speed0, int speed1) -{ - bool found = false; - - qDebug() << speed0 << "X" << speed1; - - for (int i = 0; i < ui->cbSpeed0->count(); i++) - { - if (ui->cbSpeed0->itemText(i).toInt() == speed0) - { - ui->cbSpeed0->setCurrentIndex(i); - found = true; - } - } - if (!found) - { - ui->cbSpeed0->addItem(QString::number(speed0)); - ui->cbSpeed0->setCurrentIndex(ui->cbSpeed0->count() - 1); - } - - found = false; - for (int i = 0; i < ui->cbSpeed1->count(); i++) - { - if (ui->cbSpeed1->itemText(i).toInt() == speed1) - { - ui->cbSpeed1->setCurrentIndex(i); - found = true; - } - } - if (!found) - { - ui->cbSpeed1->addItem(QString::number(speed1)); - ui->cbSpeed1->setCurrentIndex(ui->cbSpeed1->count() - 1); - } -} - - -//-1 means leave it at whatever it booted up to. 0 means disable. Otherwise the actual rate we want. -int ConnectionWindow::getSpeed0() -{ - switch (ui->cbSpeed0->currentIndex()) - { - case -1: - return -1; - break; - case 0: - return -1; - break; - case 1: - return 0; - break; - default: - return (ui->cbSpeed0->currentText().toInt()); - break; - } -} - -int ConnectionWindow::getSpeed1() -{ - switch (ui->cbSpeed1->currentIndex()) - { - case -1: - return -1; - break; - case 0: - return -1; - break; - case 1: - return 0; - break; - default: - return (ui->cbSpeed1->currentText().toInt()); - break; - } -} - -QString ConnectionWindow::getPortName() -{ - return (ui->cbPort->currentText()); -} - -ConnectionType::ConnectionType ConnectionWindow::getConnectionType() -{ - if (ui->rbGVRET->isChecked()) return ConnectionType::GVRET_SERIAL; - if (ui->rbKvaser->isChecked()) return ConnectionType::KVASER; - if (ui->rbSocketCAN->isChecked()) return ConnectionType::SOCKETCAN; -} - -void ConnectionWindow::setCAN1SWMode(bool mode) -{ - ui->ckSingleWire->setChecked(mode); -} - -bool ConnectionWindow::getCAN1SWMode() -{ - if (ui->ckSingleWire->checkState() == Qt::Checked) return true; - return false; -} diff --git a/connectionwindow.h b/connectionwindow.h deleted file mode 100644 index e098f67e..00000000 --- a/connectionwindow.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef CONNECTIONWINDOW_H -#define CONNECTIONWINDOW_H - -#include -#include -#include -#include - -namespace Ui { -class ConnectionWindow; -} - -namespace ConnectionType -{ - enum ConnectionType - { - GVRET_SERIAL, - KVASER, - SOCKETCAN - }; -} - -class ConnectionWindow : public QDialog -{ - Q_OBJECT - -public: - explicit ConnectionWindow(QWidget *parent = 0); - ~ConnectionWindow(); - void showEvent(QShowEvent *); - int getSpeed0(); - int getSpeed1(); - QString getPortName(); //name of port to connect to - ConnectionType::ConnectionType getConnectionType(); - bool getCAN1SWMode(); - -signals: - void updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1); - -public slots: - void setSpeeds(int speed0, int speed1); - void setCAN1SWMode(bool mode); - -private slots: - void handleOKButton(); - void handleConnTypeChanged(); - -private: - Ui::ConnectionWindow *ui; - QList ports; - QSettings *settings; - - ConnectionType::ConnectionType currentConnType; - QString currentPortName; - int currentSpeed1, currentSpeed2; - - void getSerialPorts(); - void getKvaserPorts(); - void getSocketcanPorts(); -}; - -#endif // CONNECTIONWINDOW_H diff --git a/connectionwindow.ui b/connectionwindow.ui deleted file mode 100644 index dc483698..00000000 --- a/connectionwindow.ui +++ /dev/null @@ -1,117 +0,0 @@ - - - ConnectionWindow - - - - 0 - 0 - 335 - 235 - - - - Connection Settings - - - - - - Connection Type - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - GVRET Serial - - - true - - - - - - - false - - - Kvaser - - - - - - - false - - - SocketCAN - - - - - - - - - - - 0 - 0 - - - - Port: - - - - - - - - - - - - CAN0 Speed - - - - - - - CAN1 Speed - - - - - - - - - - - - - - - Set CAN1 to Single Wire Mode - - - - - - - Update Settings - - - - - - - - diff --git a/dbc_classes.cpp b/dbc/dbc_classes.cpp similarity index 100% rename from dbc_classes.cpp rename to dbc/dbc_classes.cpp diff --git a/dbc_classes.h b/dbc/dbc_classes.h similarity index 100% rename from dbc_classes.h rename to dbc/dbc_classes.h diff --git a/dbchandler.cpp b/dbc/dbchandler.cpp similarity index 98% rename from dbchandler.cpp rename to dbc/dbchandler.cpp index 2142ee3c..0cb5124f 100644 --- a/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -37,6 +37,7 @@ bool DBCSignalHandler::addSignal(DBC_SIGNAL &sig) bool DBCSignalHandler::removeSignal(DBC_SIGNAL *sig) { + Q_UNUSED(sig); //if (sigs.removeAll(*sig) > 0) return true; return false; } @@ -75,7 +76,7 @@ int DBCSignalHandler::getCount() return sigs.count(); } -DBC_MESSAGE* DBCMessageHandler::findMsgByID(int id) +DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id) { if (messages.count() == 0) return NULL; for (int i = 0; i < messages.count(); i++) @@ -117,6 +118,7 @@ bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg) bool DBCMessageHandler::removeMessage(DBC_MESSAGE *msg) { + Q_UNUSED(msg); //if (messages.removeAll(*msg) > 0) return true; return false; } @@ -130,7 +132,7 @@ bool DBCMessageHandler::removeMessageByIndex(int idx) return true; } -bool DBCMessageHandler::removeMessage(int ID) +bool DBCMessageHandler::removeMessage(uint32_t ID) { bool foundSome = false; if (messages.count() == 0) return false; @@ -302,7 +304,7 @@ void DBCFile::loadFile(QString fileName) { int offset = 0; bool isMultiplexor = false; - bool isMultiplexed = false; + //bool isMultiplexed = false; DBC_SIGNAL sig; sig.multiplexValue = 0; @@ -326,7 +328,7 @@ void DBCFile::loadFile(QString fileName) if (match.hasMatch()) { qDebug() << "Multiplexed signal"; - isMultiplexed = true; + //isMultiplexed = true; sig.isMultiplexed = true; sig.multiplexValue = match.captured(2).toInt(); offset = 1; @@ -805,7 +807,7 @@ DBC_MESSAGE* DBCHandler::findMessage(const CANFrame &frame) { for(int i = 0; i < loadedFiles.count(); i++) { - if (loadedFiles[i].getAssocBus() == -1 || frame.bus == loadedFiles[i].getAssocBus()) + if (loadedFiles[i].getAssocBus() == -1 || frame.bus == (unsigned int)loadedFiles[i].getAssocBus()) { DBC_MESSAGE* msg = loadedFiles[i].messageHandler->findMsgByID(frame.ID); if (msg != NULL) return msg; diff --git a/dbchandler.h b/dbc/dbchandler.h similarity index 96% rename from dbchandler.h rename to dbc/dbchandler.h index 80376da4..5f74ee87 100644 --- a/dbchandler.h +++ b/dbc/dbchandler.h @@ -32,13 +32,13 @@ class DBCMessageHandler: public QObject { Q_OBJECT public: - DBC_MESSAGE *findMsgByID(int id); + DBC_MESSAGE *findMsgByID(uint32_t id); DBC_MESSAGE *findMsgByIdx(int idx); DBC_MESSAGE *findMsgByName(QString name); bool addMessage(DBC_MESSAGE &msg); bool removeMessage(DBC_MESSAGE *msg); bool removeMessageByIndex(int idx); - bool removeMessage(int ID); + bool removeMessage(uint32_t ID); bool removeMessage(QString name); void removeAllMessages(); int getCount(); diff --git a/dbcloadsavewindow.cpp b/dbc/dbcloadsavewindow.cpp similarity index 99% rename from dbcloadsavewindow.cpp rename to dbc/dbcloadsavewindow.cpp index 0ef704d0..a37f8134 100644 --- a/dbcloadsavewindow.cpp +++ b/dbc/dbcloadsavewindow.cpp @@ -114,6 +114,7 @@ void DBCLoadSaveWindow::cellChanged(int row, int col) void DBCLoadSaveWindow::cellDoubleClicked(int row, int col) { + Q_UNUSED(col) editorWindow->setFileIdx(row); editorWindow->show(); } diff --git a/dbcloadsavewindow.h b/dbc/dbcloadsavewindow.h similarity index 100% rename from dbcloadsavewindow.h rename to dbc/dbcloadsavewindow.h diff --git a/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp similarity index 76% rename from dbcmaineditor.cpp rename to dbc/dbcmaineditor.cpp index 596346e0..16fe8369 100644 --- a/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -5,6 +5,8 @@ #include #include +#define MT_COLUMN_COUNT 5 + DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector *frames, QWidget *parent) : QDialog(parent), ui(new Ui::DBCMainEditor) @@ -26,7 +28,7 @@ DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector *frame QStringList headers2; headers2 << "Msg ID" << "Msg Name" << "Data Len" << "Signals" << "Comment"; - ui->MessagesTable->setColumnCount(5); + ui->MessagesTable->setColumnCount(MT_COLUMN_COUNT); ui->MessagesTable->setColumnWidth(0, 80); ui->MessagesTable->setColumnWidth(1, 240); ui->MessagesTable->setColumnWidth(2, 80); @@ -210,148 +212,125 @@ void DBCMainEditor::onCellChangedNode(int row,int col) void DBCMainEditor::onCellChangedMessage(int row,int col) { - if (inhibitCellChanged) return; + QTableWidgetItem* item = NULL; + bool ret = false; + DBC_MESSAGE *msg = NULL; + uint msgID; - qDebug() << "Editing row: " << row << " col: " << col; + if (inhibitCellChanged) return; - QTableWidgetItem *replacement = NULL; - int msgID; - QString msgName; - int msgLen; - QString msgComment; - DBC_MESSAGE newMsg; DBC_NODE *node = dbcFile->findNodeByIdx(ui->NodesTable->currentRow()); - DBC_MESSAGE *msg; if (node == NULL) { qDebug() << "No node set?!? This is bad!"; return; - //dbcHandler->findNodeByIdx(0); } - msgID = Utility::ParseStringToNum(ui->MessagesTable->item(row, 0)->text()); - qDebug() << "Msg ID of edited: " << msgID; + item = ui->MessagesTable->item(row, 0); + if(!item) return; + + msgID = Utility::ParseStringToNum2(item->text(), &ret); msg = dbcFile->messageHandler->findMsgByID(msgID); switch(col) { - case 0: //msg id - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - if (dbcFile->messageHandler->findMsgByID(msgID) != NULL) + case 0: //msg id + { + /* sanity checks */ + if(!ret) + { + /* bad message id */ + ui->MessagesTable->item(row, 0)->setText(""); + return; + } + if (msg != NULL) { QMessageBox msg; msg.setParent(0); msg.setText("An existing msg with that ID already exists! Aborting!"); msg.exec(); + + ui->MessagesTable->item(row, 0)->setText(""); return; } + + /* insert row */ + DBC_MESSAGE newMsg; newMsg.ID = msgID; newMsg.name = ""; newMsg.sender = node; newMsg.len = 0; for (int i = 0; i < referenceFrames->length(); i++) { - if (referenceFrames->at(i).ID == msgID) + if ((uint) referenceFrames->at(i).ID == msgID) { newMsg.len = referenceFrames->at(i).len; break; } } dbcFile->messageHandler->addMessage(newMsg); - } - else //editing an existing record - { - if (msg != NULL) msg->ID = msgID; - } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(Utility::formatNumber(msgID)); - ui->MessagesTable->setItem(row, col, replacement); - replacement = new QTableWidgetItem(QString::number(newMsg.len)); - ui->MessagesTable->setItem(row, 2, replacement); - inhibitCellChanged = false; - break; - - case 1: //msg name - msgName = ui->MessagesTable->item(row, col)->text().simplified().replace(' ', '_'); - if (msgName.length() == 0) return; - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - if (dbcFile->messageHandler->findMsgByName(msgName) != NULL) + + /* insert message in table */ + inhibitCellChanged = true; + + item = ui->MessagesTable->item(row, 0); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + item->setText(Utility::formatNumber(msgID)); + + for(int i=1 ; iMessagesTable->item(row, i); + item->setFlags(item->flags() | Qt::ItemIsEditable); } - newMsg.ID = -1; - newMsg.name = msgName; - newMsg.sender = node; - dbcFile->messageHandler->addMessage(newMsg); - } - else - { - if (msg != NULL) msg->name = msgName; - } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(msgName); - ui->MessagesTable->setItem(row, col, replacement); - inhibitCellChanged = false; - break; - case 2: //data length - msgLen = ui->MessagesTable->item(row, col)->text().toInt(); - if (msgLen < 0) msgLen = 0; - if (msgLen > 8) msgLen = 8; - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - DBC_MESSAGE newMsg; - newMsg.ID = -1; - newMsg.name = ""; - newMsg.len = msgLen; - newMsg.sender = node; - dbcFile->messageHandler->addMessage(newMsg); + /* set length */ + item = ui->MessagesTable->item(row, 2); + item->setText(QString::number(newMsg.len)); + + inhibitCellChanged = false; + + /* insert a new row */ + insertBlankRow(); + break; } - else //editing an existing record + case 1: //msg name { - if (msg != NULL) msg->len = msgLen; + QString msgName = ui->MessagesTable->item(row, 1)->text().simplified().replace(' ', '_'); + if (msgName.length() == 0) return; + if( ret && (msg!=NULL) ) + msg->name = msgName; + break; } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(QString::number(msgLen, 16)); - ui->MessagesTable->setItem(row, col, replacement); - inhibitCellChanged = false; - - break; - case 3: //signals (number) - we don't handle anything here. User cannot directly change this value - break; - case 4: //comment - msgComment = ui->MessagesTable->item(row, col)->text().simplified(); - if (row == ui->MessagesTable->rowCount() - 1) //new record + case 2: //data length { - DBC_MESSAGE newMsg; - newMsg.ID = -1; - newMsg.name = ""; - newMsg.len = 0; - newMsg.comment = msgComment; - newMsg.sender = node; - dbcFile->messageHandler->addMessage(newMsg); + bool parseOk = false; + uint msgLen = ui->MessagesTable->item(row, col)->text().toUInt(&parseOk); + + /* sanity checks */ + if(!parseOk) + { + ui->MessagesTable->item(row, col)->setText(""); + return; + } + if (msgLen > 8) + { + msgLen = 8; + ui->MessagesTable->item(row, col)->setText(QString::number(msgLen)); + } + + if( ret && (msg!=NULL) ) + msg->len = msgLen; + break; } - else //editing an existing record + case 3: //signals (number) - we don't handle anything here. User cannot directly change this value + break; + case 4: //comment { - if (msg != NULL) msg->comment = msgComment; + QString msgComment = ui->MessagesTable->item(row, col)->text().simplified(); + if( ret && (msgComment!=NULL) ) + msg->comment = msgComment; + break; } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(msgComment); - ui->MessagesTable->setItem(row, col, replacement); - inhibitCellChanged = false; - break; - - } - - if (row == ui->MessagesTable->rowCount() - 1) - { - ui->MessagesTable->insertRow(ui->MessagesTable->rowCount()); } ui->MessagesTable->setCurrentCell(row, col); @@ -426,6 +405,7 @@ void DBCMainEditor::refreshNodesTable() //insert a fresh entry at the bottom that contains nothing ui->NodesTable->insertRow(ui->NodesTable->rowCount()); + ui->NodesTable->selectRow(0); } void DBCMainEditor::refreshMessagesTable(const DBC_NODE *node) @@ -466,5 +446,17 @@ void DBCMainEditor::refreshMessagesTable(const DBC_NODE *node) } //insert blank record that can be used to add new messages - ui->MessagesTable->insertRow(ui->MessagesTable->rowCount()); + insertBlankRow(); +} + +void DBCMainEditor::insertBlankRow() +{ + int rowIdx = ui->MessagesTable->rowCount(); + ui->MessagesTable->insertRow(rowIdx); + for(int i=1 ; isetFlags(item->flags() & ~Qt::ItemIsEditable); + ui->MessagesTable->setItem(rowIdx, i, item); + } } diff --git a/dbcmaineditor.h b/dbc/dbcmaineditor.h similarity index 97% rename from dbcmaineditor.h rename to dbc/dbcmaineditor.h index 07e8e11c..4067693d 100644 --- a/dbcmaineditor.h +++ b/dbc/dbcmaineditor.h @@ -46,6 +46,7 @@ private slots: void closeEvent(QCloseEvent *event); void readSettings(); void writeSettings(); + void insertBlankRow(); }; diff --git a/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp similarity index 99% rename from dbcsignaleditor.cpp rename to dbc/dbcsignaleditor.cpp index 97924391..b3a5acf6 100644 --- a/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -348,6 +348,10 @@ void DBCSignalEditor::addNewSignal() void DBCSignalEditor::deleteCurrentSignal() { int currIdx = ui->signalsList->currentRow(); + + if(currIdx==ui->signalsList->count()-1) + return; + if (currIdx > -1) { delete(ui->signalsList->item(currIdx)); diff --git a/dbcsignaleditor.h b/dbc/dbcsignaleditor.h similarity index 100% rename from dbcsignaleditor.h rename to dbc/dbcsignaleditor.h diff --git a/deltawindow.ui b/deltawindow.ui deleted file mode 100644 index 3a67a5e8..00000000 --- a/deltawindow.ui +++ /dev/null @@ -1,24 +0,0 @@ - - - DeltaWindow - - - - 0 - 0 - 978 - 654 - - - - Dialog - - - - - - - - - - diff --git a/firmwareuploaderwindow.cpp b/firmwareuploaderwindow.cpp index cd032ee3..19ae9e40 100644 --- a/firmwareuploaderwindow.cpp +++ b/firmwareuploaderwindow.cpp @@ -25,7 +25,7 @@ FirmwareUploaderWindow::FirmwareUploaderWindow(const QVector *frames, updateProgress(); timer = new QTimer(); - timer->setInterval(100); //100ms without a reply will cause us to attempt a resend + timer->setInterval(100); //100ms without a reply will cause us to attempt a resend connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(handleLoadFile())); @@ -36,6 +36,7 @@ FirmwareUploaderWindow::FirmwareUploaderWindow(const QVector *frames, FirmwareUploaderWindow::~FirmwareUploaderWindow() { timer->stop(); + CANConManager::getInstance()->removeAllTargettedFrames(this); delete timer; delete ui; } @@ -47,7 +48,7 @@ void FirmwareUploaderWindow::updateProgress() void FirmwareUploaderWindow::updatedFrames(int numFrames) { - CANFrame thisFrame; + //CANFrame thisFrame; if (numFrames == -1) //all frames deleted. { } @@ -66,10 +67,10 @@ void FirmwareUploaderWindow::updatedFrames(int numFrames) } } -void FirmwareUploaderWindow::gotTargettedFrame(int frameLoc) +void FirmwareUploaderWindow::gotTargettedFrame(CANFrame frame) { - const CANFrame &frame = modelFrames->at(frameLoc); - if (frame.ID == (baseAddress + 0x10)) { + qDebug() << "FUW: Got targetted frame with id " << frame.ID; + if (frame.ID == (uint32_t)(baseAddress + 0x10)) { qDebug() << "Start firmware reply"; if ((frame.data[0] == 0xAD) && (frame.data[1] == 0xDE)) { @@ -81,7 +82,7 @@ void FirmwareUploaderWindow::gotTargettedFrame(int frameLoc) if ((frame.data[6] == ((token >> 16) & 0xFF)) && (frame.data[7] == ((token >> 24) & 0xFF))) { qDebug() << "starting firmware process"; - MainWindow::getReference()->setTargettedID(baseAddress + 0x20); + //MainWindow::getReference()->setTargettedID(baseAddress + 0x20); transferInProgress = true; sendFirmwareChunk(); } @@ -90,7 +91,7 @@ void FirmwareUploaderWindow::gotTargettedFrame(int frameLoc) } } - if (frame.ID == (baseAddress + 0x20)) { + if (frame.ID == (uint32_t)(baseAddress + 0x20)) { qDebug() << "Firmware reception success reply"; int seq = frame.data[0] + (256 * frame.data[1]); if (seq == currentSendingPosition) @@ -126,6 +127,7 @@ void FirmwareUploaderWindow::sendFirmwareChunk() int xorByte = 0; output->extended = false; output->len = 7; + output->bus = bus; output->ID = baseAddress + 0x16; output->data[0] = currentSendingPosition & 0xFF; output->data[1] = (currentSendingPosition >> 8) & 0xFF; @@ -135,7 +137,7 @@ void FirmwareUploaderWindow::sendFirmwareChunk() output->data[5] = firmwareData[firmwareLocation++]; for (int i = 0; i < 6; i++) xorByte = xorByte ^ output->data[i]; output->data[6] = xorByte; - sendCANFrame(output, bus); + sendCANFrame(output); timer->start(); } @@ -143,13 +145,14 @@ void FirmwareUploaderWindow::sendFirmwareEnding() { CANFrame *output = new CANFrame; output->extended = false; + output->bus = bus; output->len = 4; output->ID = baseAddress + 0x30; output->data[3] = 0xC0; output->data[2] = 0xDE; output->data[1] = 0xFA; output->data[0] = 0xDE; - sendCANFrame(output, bus); + //sendCANFrame(output, bus); } void FirmwareUploaderWindow::handleStartStopTransfer() @@ -164,10 +167,12 @@ void FirmwareUploaderWindow::handleStartStopTransfer() bus = ui->spinBus->value(); baseAddress = Utility::ParseStringToNum(ui->txtBaseAddr->text()); qDebug() << "Base address: " + QString::number(baseAddress); - MainWindow::getReference()->setTargettedID(baseAddress + 0x10); + CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x10, 0x7FF, this); + CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x20, 0x7FF, this); CANFrame *output = new CANFrame; output->extended = false; output->len = 8; + output->bus = bus; output->ID = baseAddress; output->data[0] = 0xEF; @@ -178,12 +183,12 @@ void FirmwareUploaderWindow::handleStartStopTransfer() output->data[5] = (token >> 8) & 0xFF; output->data[6] = (token >> 16) & 0xFF; output->data[7] = (token >> 24) & 0xFF; - sendCANFrame(output, bus); + sendCANFrame(output); } else //stop anything in process { ui->btnStartStop->setText("Start Upload"); - MainWindow::getReference()->setTargettedID(-1); + CANConManager::getInstance()->removeAllTargettedFrames(this); } } @@ -191,7 +196,6 @@ void FirmwareUploaderWindow::handleLoadFile() { QString filename; QFileDialog dialog; - bool result = false; QStringList filters; filters.append(QString(tr("Raw firmware binary (*.bin)"))); diff --git a/firmwareuploaderwindow.h b/firmwareuploaderwindow.h index 5371c193..ec079069 100644 --- a/firmwareuploaderwindow.h +++ b/firmwareuploaderwindow.h @@ -4,8 +4,8 @@ #include #include #include "can_structs.h" +#include "connections/canconmanager.h" #include "utility.h" -#include "serialworker.h" namespace Ui { class FirmwareUploaderWindow; @@ -20,10 +20,10 @@ class FirmwareUploaderWindow : public QDialog ~FirmwareUploaderWindow(); signals: - void sendCANFrame(const CANFrame *, int); + void sendCANFrame(const CANFrame *); public slots: - void gotTargettedFrame(int frameLoc); + void gotTargettedFrame(CANFrame frame); private slots: void handleLoadFile(); diff --git a/framefileio.cpp b/framefileio.cpp index c2796855..380b30b9 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -246,6 +246,8 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector *frames bool FrameFileIO::saveVehicleSpyFile(QString filename, const QVector *frames) { + Q_UNUSED(filename); + Q_UNUSED(frames); return true; } @@ -324,7 +326,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector* frames) else thisFrame.isReceived = true; thisFrame.bus = 0; thisFrame.len = tokens.length() - 3; - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) { if (tokens[d + 3] != "") { @@ -381,7 +383,7 @@ bool FrameFileIO::saveCRTDFile(QString filename, const QVector* frames outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); outFile->putChar(' '); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -440,7 +442,7 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector* frames) thisFrame.bus = 0; thisFrame.extended = false; QList tokens = line.mid(41, thisFrame.len * 3).split(' '); - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) { if (tokens[d] != "") { @@ -512,9 +514,9 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) { thisFrame.isReceived = true; thisFrame.bus = tokens[3].toInt(); - thisFrame.len = tokens[4].toInt(); + thisFrame.len = tokens[4].toUInt(); for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16); } else if (fileVersion == 2) @@ -522,10 +524,10 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) if (tokens[3].at(0) == 'R') thisFrame.isReceived = true; else thisFrame.isReceived = false; thisFrame.bus = tokens[4].toInt(); - thisFrame.len = tokens[5].toInt(); - if (thisFrame.len + 6 > tokens.length()) thisFrame.len = tokens.length() - 6; + thisFrame.len = tokens[5].toUInt(); + if (thisFrame.len + 6 > (unsigned int) tokens.length()) thisFrame.len = tokens.length() - 6; for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16); } @@ -580,7 +582,7 @@ bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector* f outFile->write(QString::number(frames->at(c).len).toUtf8()); outFile->putChar(44); - for (int temp = 0; temp < 8; temp++) + for (unsigned int temp = 0; temp < 8; temp++) { if (temp < frames->at(c).len) outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); @@ -636,7 +638,7 @@ bool FrameFileIO::loadGenericCSVFile(QString filename, QVector* frames QList dataTok = tokens[1].split(' '); thisFrame.len = dataTok.length(); if (thisFrame.len > 8) thisFrame.len = 8; - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataTok[d].toInt(NULL, 16); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataTok[d].toInt(NULL, 16); frames->append(thisFrame); } @@ -674,7 +676,7 @@ bool FrameFileIO::saveGenericCSVFile(QString filename, const QVector* outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); outFile->putChar(44); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -762,10 +764,9 @@ bool FrameFileIO::loadLogFile(QString filename, QVector* frames) if (tokens[4] == "s") thisFrame.extended = false; else thisFrame.extended = true; thisFrame.bus = tokens[2].toInt() - 1; - thisFrame.len = tokens[5].toInt(); + thisFrame.len = tokens[5].toUInt(); if (thisFrame.len > 8) thisFrame.len = 8; - if (thisFrame.len < 0) thisFrame.len = 0; - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16); frames->append(thisFrame); } else foundErrors = true; @@ -825,7 +826,7 @@ bool FrameFileIO::saveLogFile(QString filename, const QVector* frames) else outFile->write(" s "); outFile->write(QString::number(frames->at(c).len).toUtf8() + " "); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -902,7 +903,7 @@ bool FrameFileIO::loadIXXATFile(QString filename, QVector* frames) QStringList dataToks = unQuote(tokens[4]).simplified().split(' '); thisFrame.len = dataToks.length(); - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16); frames->append(thisFrame); } else foundErrors = true; @@ -955,7 +956,7 @@ bool FrameFileIO::saveIXXATFile(QString filename, const QVector* frame else outFile->write(",\"Std\""); outFile->write(",\"\",\""); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -1018,7 +1019,7 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector* frames) if (thisFrame.len <= 8 && thisFrame.ID <= 0x7FF) { - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d]; + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d]; frames->append(thisFrame); } else foundErrors = true; @@ -1050,8 +1051,8 @@ bool FrameFileIO::saveCANDOFile(QString filename, const QVector* frame ms = (thisFrame.timestamp / 1000); data[0] = (((ms / 1000) % 60) << 2) + ((ms % 1000) >> 8); data[1] = (char)(ms & 0xFF); - data[2] = 0xFF; - data[3] = 0xFF; + data[2] = (char)0xFF; + data[3] = (char)0xFF; for (int l = 0; l < 8; l++) data[4 + l] = 0; outFile->write(data); @@ -1063,7 +1064,7 @@ bool FrameFileIO::saveCANDOFile(QString filename, const QVector* frame qApp->processEvents(); lineCounter = 0; } - for (int j = 0; j < 8; j++) data[4 + j] = 0xFF; + for (int j = 0; j < 8; j++) data[4 + j] = (char)0xFF; thisFrame = frames->at(c); if (!thisFrame.extended) @@ -1074,7 +1075,7 @@ bool FrameFileIO::saveCANDOFile(QString filename, const QVector* frame data[1] = (char)(ms & 0xFF); data[2] = (char)(id & 0xFF); data[3] = (char)((id >> 8) + (thisFrame.len << 4)); - for (int d = 0; d < thisFrame.len; d++) data[4 + d] = (char)thisFrame.data[d]; + for (unsigned int d = 0; d < thisFrame.len; d++) data[4 + d] = (char)thisFrame.data[d]; outFile->write(data); } } @@ -1140,11 +1141,10 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector* frames) if (thisFrame.ID <= 0x7FF) thisFrame.extended = false; else thisFrame.extended = true; thisFrame.bus = 0; - thisFrame.len = tokens[3].toInt(); + thisFrame.len = tokens[3].toUInt(); if (thisFrame.len > 8) thisFrame.len = 8; - if (thisFrame.len < 0) thisFrame.len = 0; - if (thisFrame.len + 4 > tokens.length()) thisFrame.len = tokens.length() - 4; - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]); + if (thisFrame.len + 4 > (unsigned int) tokens.length()) thisFrame.len = tokens.length() - 4; + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]); frames->append(thisFrame); } else foundErrors = true; @@ -1206,7 +1206,7 @@ bool FrameFileIO::saveMicrochipFile(QString filename, const QVector* f outFile->write("0x" + QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8() + ";"); outFile->write(QString::number(frames->at(c).len).toUtf8() + ";"); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write("0x" + QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(';'); @@ -1299,12 +1299,11 @@ bool FrameFileIO::loadTraceFile(QString filename, QVector* frames) if (thisFrame.ID <= 0x7FF) thisFrame.extended = false; else thisFrame.extended = true; thisFrame.bus = 0; - thisFrame.len = tokens[3].toInt(); - if (thisFrame.len < 0) thisFrame.len = 0; + thisFrame.len = tokens[3].toUInt(); if (thisFrame.len > 8) thisFrame.len = 8; QList dataToks = tokens[4].split(' '); - if (thisFrame.len > dataToks.length()) thisFrame.len = dataToks.length(); - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16); + if (thisFrame.len > (unsigned int) dataToks.length()) thisFrame.len = (unsigned int) dataToks.length(); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16); frames->append(thisFrame); } else foundErrors = true; @@ -1391,7 +1390,7 @@ bool FrameFileIO::saveTraceFile(QString filename, const QVector * fram outFile->write(QString::number(frames->at(c).len).toUtf8() + "\t"); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); diff --git a/framefileio.h b/framefileio.h index 13f6e594..0c455151 100644 --- a/framefileio.h +++ b/framefileio.h @@ -22,6 +22,14 @@ class FrameFileIO: public QObject public: FrameFileIO(); + //these present a GUI to the user and allow them to pick the file to load/save + //The QString returns the filename that was selected and so is really a sort of return value + //The QVector is used as either the target for loading or the source for saving. + //These routines call the below loading/saving functions so no need to use them directly if you don't want. + static bool loadFrameFile(QString &, QVector*); + static bool saveFrameFile(QString &, const QVector*); + + //These do the actual loading and saving and can be used directly if you'd prefer static bool loadCRTDFile(QString, QVector*); static bool loadNativeCSVFile(QString, QVector*); static bool loadGenericCSVFile(QString, QVector*); @@ -40,8 +48,6 @@ class FrameFileIO: public QObject static bool saveIXXATFile(QString, const QVector*); static bool saveCANDOFile(QString, const QVector*); static bool saveVehicleSpyFile(QString, const QVector*); - static bool loadFrameFile(QString &, QVector*); - static bool saveFrameFile(QString &, const QVector*); static bool loadCanDumpFile(QString, QVector*); static bool loadPCANFile(QString, QVector*); diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index be6dae76..41458030 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "connections/canconmanager.h" /* * Notes about new functionality: @@ -18,22 +19,21 @@ * */ -FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, SerialWorker *worker, QWidget *parent) : +FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidget *parent) : QDialog(parent), ui(new Ui::FramePlaybackWindow) { ui->setupUi(this); - ui->comboCANBus->addItem(tr("None")); - ui->comboCANBus->addItem(tr("0")); - ui->comboCANBus->addItem(tr("1")); - ui->comboCANBus->addItem(tr("Both")); + + int numBuses = CANConManager::getInstance()->getNumBuses(); + for (int n = 0; n < numBuses; n++) ui->comboCANBus->addItem(QString::number(n)); + ui->comboCANBus->addItem(tr("All")); ui->comboCANBus->addItem(tr("From File")); readSettings(); modelFrames = frames; - serialWorker = worker; playbackTimer = new QTimer(); @@ -70,9 +70,6 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, Serial playbackTimer->setInterval(ui->spinPlaySpeed->value()); //set the timer to the default value of the control - connect(this, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int)), Qt::QueuedConnection); - connect(this, SIGNAL(sendFrameBatch(const QList*)), worker, SLOT(sendFrameBatch(const QList*)), Qt::QueuedConnection); - QStringList headers; headers << "Source" << "Loops"; ui->tblSequence->setColumnCount(2); @@ -85,8 +82,6 @@ FramePlaybackWindow::~FramePlaybackWindow() { delete ui; - disconnect(serialWorker); - playbackTimer->stop(); delete playbackTimer; } @@ -405,7 +400,7 @@ void FramePlaybackWindow::btnBackOneClick() playbackActive = false; updatePosition(false); - emit sendFrameBatch(&sendingBuffer); + CANConManager::getInstance()->sendFrames(sendingBuffer); } void FramePlaybackWindow::btnPauseClick() @@ -456,7 +451,7 @@ void FramePlaybackWindow::btnFwdOneClick() playbackTimer->stop(); playbackActive = false; updatePosition(true); - emit sendFrameBatch(&sendingBuffer); + CANConManager::getInstance()->sendFrames(sendingBuffer); } void FramePlaybackWindow::changePlaybackSpeed(int newSpeed) @@ -471,8 +466,6 @@ void FramePlaybackWindow::changeLooping(bool check) void FramePlaybackWindow::changeSendingBus(int newIdx) { - //falls out neatly this way. 0 = no sending, 1 = bus 0, 2 = bus 1, 3 = both, 4 = from file - //the index is exactly the same as the whichSendBus bitfield. whichBusSend = newIdx; } @@ -522,7 +515,7 @@ void FramePlaybackWindow::timerTriggered() updatePosition(false); } } - emit sendFrameBatch(&sendingBuffer); + CANConManager::getInstance()->sendFrames(sendingBuffer); } void FramePlaybackWindow::updatePosition(bool forward) @@ -596,23 +589,25 @@ void FramePlaybackWindow::updatePosition(bool forward) int originalBus = thisFrame->bus; if (currentSeqItem->idFilters.find(thisFrame->ID).value()) { - //index 0 is none, 1 is Bus 0, 2 is bus 1, 3 is both, 4 is from file - if (whichBusSend & 4) + if (whichBusSend < ui->comboCANBus->count() - 2) { + thisFrame->bus = whichBusSend; sendingBuffer.append(*thisFrame); } - if (whichBusSend & 1) + else if (whichBusSend == (ui->comboCANBus->count() - 2)) //all { - thisFrame->bus = 0; - sendingBuffer.append(*thisFrame); + for (int c = 0; c < ui->comboCANBus->count() - 2; c++) + { + thisFrame->bus = c; + sendingBuffer.append(*thisFrame); + } } - if (whichBusSend & 2) + else //from file so retain original bus and send as-is { - thisFrame->bus = 1; sendingBuffer.append(*thisFrame); } + thisFrame->bus = originalBus; updateFrameLabel(); } - } diff --git a/frameplaybackwindow.h b/frameplaybackwindow.h index 07296dde..a0a2026a 100644 --- a/frameplaybackwindow.h +++ b/frameplaybackwindow.h @@ -5,7 +5,6 @@ #include #include #include "can_structs.h" -#include "serialworker.h" #include "framefileio.h" namespace Ui { @@ -27,7 +26,7 @@ class FramePlaybackWindow : public QDialog Q_OBJECT public: - explicit FramePlaybackWindow(const QVector *frames, SerialWorker *worker, QWidget *parent = 0); + explicit FramePlaybackWindow(const QVector *frames, QWidget *parent = 0); ~FramePlaybackWindow(); private slots: @@ -53,10 +52,6 @@ private slots: void saveFilters(); void loadFilters(); -signals: - void sendCANFrame(const CANFrame *, int); - void sendFrameBatch(const QList *); - private: Ui::FramePlaybackWindow *ui; QList foundID; @@ -65,7 +60,6 @@ private slots: const QVector *modelFrames; int currentPosition; QTimer *playbackTimer; - SerialWorker *serialWorker; bool playbackActive; bool playbackForward; int whichBusSend; diff --git a/framesenderwindow.cpp b/framesenderwindow.cpp index 91dd13cd..e91d12b6 100644 --- a/framesenderwindow.cpp +++ b/framesenderwindow.cpp @@ -5,6 +5,7 @@ #include #include #include "mainwindow.h" +#include "connections/canconmanager.h" /* * notes: need to ensure that you grab pointers when modifying data structures and dont @@ -139,9 +140,9 @@ void FrameSenderWindow::processIncomingFrame(CANFrame *frame) Trigger *thisTrigger = &sendingData[sd].triggers[trig]; qDebug() << "Trigger ID: " << thisTrigger->ID; qDebug() << "Frame ID: " << frame->ID; - if (thisTrigger->ID > 0 && thisTrigger->ID == frame->ID) + if (thisTrigger->ID > 0 && (uint32_t)thisTrigger->ID == frame->ID) { - if (thisTrigger->bus == frame->bus || thisTrigger->bus == -1) + if ((uint32_t)thisTrigger->bus == frame->bus || thisTrigger->bus == -1) { if (thisTrigger->currCount < thisTrigger->maxCount) { @@ -151,7 +152,7 @@ void FrameSenderWindow::processIncomingFrame(CANFrame *frame) sendingData[sd].count++; doModifiers(sd); updateGridRow(sd); - sendCANFrame(&sendingData[sd], sendingData[sd].bus); + CANConManager::getInstance()->sendFrame(sendingData[sd]); } else //delayed sending frame { @@ -354,7 +355,7 @@ void FrameSenderWindow::handleTick() doModifiers(i); updateGridRow(i); qDebug() << "About to try to send a frame"; - emit sendCANFrame(&sendingData[i], sendingData[i].bus); + CANConManager::getInstance()->sendFrame(sendingData[i]); if (trigger->ID > 0) trigger->readyCount = false; //reset flag if this is a timed ID trigger } } @@ -457,7 +458,7 @@ CANFrame* FrameSenderWindow::lookupFrame(int ID, int bus) { if (!frameCache.contains(ID)) return NULL; - if (bus == -1 || frameCache[ID].bus == bus) return &frameCache[ID]; + if (bus == -1 || frameCache[ID].bus == (unsigned int)bus) return &frameCache[ID]; return NULL; } @@ -471,7 +472,7 @@ void FrameSenderWindow::processModifierText(int line) { qDebug() << "processModifierText"; QString modString; - bool firstOp = true; + //bool firstOp = true; bool abort = false; QString token; ModifierOp thisOp; @@ -495,7 +496,6 @@ void FrameSenderWindow::processModifierText(int line) { Modifier thisMod; thisMod.destByte = 0; - firstOp = true; QString leftSide = Utility::grabAlphaNumeric(mods[i]); if (leftSide.startsWith("D") && leftSide.length() == 2) @@ -701,7 +701,7 @@ void FrameSenderWindow::updateGridRow(int idx) QTableWidgetItem *item = ui->tableSender->item(gridLine, 7); if (item == NULL) item = new QTableWidgetItem(); item->setText(QString::number(temp->count)); - for (int i = 0; i < temp->len; i++) + for (unsigned int i = 0; i < temp->len; i++) { dataString.append(Utility::formatNumber(temp->data[i])); dataString.append(" "); diff --git a/framesenderwindow.h b/framesenderwindow.h index e80d5854..57642e89 100644 --- a/framesenderwindow.h +++ b/framesenderwindow.h @@ -30,9 +30,6 @@ private slots: void loadGrid(); void updatedFrames(int); -signals: - void sendCANFrame(const CANFrame *, int); - private: Ui::FrameSenderWindow *ui; QList sendingData; diff --git a/mainwindow.cpp b/mainwindow.cpp index 45c7cbcb..3c00e91c 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4,9 +4,8 @@ #include #include #include -#include "canframemodel.h" +#include "connections/canconmanager.h" #include "utility.h" -#include "serialworker.h" /* Compile for all platforms and create release (remember to include QScintilla libs) and make Win32 binary. @@ -47,7 +46,8 @@ MainWindow::MainWindow(QWidget *parent) : this->setWindowTitle("Savvy CAN V" + QString::number(VERSION)); - model = new CANFrameModel(); + model = new CANFrameModel(this); // set parent to mainwindow to prevent canframemodel to change thread (might be done by setModel but just in case) + ui->canFramesView->setModel(model); readSettings(); @@ -61,26 +61,6 @@ MainWindow::MainWindow(QWidget *parent) : 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. - //ui->canFramesView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - - worker = new SerialWorker(model); - worker->moveToThread(&serialWorkerThread); - connect(&serialWorkerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(&serialWorkerThread, &QThread::started, worker, &SerialWorker::run); //setup timers within the proper thread - connect(this, &MainWindow::sendSerialPort, worker, &SerialWorker::setSerialPort, Qt::QueuedConnection); - connect(worker, &SerialWorker::frameUpdateRapid, this, &MainWindow::gotFrames, Qt::QueuedConnection); - connect(this, &MainWindow::updateBaudRates, worker, &SerialWorker::updateBaudRates, Qt::QueuedConnection); - connect(this, &MainWindow::sendCANFrame, worker, &SerialWorker::sendFrame, Qt::QueuedConnection); - connect(worker, &SerialWorker::connectionSuccess, this, &MainWindow::connectionSucceeded, Qt::QueuedConnection); - connect(worker, &SerialWorker::connectionFailure, this, &MainWindow::connectionFailed, Qt::QueuedConnection); - connect(worker, &SerialWorker::deviceInfo, this, &MainWindow::gotDeviceInfo, Qt::QueuedConnection); - connect(this, &MainWindow::closeSerialPort, worker, &SerialWorker::closeSerialPort, Qt::QueuedConnection); - connect(this, &MainWindow::startFrameCapturing, worker, &SerialWorker::startFrameCapture); - connect(this, &MainWindow::stopFrameCapturing, worker, &SerialWorker::stopFrameCapture); - connect(this, &MainWindow::settingsUpdated, worker, &SerialWorker::readSettings); - serialWorkerThread.start(); - serialWorkerThread.setPriority(QThread::HighPriority); graphingWindow = NULL; frameInfoWindow = NULL; @@ -100,6 +80,8 @@ MainWindow::MainWindow(QWidget *parent) : udsScanWindow = NULL; motorctrlConfigWindow = NULL; isoWindow = NULL; + snifferWindow = NULL; + bisectWindow = NULL; dbcHandler = new DBCHandler; bDirty = false; inhibitFilterUpdate = false; @@ -109,7 +91,6 @@ MainWindow::MainWindow(QWidget *parent) : model->setDBCHandler(dbcHandler); connect(ui->actionSetup, SIGNAL(triggered(bool)), SLOT(showConnectionSettingsWindow())); - connect(ui->actionConnect, SIGNAL(triggered(bool)), this, SLOT(connButtonPress())); connect(ui->actionOpen_Log_File, &QAction::triggered, this, &MainWindow::handleLoadFile); connect(ui->actionGraph_Dta, &QAction::triggered, this, &MainWindow::showGraphingWindow); connect(ui->actionFrame_Data_Analysis, &QAction::triggered, this, &MainWindow::showFrameDataAnalysis); @@ -144,9 +125,13 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow); connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow); connect(ui->actionISO_TP_Decoder, &QAction::triggered, this, &MainWindow::showISOInterpreterWindow); + connect(ui->actionSniffer, &QAction::triggered, this, &MainWindow::showSnifferWindow); connect(ui->actionMotorControlConfig, &QAction::triggered, this, &MainWindow::showMCConfigWindow); + connect(ui->actionCapture_Bisector, &QAction::triggered, this, &MainWindow::showBisectWindow); + + connect(CANConManager::getInstance(), &CANConManager::framesReceived, model, &CANFrameModel::addFrames); - lbStatusConnected.setText(tr("Not connected")); + lbStatusConnected.setText(tr("Connected to 0 buses")); updateFileStatus(); lbStatusDatabase.setText(tr("No DBC database loaded")); ui->statusBar->addWidget(&lbStatusConnected); @@ -157,7 +142,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->lbNumFrames->setText("0"); connect(&updateTimer, &QTimer::timeout, this, &MainWindow::tickGUIUpdate); - updateTimer.setInterval(250); + updateTimer.setInterval(500); //test 250); updateTimer.start(); elapsedTime = new QTime; @@ -178,15 +163,19 @@ MainWindow::MainWindow(QWidget *parent) : qDebug() << "normal row height = " << normalRowHeight; model->clearFrames(); + //connect(CANConManager::getInstance(), CANConManager::connectionStatusUpdated, this, MainWindow::connectionStatusUpdated); + connect(CANConManager::getInstance(), SIGNAL(connectionStatusUpdated(int)), this, SLOT(connectionStatusUpdated(int))); + //Automatically create the connection window so it can be updated even if we never opened it. connectionWindow = new ConnectionWindow(); - connect(connectionWindow, SIGNAL(updateConnectionSettings(QString,QString,int,int)), this, SLOT(updateConnectionSettings(QString,QString,int,int))); + connect(this, SIGNAL(suspendCapturing(bool)), connectionWindow, SLOT(setSuspendAll(bool))); + } MainWindow::~MainWindow() { - serialWorkerThread.quit(); - serialWorkerThread.wait(); + //serialWorkerThread.quit(); + //serialWorkerThread.wait(); //delete worker; if (graphingWindow) @@ -284,13 +273,24 @@ MainWindow::~MainWindow() isoWindow->close(); delete isoWindow; } + if (snifferWindow) + { + snifferWindow->close(); + delete snifferWindow; + snifferWindow = NULL; + } - delete elapsedTime; + if (bisectWindow) + { + bisectWindow->close(); + delete bisectWindow; + bisectWindow = NULL; + } - delete ui; - delete dbcHandler; - model->clearFrames(); delete model; + delete elapsedTime; + delete dbcHandler; + delete ui; } void MainWindow::exitApp() @@ -311,6 +311,7 @@ void MainWindow::exitApp() if (fuzzingWindow) fuzzingWindow->close(); if (udsScanWindow) udsScanWindow->close(); if (isoWindow) isoWindow->close(); + if (snifferWindow) snifferWindow->close(); this->close(); } @@ -340,16 +341,16 @@ void MainWindow::readSettings() ui->cbAutoScroll->setChecked(true); } + /* int cType = settings.value("Main/DefaultConnectionType", 0).toInt(); if (cType == 0) connType = "GVRET"; if (cType == 1) connType = "KVASER"; if (cType == 2) connType = "SOCKETCAN"; portName = settings.value("Main/DefaultConnectionPort", "").toString(); - canSpeed0 = -1; - canSpeed1 = -1; + */ - qDebug() << connType; - qDebug() << portName; + //qDebug() << connType; + //qDebug() << portName; //"Main/SingleWireMode" @@ -380,52 +381,18 @@ void MainWindow::writeSettings() void MainWindow::updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1) { - connType = connectionType; - portName = port; + Q_UNUSED(connectionType); + Q_UNUSED(port); + Q_UNUSED(speed0); + Q_UNUSED(speed1); + //connType = connectionType; + //portName = port; - canSpeed0 = speed0; - canSpeed1 = speed1; + //canSpeed0 = speed0; + //canSpeed1 = speed1; if (isConnected) { - emit updateBaudRates(speed0, speed1); - } -} - -void MainWindow::connButtonPress() -{ - if (!isConnected) - { - if (connType == "GVRET") - { - QList ports; - ports = QSerialPortInfo::availablePorts(); - - for (int i = 0; i < ports.count(); i++) - { - if (ports[i].portName() == portName) - { - portInfo = ports[i]; - //need to create some way to send single wire mode to serial port code - emit sendSerialPort(&portInfo); - lbStatusConnected.setText(tr("Attempting to connect to port ") + portName); - } - } - } - else if (connType == "KVASER") - { - - } - else if (connType == "SOCKETCAN") - { - - } - } - else - { - emit closeSerialPort(); - isConnected = false; - lbStatusConnected.setText(tr("Not Connected")); - ui->actionConnect->setText(tr("Connect")); + //emit updateBaudRates(speed0, speed1); } } @@ -517,28 +484,30 @@ void MainWindow::filterClearAll() void MainWindow::tickGUIUpdate() { - int elapsed = elapsedTime->elapsed(); - if(elapsed) { - framesPerSec += rxFrames * 1000 / elapsed - (framesPerSec / 4); - elapsedTime->restart(); - } - else - framesPerSec = 0; - - model->sendBulkRefresh(rxFrames); + rxFrames = model->sendBulkRefresh(); + //if(rxFrames>0) + //{ + int elapsed = elapsedTime->elapsed(); + if(elapsed) { + framesPerSec = rxFrames * 1000 / elapsed; + elapsedTime->restart(); + } + else + framesPerSec = 0; - ui->lbNumFrames->setText(QString::number(model->rowCount())); - if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom(); - ui->lbFPS->setText(QString::number(framesPerSec / 4)); - if (rxFrames > 0) - { - bDirty = true; - emit framesUpdated(rxFrames); //anyone care that frames were updated? - } + ui->lbNumFrames->setText(QString::number(model->rowCount())); + if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom(); + ui->lbFPS->setText(QString::number(framesPerSec)); + if (rxFrames > 0) + { + bDirty = true; + emit framesUpdated(rxFrames); //anyone care that frames were updated? + } - if (model->needsFilterRefresh()) updateFilterList(); + if (model->needsFilterRefresh()) updateFilterList(); - rxFrames = 0; + rxFrames = 0; + //} } void MainWindow::gotFrames(int framesSinceLastUpdate) @@ -549,7 +518,7 @@ void MainWindow::gotFrames(int framesSinceLastUpdate) void MainWindow::addFrameToDisplay(CANFrame &frame, bool autoRefresh = false) { - model->addFrame(frame, autoRefresh); + model->addFrame(frame, autoRefresh); if (autoRefresh) { if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom(); @@ -572,6 +541,7 @@ void MainWindow::clearFrames() { ui->canFramesView->scrollToTop(); model->clearFrames(); + CANConManager::getInstance()->resetTimeBasis(); ui->lbNumFrames->setText(QString::number(model->rowCount())); bDirty = false; loadedFileName = ""; @@ -585,16 +555,6 @@ void MainWindow::normalizeTiming() emit framesUpdated(-2); //claim an all new set of frames because every frame was updated. } -void MainWindow::changeBaudRates() -{ - int Speed1 = 0, Speed2 = 0; - - //Speed1 = ui->cbSpeed1->currentText().toInt(); - //Speed2 = ui->cbSpeed2->currentText().toInt(); - - emit updateBaudRates(Speed1, Speed2); -} - void MainWindow::handleLoadFile() { QString filename; @@ -726,7 +686,7 @@ Data Bytes: 88 10 00 13 BB 00 06 00 outFile->write(builderString.toUtf8()); builderString = tr("Data Bytes: "); - for (int temp = 0; temp < thisFrame.len; temp++) + for (unsigned int temp = 0; temp < thisFrame.len; temp++) { builderString += Utility::formatNumber(thisFrame.data[temp]) + " "; } @@ -761,52 +721,16 @@ void MainWindow::toggleCapture() { allowCapture = !allowCapture; if (allowCapture) - { ui->btnCaptureToggle->setText("Suspend Capturing"); - emit startFrameCapturing(); - } else - { ui->btnCaptureToggle->setText("Restart Capturing"); - emit stopFrameCapturing(); - } -} - -void MainWindow::connectionSucceeded(int baud0, int baud1) -{ - lbStatusConnected.setText(tr("Connected to GVRET")); - //finally, find the baud rate in the list of rates or - //add it to the bottom if needed (that'll be weird though... -/* - int idx = ui->cbSpeed1->findText(QString::number(baud0)); - if (idx > -1) ui->cbSpeed1->setCurrentIndex(idx); - else - { - ui->cbSpeed1->addItem(QString::number(baud0)); - ui->cbSpeed1->setCurrentIndex(ui->cbSpeed1->count() - 1); - } - idx = ui->cbSpeed2->findText(QString::number(baud1)); - if (idx > -1) ui->cbSpeed2->setCurrentIndex(idx); - else - { - ui->cbSpeed2->addItem(QString::number(baud1)); - ui->cbSpeed2->setCurrentIndex(ui->cbSpeed2->count() - 1); - } - */ - if (connectionWindow) connectionWindow->setSpeeds(baud0, baud1); - //ui->btnConnect->setEnabled(false); - ui->actionConnect->setText(tr("Disconnect")); - isConnected = true; + emit suspendCapturing(!allowCapture); } -void MainWindow::connectionFailed() -{ - lbStatusConnected.setText(tr("Failed to connect!")); - - QMessageBox msgBox; - msgBox.setText("Connection to the GVRET firmware failed.\nYou might have an old version of GVRET\nor may have chosen the wrong serial port."); - msgBox.exec(); +void MainWindow::connectionStatusUpdated(int conns) +{ + lbStatusConnected.setText(tr("Connected to ") + QString::number(conns) + tr(" buses")); } void MainWindow::updateFileStatus() @@ -835,33 +759,6 @@ void MainWindow::updateFileStatus() lbStatusFilename.setText(output); } -void MainWindow::gotDeviceInfo(int build, int swCAN) -{ - QString str = tr("Connected to GVRET ") + QString::number(build); - if (swCAN == 1) str += "(SW)"; - lbStatusConnected.setText(str); - - if (build < CURRENT_GVRET_VER) - { - QMessageBox msgBox; - msgBox.setText("It appears that you are not running\nan up-to-date version of GVRET\n\nYour version: " - + QString::number(build) +"\nCurrent Version: " + QString::number(CURRENT_GVRET_VER) - + "\n\nPlease upgrade your firmware version.\nOtherwise, you may experience difficulties."); - msgBox.exec(); - } - - if (connectionWindow) - { - if (swCAN == 1) connectionWindow->setCAN1SWMode(true); - else connectionWindow->setCAN1SWMode(false); - } -} - -void MainWindow::setTargettedID(int id) -{ - worker->targetFrameID(id); -} - void MainWindow::showSettingsDialog() { if (!settingsDialog) @@ -914,6 +811,22 @@ void MainWindow::showISOInterpreterWindow() isoWindow->show(); } +void MainWindow::showSnifferWindow() +{ + if (!snifferWindow) + snifferWindow = new SnifferWindow(this); + snifferWindow->show(); +} + +void MainWindow::showBisectWindow() +{ + if (!bisectWindow) + { + bisectWindow = new BisectWindow(model->getListReference()); + } + bisectWindow->show(); +} + void MainWindow::showFrameSenderWindow() { if (!frameSenderWindow) @@ -922,8 +835,6 @@ void MainWindow::showFrameSenderWindow() frameSenderWindow = new FrameSenderWindow(model->getListReference()); else frameSenderWindow = new FrameSenderWindow(model->getFilteredListReference()); - - connect(frameSenderWindow, &FrameSenderWindow::sendCANFrame, worker, &SerialWorker::sendFrame); } frameSenderWindow->show(); } @@ -933,9 +844,9 @@ void MainWindow::showPlaybackWindow() if (!playbackWindow) { if (!useFiltered) - playbackWindow = new FramePlaybackWindow(model->getListReference(), worker); + playbackWindow = new FramePlaybackWindow(model->getListReference()); else - playbackWindow = new FramePlaybackWindow(model->getFilteredListReference(), worker); + playbackWindow = new FramePlaybackWindow(model->getFilteredListReference()); } playbackWindow->show(); } @@ -945,8 +856,6 @@ void MainWindow::showFirmwareUploaderWindow() if (!firmwareUploaderWindow) { firmwareUploaderWindow = new FirmwareUploaderWindow(model->getListReference()); - connect(firmwareUploaderWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int))); - connect(worker, SIGNAL(gotTargettedFrame(int)), firmwareUploaderWindow, SLOT(gotTargettedFrame(int))); } firmwareUploaderWindow->show(); } @@ -974,8 +883,6 @@ void MainWindow::showFuzzingWindow() if (!fuzzingWindow) { fuzzingWindow = new FuzzingWindow(model->getListReference()); - connect(fuzzingWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int))); - connect(fuzzingWindow, SIGNAL(sendFrameBatch(const QList*)), worker, SLOT(sendFrameBatch(const QList*))); } fuzzingWindow->show(); } @@ -985,8 +892,8 @@ void MainWindow::showMCConfigWindow() if (!motorctrlConfigWindow) { motorctrlConfigWindow = new MotorControllerConfigWindow(model->getListReference()); - connect(motorctrlConfigWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int))); - connect(motorctrlConfigWindow, SIGNAL(sendFrameBatch(const QList*)), worker, SLOT(sendFrameBatch(const QList*))); + //connect(motorctrlConfigWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int))); + //connect(motorctrlConfigWindow, SIGNAL(sendFrameBatch(const QList*)), worker, SLOT(sendFrameBatch(const QList*))); } motorctrlConfigWindow->show(); } @@ -996,7 +903,6 @@ void MainWindow::showUDSScanWindow() if (!udsScanWindow) { udsScanWindow = new UDSScanWindow(model->getListReference()); - connect(udsScanWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int))); } udsScanWindow->show(); } @@ -1006,7 +912,6 @@ void MainWindow::showScriptingWindow() if (!scriptingWindow) { scriptingWindow = new ScriptingWindow(model->getListReference()); - connect(scriptingWindow, &ScriptingWindow::sendCANFrame, worker, &SerialWorker::sendFrame); } scriptingWindow->show(); } @@ -1060,7 +965,6 @@ void MainWindow::showConnectionSettingsWindow() if (!connectionWindow) { connectionWindow = new ConnectionWindow(); - connect(connectionWindow, SIGNAL(updateConnectionSettings(QString,QString,int,int)), this, SLOT(updateConnectionSettings(QString,QString,int,int))); } connectionWindow->show(); } diff --git a/mainwindow.h b/mainwindow.h index d6f1bfd1..2ad48bc6 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -8,26 +8,30 @@ #include "canframemodel.h" #include "can_structs.h" #include "framefileio.h" -#include "graphingwindow.h" -#include "frameinfowindow.h" +#include "re/graphingwindow.h" +#include "re/frameinfowindow.h" #include "frameplaybackwindow.h" -#include "flowviewwindow.h" +#include "bisectwindow.h" +#include "re/flowviewwindow.h" #include "framesenderwindow.h" -#include "filecomparatorwindow.h" -#include "dbchandler.h" -#include "dbcmaineditor.h" +#include "re/filecomparatorwindow.h" +#include "dbc/dbchandler.h" +#include "dbc/dbcmaineditor.h" #include "mainsettingsdialog.h" #include "firmwareuploaderwindow.h" -#include "discretestatewindow.h" -#include "connectionwindow.h" +#include "re/discretestatewindow.h" +#include "connections/connectionwindow.h" #include "scriptingwindow.h" -#include "rangestatewindow.h" -#include "dbcloadsavewindow.h" -#include "fuzzingwindow.h" -#include "udsscanwindow.h" -#include "isotp_interpreterwindow.h" +#include "re/rangestatewindow.h" +#include "dbc/dbcloadsavewindow.h" +#include "re/fuzzingwindow.h" +#include "re/udsscanwindow.h" +#include "re/sniffer/snifferwindow.h" +#include "re/isotp_interpreterwindow.h" #include "motorcontrollerconfigwindow.h" +class ConnectionWindow; + namespace Ui { class MainWindow; } @@ -40,7 +44,6 @@ class MainWindow : public QMainWindow explicit MainWindow(QWidget *parent = 0); static QString loadedFileName; static MainWindow *getReference(); - void setTargettedID(int); ~MainWindow(); private slots: @@ -49,7 +52,6 @@ private slots: void handleSaveFilteredFile(); void handleSaveFilters(); void handleLoadFilters(); - void connButtonPress(); void showGraphingWindow(); void showFrameDataAnalysis(); void clearFrames(); @@ -69,12 +71,11 @@ private slots: void showMCConfigWindow(); void showUDSScanWindow(); void showISOInterpreterWindow(); + void showSnifferWindow(); + void showBisectWindow(); void exitApp(); void handleSaveDecoded(); - void changeBaudRates(); - void connectionFailed(); - void gotDeviceInfo(int, int); - void connectionSucceeded(int, int); + void connectionStatusUpdated(int conns); void gridClicked(QModelIndex); void gridDoubleClicked(QModelIndex); void interpretToggled(bool); @@ -94,12 +95,8 @@ public slots: void updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1); signals: - void sendSerialPort(QSerialPortInfo *port); - void closeSerialPort(); - void updateBaudRates(int, int); void sendCANFrame(const CANFrame *, int); - void stopFrameCapturing(); - void startFrameCapturing(); + void suspendCapturing(bool); //-1 = frames cleared, -2 = a new file has been loaded (so all frames are different), otherwise # of new frames void framesUpdated(int numFrames); //something has updated the frame list @@ -114,8 +111,6 @@ public slots: //canbus related data CANFrameModel *model; DBCHandler *dbcHandler; - QThread serialWorkerThread; - SerialWorker *worker; QByteArray inputBuffer; QTimer updateTimer; QTime *elapsedTime; @@ -146,7 +141,9 @@ public slots: FuzzingWindow *fuzzingWindow; UDSScanWindow *udsScanWindow; ISOTP_InterpreterWindow *isoWindow; + SnifferWindow* snifferWindow; MotorControllerConfigWindow *motorctrlConfigWindow; + BisectWindow* bisectWindow; //various private storage QLabel lbStatusConnected; @@ -154,9 +151,6 @@ public slots: QLabel lbStatusDatabase; int normalRowHeight; bool isConnected; - QSerialPortInfo portInfo; - QString connType, portName; - int canSpeed0, canSpeed1; //private methods void saveDecodedTextFile(QString); diff --git a/discretestatewindow.cpp b/re/discretestatewindow.cpp similarity index 98% rename from discretestatewindow.cpp rename to re/discretestatewindow.cpp index 473402e7..f6f46bee 100644 --- a/discretestatewindow.cpp +++ b/re/discretestatewindow.cpp @@ -267,6 +267,8 @@ void DiscreteStateWindow::handleTick() { case DWStates::IDLE: break; + case DWStates::DONE: + break; case DWStates::COUNTDOWN_SIGNAL: ticksUntilStateChange--; if (ticksUntilStateChange == 0) @@ -334,7 +336,7 @@ void DiscreteStateWindow::calculateResults() frameCache.clear(); for (int i = 0; i < modelFrames->count(); i++) { - if (modelFrames->at(i).ID == it.key()) frameCache.append(modelFrames->at(i)); + if (modelFrames->at(i).ID == (unsigned int)it.key()) frameCache.append(modelFrames->at(i)); } for (int bits = maxBits; bits >= minBits; bits--) { diff --git a/discretestatewindow.h b/re/discretestatewindow.h similarity index 100% rename from discretestatewindow.h rename to re/discretestatewindow.h diff --git a/filecomparatorwindow.cpp b/re/filecomparatorwindow.cpp similarity index 98% rename from filecomparatorwindow.cpp rename to re/filecomparatorwindow.cpp index 83f120ef..9ab25f41 100644 --- a/filecomparatorwindow.cpp +++ b/re/filecomparatorwindow.cpp @@ -112,7 +112,7 @@ void FileComparatorWindow::calculateDetails() CANFrame frame = interestedFrames.at(x); if (interestedIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there { - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { interestedIDs[frame.ID].values[y][frame.data[y]]++; tmp = frame.data[y]; @@ -137,7 +137,7 @@ void FileComparatorWindow::calculateDetails() } } //memset(newData->values, 0, 256 * 8); - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { newData->values[y][frame.data[y]] = 1; tmp = frame.data[y]; @@ -154,7 +154,7 @@ void FileComparatorWindow::calculateDetails() CANFrame frame = referenceFrames.at(x); if (referenceIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there { - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { referenceIDs[frame.ID].values[y][frame.data[y]]++; tmp = frame.data[y]; @@ -177,7 +177,7 @@ void FileComparatorWindow::calculateDetails() } } //memset(newData->values, 0, 256 * 8); - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { newData->values[y][frame.data[y]] = 1; tmp = frame.data[y]; diff --git a/filecomparatorwindow.h b/re/filecomparatorwindow.h similarity index 100% rename from filecomparatorwindow.h rename to re/filecomparatorwindow.h diff --git a/flowviewwindow.cpp b/re/flowviewwindow.cpp similarity index 98% rename from flowviewwindow.cpp rename to re/flowviewwindow.cpp index f443d491..a46aa582 100644 --- a/flowviewwindow.cpp +++ b/re/flowviewwindow.cpp @@ -371,7 +371,7 @@ void FlowViewWindow::updatedFrames(int numFrames) else //just got some new frames. See if they are relevant. { if (numFrames > modelFrames->count()) return; - int refID; + unsigned int refID; if (frameCache.count() > 0) refID = frameCache[0].ID; else refID = 0; bool needRefresh = false; @@ -382,7 +382,7 @@ void FlowViewWindow::updatedFrames(int numFrames) if (!foundID.contains(thisFrame.ID)) { foundID.append(thisFrame.ID); - QListWidgetItem* item = new QListWidgetItem(Utility::formatNumber(thisFrame.ID), ui->listFrameID); + /*QListWidgetItem* item =*/ new QListWidgetItem(Utility::formatNumber(thisFrame.ID), ui->listFrameID); } if (thisFrame.ID == refID) @@ -495,7 +495,7 @@ void FlowViewWindow::refreshIDList() if (!foundID.contains(id)) { foundID.append(id); - QListWidgetItem* item = new QListWidgetItem(Utility::formatNumber(id), ui->listFrameID); + /*QListWidgetItem* item = */ new QListWidgetItem(Utility::formatNumber(id), ui->listFrameID); } } //default is to sort in ascending order @@ -510,7 +510,7 @@ void FlowViewWindow::updateFrameLabel() void FlowViewWindow::changeID(QString newID) { //parse the ID and then load up the frame cache with just messages with that ID. - int id = Utility::ParseStringToNum(newID); + uint32_t id = (uint32_t)Utility::ParseStringToNum(newID); frameCache.clear(); if (modelFrames->count() == 0) return; @@ -531,7 +531,7 @@ void FlowViewWindow::changeID(QString newID) if (frameCache.count() == 0) return; removeAllGraphs(); - for (int c = 0; c < frameCache.at(0).len; c++) + for (uint32_t c = 0; c < frameCache.at(0).len; c++) { createGraph(c); } diff --git a/flowviewwindow.h b/re/flowviewwindow.h similarity index 100% rename from flowviewwindow.h rename to re/flowviewwindow.h diff --git a/frameinfowindow.cpp b/re/frameinfowindow.cpp similarity index 99% rename from frameinfowindow.cpp rename to re/frameinfowindow.cpp index 33c5aa54..4ba44335 100644 --- a/frameinfowindow.cpp +++ b/re/frameinfowindow.cpp @@ -84,7 +84,7 @@ void FrameInfoWindow::updatedFrames(int numFrames) else //just got some new frames. See if they are relevant. { if (numFrames > modelFrames->count()) return; - int currID = 0; + unsigned int currID = 0; if (ui->listFrameID->currentItem()) currID = ui->listFrameID->currentItem()->text().toInt(NULL, 16); bool foundID = false; @@ -140,7 +140,7 @@ void FrameInfoWindow::updateDetailsWindow(QString newID) for (int i = 0; i < modelFrames->count(); i++) { CANFrame thisFrame = modelFrames->at(i); - if (thisFrame.ID == targettedID) frameCache.append(thisFrame); + if (thisFrame.ID == (unsigned int)targettedID) frameCache.append(thisFrame); } ui->treeDetails->clear(); diff --git a/frameinfowindow.h b/re/frameinfowindow.h similarity index 100% rename from frameinfowindow.h rename to re/frameinfowindow.h diff --git a/fuzzingwindow.cpp b/re/fuzzingwindow.cpp similarity index 94% rename from fuzzingwindow.cpp rename to re/fuzzingwindow.cpp index 45e564c9..d2b62a33 100644 --- a/fuzzingwindow.cpp +++ b/re/fuzzingwindow.cpp @@ -3,6 +3,7 @@ #include "utility.h" #include #include "mainwindow.h" +#include "connections/canconmanager.h" FuzzingWindow::FuzzingWindow(const QVector *frames, QWidget *parent) : QDialog(parent), @@ -36,9 +37,10 @@ FuzzingWindow::FuzzingWindow(const QVector *frames, QWidget *parent) : fuzzTimer->setInterval(ui->spinTiming->value()); - ui->cbBuses->addItem(tr("0")); - ui->cbBuses->addItem(tr("1")); - ui->cbBuses->addItem(tr("Both")); + int numBuses = CANConManager::getInstance()->getNumBuses(); + for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); + ui->cbBuses->addItem(tr("All")); + } FuzzingWindow::~FuzzingWindow() @@ -48,7 +50,6 @@ FuzzingWindow::~FuzzingWindow() void FuzzingWindow::updatedFrames(int numFrames) { - CANFrame thisFrame; int id; if (numFrames == -1) //all frames deleted. Kill the display { @@ -111,8 +112,7 @@ void FuzzingWindow::timerTriggered() { CANFrame thisFrame; sendingBuffer.clear(); - int buses = ui->cbBuses->currentIndex() + 1; - if (buses == 0) buses = 1; + int buses = ui->cbBuses->currentIndex(); for (int count = 0; count < ui->spinBurst->value(); count++) { thisFrame.ID = currentID; @@ -121,22 +121,26 @@ void FuzzingWindow::timerTriggered() else thisFrame.extended = false; thisFrame.bus = 0; //hard coded for now. TODO: do not hard code thisFrame.len = ui->spinBytes->value(); - if (buses & 1) + + if (buses < (ui->cbBuses->count() - 1)) { - thisFrame.bus = 0; + thisFrame.bus = buses; sendingBuffer.append(thisFrame); } - if (buses & 2) + else //fuzz all the buses! HACK THE PLANET! Er, something... { - thisFrame.bus = 1; - sendingBuffer.append(thisFrame); + for (int j = 0; j < ui->cbBuses->count() - 1; j++) + { + thisFrame.bus = j; + sendingBuffer.append(thisFrame); + } } calcNextID(); calcNextBitPattern(); numSentFrames++; } - emit sendFrameBatch(&sendingBuffer); + CANConManager::getInstance()->sendFrames(sendingBuffer); ui->lblNumFrames->setText("# of sent frames: " + QString::number(numSentFrames)); } @@ -252,7 +256,7 @@ void FuzzingWindow::calcNextBitPattern() for (int bit = 0; bit < 8; bit++) { thisBit = bitGrid[byt * 8 + bit]; - if (thisBit == 1 && (byt * 8 + bit) == bitAccum) + if ( (thisBit == 1) && (unsigned int)(byt * 8 + bit) == bitAccum) { currentBytes[byt] |= (1 << bit); } diff --git a/fuzzingwindow.h b/re/fuzzingwindow.h similarity index 96% rename from fuzzingwindow.h rename to re/fuzzingwindow.h index 45216025..724d84c7 100644 --- a/fuzzingwindow.h +++ b/re/fuzzingwindow.h @@ -29,7 +29,7 @@ class FuzzingWindow : public QDialog ~FuzzingWindow(); signals: - void sendCANFrame(const CANFrame *, int); + void sendCANFrame(const CANFrame *); void sendFrameBatch(const QList *); private slots: diff --git a/graphingwindow.cpp b/re/graphingwindow.cpp similarity index 99% rename from graphingwindow.cpp rename to re/graphingwindow.cpp index 88a2ddfb..a401eac9 100644 --- a/graphingwindow.cpp +++ b/re/graphingwindow.cpp @@ -178,6 +178,7 @@ void GraphingWindow::plottableDoubleClick(QCPAbstractPlottable* plottable, QMous void GraphingWindow::gotCenterTimeID(int32_t ID, double timestamp) { + Q_UNUSED(ID) //its problematic to try to highlight a graph since we get the ID //and timestamp not the signal in question so there is no real way //to know which graph. But, if that changes here is a stub @@ -195,8 +196,8 @@ void GraphingWindow::gotCenterTimeID(int32_t ID, double timestamp) void GraphingWindow::titleDoubleClick(QMouseEvent* event, QCPPlotTitle* title) { Q_UNUSED(event) + Q_UNUSED(title) // Set the plot title by double clicking on it - bool ok; /* QString newTitle = QInputDialog::getText(this, "SavvyCAN Graphing", "New plot title:", QLineEdit::Normal, title->text(), &ok); @@ -354,6 +355,8 @@ bool GraphingWindow::eventFilter(QObject *obj, QEvent *event) // standard event processing return QObject::eventFilter(obj, event); } + + return false; } void GraphingWindow::resetView() diff --git a/graphingwindow.h b/re/graphingwindow.h similarity index 98% rename from graphingwindow.h rename to re/graphingwindow.h index 48872439..e3fad883 100644 --- a/graphingwindow.h +++ b/re/graphingwindow.h @@ -3,7 +3,7 @@ #include "qcustomplot.h" #include "can_structs.h" -#include "dbchandler.h" +#include "dbc/dbchandler.h" #include diff --git a/isotp_handler.cpp b/re/isotp_handler.cpp similarity index 99% rename from isotp_handler.cpp rename to re/isotp_handler.cpp index 0fdac38f..f679213e 100644 --- a/isotp_handler.cpp +++ b/re/isotp_handler.cpp @@ -151,7 +151,7 @@ void ISOTP_HANDLER::processFrame(const CANFrame &frame) int frameType; int frameLen; int ln; - int offset; + //int offset; ISOTP_MESSAGE msg; ISOTP_MESSAGE *pMsg; @@ -230,7 +230,7 @@ void ISOTP_HANDLER::processFrame(const CANFrame &frame) } if (!pMsg) return; ln = pMsg->len - pMsg->data.count(); - offset = pMsg->data.count(); + //offset = pMsg->data.count(); if (useExtendedAddressing) { if (ln > 6) ln = 6; diff --git a/isotp_handler.h b/re/isotp_handler.h similarity index 100% rename from isotp_handler.h rename to re/isotp_handler.h diff --git a/isotp_interpreterwindow.cpp b/re/isotp_interpreterwindow.cpp similarity index 100% rename from isotp_interpreterwindow.cpp rename to re/isotp_interpreterwindow.cpp diff --git a/isotp_interpreterwindow.h b/re/isotp_interpreterwindow.h similarity index 100% rename from isotp_interpreterwindow.h rename to re/isotp_interpreterwindow.h diff --git a/newgraphdialog.cpp b/re/newgraphdialog.cpp similarity index 99% rename from newgraphdialog.cpp rename to re/newgraphdialog.cpp index 79da03ea..e2d6092b 100644 --- a/newgraphdialog.cpp +++ b/re/newgraphdialog.cpp @@ -145,7 +145,6 @@ void NewGraphDialog::loadSignals(int idx) void NewGraphDialog::bitfieldClicked(int x,int y) { int bit = (y * 8 + (7-x)); - int res; qDebug() << "Clicked bit: " << bit; startBit = bit; diff --git a/newgraphdialog.h b/re/newgraphdialog.h similarity index 96% rename from newgraphdialog.h rename to re/newgraphdialog.h index 907a03cc..85ce74c6 100644 --- a/newgraphdialog.h +++ b/re/newgraphdialog.h @@ -3,7 +3,7 @@ #include #include "graphingwindow.h" -#include "dbchandler.h" +#include "dbc/dbchandler.h" namespace Ui { class NewGraphDialog; diff --git a/rangestatewindow.cpp b/re/rangestatewindow.cpp similarity index 99% rename from rangestatewindow.cpp rename to re/rangestatewindow.cpp index 4171fc16..76d03e32 100644 --- a/rangestatewindow.cpp +++ b/re/rangestatewindow.cpp @@ -171,7 +171,7 @@ void RangeStateWindow::refreshFilterList() void RangeStateWindow::recalcButton() { QHash::iterator iter; - int id; + uint32_t id; ui->listCandidates->clear(); foundSignals.clear(); @@ -376,7 +376,7 @@ void RangeStateWindow::createGraph(QVector values) else ymin *= 0.8; ymax = maxval; - if (ymax < 0) ymax * 0.8; + if (ymax < 0) ymax *= 0.8; else ymax *= 1.2; if (fabs(ymin) < 0.01) ymin -= (ymax / 60.0); @@ -401,7 +401,7 @@ void RangeStateWindow::clickedSignalList(int idx) { if (idx == -1) return; //just in case... - int id, startBit, bitLength; + uint32_t id, startBit, bitLength; bool isSigned = false, isBigEndian = false; int64_t valu; diff --git a/rangestatewindow.h b/re/rangestatewindow.h similarity index 100% rename from rangestatewindow.h rename to re/rangestatewindow.h diff --git a/re/sniffer/snifferitem.cpp b/re/sniffer/snifferitem.cpp new file mode 100644 index 00000000..af8bee1e --- /dev/null +++ b/re/sniffer/snifferitem.cpp @@ -0,0 +1,86 @@ +#include +#include +#include "snifferitem.h" + + +SnifferItem::SnifferItem(const CANFrame& pFrame): + mNotch(0), + mID(pFrame.ID) +{ + mMarker = {0,0}; + mLastMarker = {0,0}; + /* that's dirty */ + update(pFrame); + update(pFrame); +} + + +SnifferItem::~SnifferItem() +{ + +} + +quint64 SnifferItem::getId() const +{ + return mID; +} + +float SnifferItem::getDelta() const +{ + return ((float)(mCurrentTime-mLastTime))/1000000; +} + +int SnifferItem::getData(uchar i) const +{ + return (i>=mCurrent.len) ? -1 : ((uchar*) &mCurrent.data)[i]; +} + +dc SnifferItem::dataChange(uchar i) const +{ + if( i= ((uchar*) &mLast.data)[i] ? dc::INC : dc::DEC; + } + + return dc::NO; +} + +int SnifferItem::elapsed() const +{ + return mTime.elapsed(); +} + +void SnifferItem::update(const CANFrame& pFrame) +{ + /* copy current to last */ + mLast = mCurrent; + mLastTime = mCurrentTime; + + /* copy new value */ + memcpy(&mCurrent.data, pFrame.data, 8); + mCurrent.len = pFrame.len; + mCurrentTime = pFrame.timestamp; + + /* update marker */ + mMarker.data |= mLast.data ^ mCurrent.data; + mMarker.len |= mLast.len ^ mCurrent.len; + + /* restart timeout */ + mTime.restart(); +} + +void SnifferItem::updateMarker() +{ + mLastMarker = mMarker; + mMarker = {0, 0}; +} + +void SnifferItem::notch(bool pNotch) +{ + if(pNotch) + mNotch |= mLastMarker.data; + else + mNotch = 0; +} diff --git a/re/sniffer/snifferitem.h b/re/sniffer/snifferitem.h new file mode 100644 index 00000000..cc06c3a0 --- /dev/null +++ b/re/sniffer/snifferitem.h @@ -0,0 +1,49 @@ +#ifndef SNIFFERITEM_H +#define SNIFFERITEM_H + +#include +#include +#include "can_structs.h" + +struct fstCan +{ + quint64 data; + int len; +}; + +enum dc +{ + NO, + INC, + DEC +}; + + +class SnifferItem +{ +public: + explicit SnifferItem(const CANFrame& pFrame); + virtual ~SnifferItem(); + + quint64 getId() const; + float getDelta() const; + int getData(uchar i) const; + dc dataChange(uchar) const; + int elapsed() const; + void update(const CANFrame& pFrame); + void updateMarker(); + void notch(bool); +private: + quint64 mID; + struct fstCan mLast; + struct fstCan mCurrent; + struct fstCan mLastMarker; + struct fstCan mMarker; + quint64 mNotch; + quint64 mLastTime; + quint64 mCurrentTime; + + QTime mTime; +}; + +#endif // SNIFFERITEM_H diff --git a/re/sniffer/sniffermodel.cpp b/re/sniffer/sniffermodel.cpp new file mode 100644 index 00000000..031b487a --- /dev/null +++ b/re/sniffer/sniffermodel.cpp @@ -0,0 +1,267 @@ +#include +#include "sniffermodel.h" +#include "snifferwindow.h" + + +SnifferModel::SnifferModel(QObject *parent) + : QAbstractItemModel(parent), + mFilter(false) +{ +} + +SnifferModel::~SnifferModel() +{ + qDeleteAll(mMap); + mMap.clear(); + mFilters.clear(); +} + + +int SnifferModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : tc::LAST+1; +} + + +int SnifferModel::rowCount(const QModelIndex &parent) const +{ + const QMap& map = mFilter ? mFilters : mMap; + return parent.isValid() ? 0 : map.size(); +} + + +QVariant SnifferModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + SnifferItem *item = static_cast(index.internalPointer()); + if(!item) QVariant(); + + int col = index.column(); + + switch(role) + { + case Qt::DisplayRole: + { + switch(col) + { + case tc::DELTA: + return QString::number(item->getDelta(), 'f'); + case tc::ID: + return QString("%1").arg(item->getId(), 5, 16, QLatin1Char(' ')).toUpper(); + default: + break; + } + if(tc::DATA_0<=col && col <=tc::DATA_7) + { + int data = item->getData(col-tc::DATA_0); + if(data>=0) + return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper(); + } + break; + } + case Qt::BackgroundRole: + { + if(tc::ID==col) + { + if(item->elapsed()>4000) + return QBrush(Qt::red); + } + else if(tc::DATA_0<=col && col<=tc::DATA_7) + { + dc change = item->dataChange(col-tc::DATA_0); + switch(change) + { + case dc::INC: + return QBrush(Qt::green); + case dc::DEC: + return QBrush(Qt::red); + default: + break; + } + } + break; + } + } + + return QVariant(); +} + + +Qt::ItemFlags SnifferModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + + +QVariant SnifferModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + switch(section) + { + case tc::DELTA: + return QString("Delta"); + case tc::ID: + return QString("ID"); + default: + break; + } + if(tc::DATA_0<=section && section <=tc::DATA_7) + return QString::number(section-tc::DATA_0); + } + + return QVariant(); +} + + +QModelIndex SnifferModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid()) + return QModelIndex(); + + const QMap& map = mFilter ? mFilters : mMap; + + if(column>tc::LAST || row>=map.size()) + return QModelIndex(); + + /* ugly but I can't find best without creating a list to keep indexes */ + QMap::const_iterator iter; + int i; + for(iter = map.begin(), i=0 ; i::iterator i; + QVector toRemove; + SnifferItem* item; + + /* update markers */ + + + for (i = mMap.begin(); i != mMap.end(); ++i) + { + i.value()->updateMarker(); + if(i.value()->elapsed()>5000) + toRemove.append(i.key()); + } + + if(toRemove.size()) + { + beginResetModel(); + foreach(quint32 id, toRemove) + { + /* remove element */ + item = mMap.take(id); + mFilters.remove(id); + delete item; + /* send notification */ + emit idChange(id, false); + } + endResetModel(); + } + else + /* refresh data */ + dataChanged(createIndex(0, 0), + createIndex(rowCount()-1, columnCount()-1), QVector(Qt::DisplayRole)); +} + + +void SnifferModel::filter(fltType pType, int pId) +{ + beginResetModel(); + switch(pType) + { + case fltType::NONE: + /* erase everything */ + mFilter = true; + mFilters.clear(); + break; + case fltType::ADD: + /* add filter to list */ + mFilter = true; + mFilters[pId] = mMap[pId]; + break; + case fltType::REMOVE: + /* remove filter */ + if(!mFilter) + mFilters = mMap; + mFilter = true; + mFilters.remove(pId); + break; + case fltType::ALL: + /* stop filtering */ + mFilter = false; + mFilters.clear(); + break; + } + endResetModel(); +} + + +/***********************************************/ +/********** slots ****************/ +/***********************************************/ + +void SnifferModel::update(CANConnection*, QVector& pFrames) +{ + foreach(const CANFrame& frame, pFrames) + { + if(!mMap.contains(frame.ID)) + { + int index = std::distance(mMap.begin(), mMap.lowerBound(frame.ID)); + /* add the frame */ + beginInsertRows(QModelIndex(), index, index); + mMap[frame.ID] = new SnifferItem(frame); + endInsertRows(); + + emit idChange(frame.ID, true); + } + else + //updateData + mMap[frame.ID]->update(frame); + } +} + +void SnifferModel::notch() +{ + QMap& map = mFilter ? mFilters : mMap; + + foreach(SnifferItem* item, map) + item->notch(true); +} + +void SnifferModel::unNotch() +{ + QMap& map = mFilter ? mFilters : mMap; + + foreach(SnifferItem* item, map) + item->notch(false); +} + + diff --git a/re/sniffer/sniffermodel.h b/re/sniffer/sniffermodel.h new file mode 100644 index 00000000..7c3fc19e --- /dev/null +++ b/re/sniffer/sniffermodel.h @@ -0,0 +1,58 @@ +#ifndef SNIFFERMODEL_H +#define SNIFFERMODEL_H + +#include +#include +#include +#include + +#include "can_structs.h" +#include "connections/canconnection.h" +#include "snifferitem.h" + + +enum fltType +{ + ALL, + ADD, + REMOVE, + NONE +}; + +class SnifferModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit SnifferModel(QObject *parent = 0); + virtual ~SnifferModel(); + + /* from QAbstractItemModel */ + QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + void refresh(); + void clear(); + void filter(fltType pType, int pId=0); + +public slots: + void update(CANConnection*, QVector&); + void notch(); + void unNotch(); + +signals: + void idChange(int, bool); + +private: + QMap mMap; + QMap mFilters; + bool mFilter; +}; + +#endif // SNIFFERMODEL_H diff --git a/re/sniffer/snifferwindow.cpp b/re/sniffer/snifferwindow.cpp new file mode 100644 index 00000000..cab2a885 --- /dev/null +++ b/re/sniffer/snifferwindow.cpp @@ -0,0 +1,132 @@ +#include +#include +#include "snifferwindow.h" +#include "ui_snifferwindow.h" +#include "connections/canconmanager.h" + +SnifferWindow::SnifferWindow(QWidget *parent) : + QDialog(parent), + ui(new Ui::snifferWindow), + mModel(this), + mTimer(this), + mFilter(false) +{ + ui->setupUi(this); + ui->treeView->setModel(&mModel); + + /* set column width */ + ui->treeView->setColumnWidth(tc::ID, 50); + ui->treeView->setColumnWidth(tc::LAST, 1); + for(int i=tc::DATA_0 ; i<=tc::DATA_7 ; i++) + ui->treeView->setColumnWidth(i, 30); + ui->treeView->header()->setDefaultAlignment(Qt::AlignCenter); + + /* activate sorting */ + ui->listWidget->setSortingEnabled(true); + + /* connect timer */ + connect(&mTimer, &QTimer::timeout, this, &SnifferWindow::update); + mTimer.setInterval(200); + + /* connect buttons */ + connect(ui->btNotch, &QPushButton::clicked, &mModel, &SnifferModel::notch); + connect(ui->btUnNotch, &QPushButton::clicked, &mModel, &SnifferModel::unNotch); + connect(ui->btAll, &QPushButton::clicked, this, &SnifferWindow::fltAll); + connect(ui->btNone, &QPushButton::clicked, this, &SnifferWindow::fltNone); + connect(&mModel, &SnifferModel::idChange, this, &SnifferWindow::idChange); + connect(ui->listWidget, &QListWidget::itemChanged, this, &SnifferWindow::itemChanged); + +} + +SnifferWindow::~SnifferWindow() +{ + closeEvent(NULL); + delete ui; +} + + +void SnifferWindow::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + connect(CANConManager::getInstance(), &CANConManager::framesReceived, &mModel, &SnifferModel::update); + mTimer.start(); + + qDebug() << "show"; +} + + +void SnifferWindow::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event); + /* stop timer */ + mTimer.stop(); + /* disconnect reception of frames */ + disconnect(CANConManager::getInstance(), 0, this, 0); + /* clear model */ + mModel.clear(); + /* clean list */ + qDeleteAll(mMap); + mMap.clear(); + /* reset filtering */ + mFilter = false; +} + + +void SnifferWindow::update() +{ + mModel.refresh(); +} + + +void SnifferWindow::fltAll() +{ + filter(false); +} + + +void SnifferWindow::fltNone() +{ + filter(true); +} + +void SnifferWindow::filter(bool pFilter) +{ + mFilter = pFilter; + mModel.filter(mFilter ? fltType::NONE : fltType::ALL); + + foreach(QListWidgetItem* item, mMap) + item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked); +} + +void SnifferWindow::idChange(int pId, bool pAdd) +{ + QListWidgetItem* item; + + if(pAdd) + { + QString text = QString("0x") + QString("%1").arg(pId, 3, 16, QLatin1Char('0')).toUpper(); + item = new QListWidgetItem(text); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked); + ui->listWidget->addItem(item); + mMap[pId] = item; + } + else + { + item = mMap.take(pId); + ui->listWidget->removeItemWidget(item); + delete item; + } +} + + +void SnifferWindow::itemChanged(QListWidgetItem * item) +{ + bool checked = (Qt::Checked == item->checkState()); + + if( !mFilter && checked ) + return; + + mModel.filter(checked ? fltType::ADD : fltType::REMOVE, mMap.key(item)); + mFilter = true; +} diff --git a/re/sniffer/snifferwindow.h b/re/sniffer/snifferwindow.h new file mode 100644 index 00000000..2d2cb1d5 --- /dev/null +++ b/re/sniffer/snifferwindow.h @@ -0,0 +1,56 @@ +#ifndef SNIFFER_H +#define SNIFFER_H + +#include +#include +#include "sniffermodel.h" + +namespace Ui { +class snifferWindow; +} + +enum tc +{ + DELTA = 0, + ID, + DATA_0, + DATA_1, + DATA_2, + DATA_3, + DATA_4, + DATA_5, + DATA_6, + DATA_7, + LAST +}; + + +class SnifferWindow : public QDialog +{ + Q_OBJECT + +public: + explicit SnifferWindow(QWidget *parent = 0); + ~SnifferWindow(); + + void showEvent(QShowEvent*); + void closeEvent(QCloseEvent*); + +public slots: + void update(); + void idChange(int, bool); + void fltAll(); + void fltNone(); + void itemChanged(QListWidgetItem*); + +private: + void filter(bool pFilter); + + Ui::snifferWindow* ui; + SnifferModel mModel; + QTimer mTimer; + QMap mMap; + bool mFilter; +}; + +#endif // SNIFFER_H diff --git a/udsscanwindow.cpp b/re/udsscanwindow.cpp similarity index 86% rename from udsscanwindow.cpp rename to re/udsscanwindow.cpp index 7398477e..9f36c36d 100644 --- a/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -1,6 +1,7 @@ #include "udsscanwindow.h" #include "ui_udsscanwindow.h" #include "mainwindow.h" +#include "connections/canconmanager.h" UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : QDialog(parent), @@ -20,10 +21,9 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); - ui->cbBuses->addItem("0"); - ui->cbBuses->addItem("1"); - ui->cbBuses->addItem("Both"); - + int numBuses = CANConManager::getInstance()->getNumBuses(); + for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); + ui->cbBuses->addItem(tr("All")); } UDSScanWindow::~UDSScanWindow() @@ -53,8 +53,6 @@ void UDSScanWindow::scanUDS() endID = Utility::ParseStringToNum(ui->txtEndID->text()); int buses = ui->cbBuses->currentIndex(); - buses++; - if (buses < 1) buses = 1; //start out by sending tester present to every address to see if anyone replies for (id = startID; id <= endID; id++) @@ -68,16 +66,20 @@ void UDSScanWindow::scanUDS() frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; frame.data[6] = 0;frame.data[7] = 0; - if (buses & 1) + if (buses < ui->cbBuses->count()- 1) { - frame.bus = 0; + frame.bus = buses; sendingFrames.append(frame); } - if (buses & 2) + else { - frame.bus = 1; - sendingFrames.append(frame); + for (int c = 0; c < ui->cbBuses->count() - 1; c++) + { + frame.bus = c; + sendingFrames.append(frame); + } } + } //then try asking for the various diagnostic session types @@ -94,15 +96,18 @@ void UDSScanWindow::scanUDS() frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; frame.data[6] = 0;frame.data[7] = 0; - if (buses & 1) + if (buses < ui->cbBuses->count()- 1) { - frame.bus = 0; + frame.bus = buses; sendingFrames.append(frame); } - if (buses & 2) + else { - frame.bus = 1; - sendingFrames.append(frame); + for (int c = 0; c < ui->cbBuses->count() - 1; c++) + { + frame.bus = c; + sendingFrames.append(frame); + } } } } @@ -129,11 +134,12 @@ void UDSScanWindow::updatedFrames(int numFrames) } //Updates here are nearly once per millisecond if there is heavy traffic. That's more like it! +//TODO: I really doubt this works anymore with the new connection system. This breaks the UDS scanner for now! ;( void UDSScanWindow::rapidFrames(int numFrames) { CANFrame thisFrame; QString result; - int id; + uint32_t id; int offset = ui->spinReplyOffset->value(); CANFrame sentFrame; bool gotReply = false; @@ -151,7 +157,7 @@ void UDSScanWindow::rapidFrames(int numFrames) thisFrame = modelFrames->at(i); id = thisFrame.ID; - if ((id == (sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) + if ((id == (uint32_t)(sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) { int temp = thisFrame.data[0] >> 4; if (temp == 0) //single frame reply (maybe) @@ -210,7 +216,7 @@ void UDSScanWindow::sendNextMsg() currIdx++; if (currIdx < sendingFrames.count()) { - emit sendCANFrame(&sendingFrames[currIdx], sendingFrames[currIdx].bus); + CANConManager::getInstance()->sendFrame(sendingFrames[currIdx]); waitTimer->start(); } else diff --git a/udsscanwindow.h b/re/udsscanwindow.h similarity index 92% rename from udsscanwindow.h rename to re/udsscanwindow.h index 10661980..4039345b 100644 --- a/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -17,9 +17,6 @@ class UDSScanWindow : public QDialog explicit UDSScanWindow(const QVector *frames, QWidget *parent = 0); ~UDSScanWindow(); -signals: - void sendCANFrame(const CANFrame *, int); - private slots: void updatedFrames(int numFrames); void rapidFrames(int numFrames); diff --git a/scriptcontainer.cpp b/scriptcontainer.cpp index 236b9791..66e120cf 100644 --- a/scriptcontainer.cpp +++ b/scriptcontainer.cpp @@ -1,14 +1,12 @@ -#include "scriptcontainer.h" - #include #include -ScriptContainer::ScriptContainer() -{ - fileName = QString(); - filePath = QString(); - scriptText = QString(); +#include "scriptcontainer.h" +#include "connections/canconmanager.h" +ScriptContainer::ScriptContainer(QString& pConName): + mConName(pConName) +{ connect(&timer, SIGNAL(timeout()), this, SLOT(tick())); } @@ -68,6 +66,22 @@ void ScriptContainer::setFilter(QJSValue id, QJSValue mask, QJSValue bus) CANFilter filter; filter.setFilter(idVal, maskVal, busVal); filters.append(filter); + + qDebug() << "FIXME setFilter"; + CANConnection* conn_p = CANConManager::getInstance()->getByName(mConName); + if(conn_p) + { + CANFlt canFlt; + for(int i=0 ; igetNumBuses() ; i++) + { + foreach(const CANFilter& flt, filters) + { + if(flt.bus==i) { + conn_p->addTargettedFrame(busVal, idVal, maskVal, this); + } + } + } + } } void ScriptContainer::setTickInterval(QJSValue interval) @@ -86,6 +100,13 @@ void ScriptContainer::clearFilters() { qDebug() << "Called clear filters"; filters.clear(); + + qDebug() << "FIXME clearFilters"; + CANConnection* conn_p = CANConManager::getInstance()->getByName(mConName); + if(conn_p) + { + conn_p->removeAllTargettedFrames(this); + } } void ScriptContainer::sendFrame(QJSValue bus, QJSValue id, QJSValue length, QJSValue data) @@ -93,25 +114,25 @@ void ScriptContainer::sendFrame(QJSValue bus, QJSValue id, QJSValue length, QJSV CANFrame frame; frame.extended = false; frame.ID = id.toInt(); - frame.len = length.toInt(); - if (frame.len < 0) frame.len = 0; + frame.len = length.toUInt(); if (frame.len > 8) frame.len = 8; if (!data.isArray()) qDebug() << "data isn't an array"; - for (int i = 0; i < frame.len; i++) + for (unsigned int i = 0; i < frame.len; i++) { frame.data[i] = (uint8_t)data.property(i).toInt(); } - frame.bus = bus.toInt(); - if (frame.bus < 0) frame.bus = 0; + frame.bus = (uint32_t)bus.toInt(); if (frame.bus > 1) frame.bus = 1; if (frame.ID > 0x7FF) frame.extended = true; - //qDebug() << "Sending frame from script"; - emit sendCANFrame(&frame, frame.bus); + qDebug() << "sending frame from script"; + CANConnection* conn_p = CANConManager::getInstance()->getByName(mConName); + if(conn_p) + conn_p->sendFrame(frame); } void ScriptContainer::gotFrame(const CANFrame &frame) @@ -125,7 +146,7 @@ void ScriptContainer::gotFrame(const CANFrame &frame) QJSValueList args; args << frame.bus << frame.ID << frame.len; QJSValue dataBytes = scriptEngine.newArray(frame.len); - for (int j = 0; j < frame.len; j++) dataBytes.setProperty(j, QJSValue(frame.data[j])); + for (unsigned int j = 0; j < frame.len; j++) dataBytes.setProperty(j, QJSValue(frame.data[j])); args.append(dataBytes); gotFrameFunction.call(args); return; //as soon as one filter matches we jump out diff --git a/scriptcontainer.h b/scriptcontainer.h index b570f125..241ac237 100644 --- a/scriptcontainer.h +++ b/scriptcontainer.h @@ -13,12 +13,13 @@ class ScriptContainer : public QObject Q_OBJECT public: - ScriptContainer(); + ScriptContainer(QString&); void gotFrame(const CANFrame &frame); QString fileName; QString filePath; QString scriptText; + QString mConName; public slots: void compileScript(); @@ -31,9 +32,6 @@ public slots: private slots: void tick(); -signals: - void sendCANFrame(const CANFrame *, int); - private: QJSEngine scriptEngine; QJSValue compiledScript; diff --git a/scriptingwindow.cpp b/scriptingwindow.cpp index 19ab11dc..be101374 100644 --- a/scriptingwindow.cpp +++ b/scriptingwindow.cpp @@ -3,9 +3,10 @@ #include #include +#include #include -#include "mainwindow.h" +#include "connections/canconmanager.h" ScriptingWindow::ScriptingWindow(const QVector *frames, QWidget *parent) : QDialog(parent), @@ -23,7 +24,8 @@ ScriptingWindow::ScriptingWindow(const QVector *frames, QWidget *paren connect(ui->btnRemoveScript, &QAbstractButton::pressed, this, &ScriptingWindow::deleteCurrentScript); connect(ui->btnRevertScript, &QAbstractButton::pressed, this, &ScriptingWindow::revertScript); connect(ui->btnSaveScript, &QAbstractButton::pressed, this, &ScriptingWindow::saveScript); - connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ScriptingWindow::updatedFrames); + + connect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &ScriptingWindow::newFrames); ui->txtScriptSource->setLexer(new QsciLexerJavaScript(ui->txtScriptSource)); } @@ -33,27 +35,22 @@ ScriptingWindow::~ScriptingWindow() delete ui; } -void ScriptingWindow::updatedFrames(int numFrames) + +void ScriptingWindow::newFrames(const CANConnection* pConn, const QVector& pFrames) { - CANFrame thisFrame; - //-1 means all frames deleted and -2 means a full refresh, neither of which we care about here. - if (numFrames > 0) + /*FIXME: name of the probe and bus should be checked */ + Q_UNUSED(pConn); + + for (int j = 0; j < scripts.length(); j++) { - if (numFrames > modelFrames->count()) return; - qDebug() << "Got frames into script window: " << numFrames; - //for every new frame pass it on to each script container. The container will determine if it needs to actually - //notify the script and do that if applicable. - for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++) + foreach(const CANFrame& frame, pFrames) { - thisFrame = modelFrames->at(i); - for (int j = 0; j < scripts.length(); j++) - { - scripts[j]->gotFrame(thisFrame); - } + scripts[j]->gotFrame(frame); } } } + void ScriptingWindow::closeEvent(QCloseEvent *event) { Q_UNUSED(event); @@ -90,7 +87,6 @@ void ScriptingWindow::loadNewScript() { QString filename; QFileDialog dialog; - bool result = false; ScriptContainer *container; QStringList filters; @@ -115,13 +111,19 @@ void ScriptingWindow::loadNewScript() QStringList fileList = filename.split('/'); QString justFileName = fileList[fileList.length() - 1]; ui->listLoadedScripts->addItem(justFileName); - container = new ScriptContainer(); + /* get the first connection in the list for now */ + qDebug() << "FIXME: connection is always the first in list"; + QString portName; + QList list = CANConManager::getInstance()->getConnections(); + if(!list.isEmpty()) + portName = list.first()->getPort(); + + container = new ScriptContainer(portName); container->fileName = justFileName; container->filePath = filename; container->scriptText = contents; container->setErrorWidget(ui->listErrors); container->compileScript(); - connect(container, &ScriptContainer::sendCANFrame, this, &ScriptingWindow::sendCANFrame); scripts.append(container); currentScript = container; ui->txtScriptSource->setText(container->scriptText); @@ -135,13 +137,17 @@ void ScriptingWindow::createNewScript() { ScriptContainer *container; - container = new ScriptContainer(); + QString portName; + QList list = CANConManager::getInstance()->getConnections(); + if(!list.isEmpty()) + portName = list.first()->getPort(); + + container = new ScriptContainer(portName); container->fileName = "UNNAMED_" + QString::number((qrand() % 10000)) + ".js"; container->filePath = QString(); container->scriptText = QString(); container->setErrorWidget(ui->listErrors); - connect(container, &ScriptContainer::sendCANFrame, this, &ScriptingWindow::sendCANFrame); scripts.append(container); ui->listLoadedScripts->addItem(container->fileName); currentScript = container; diff --git a/scriptingwindow.h b/scriptingwindow.h index d27620b5..38519d96 100644 --- a/scriptingwindow.h +++ b/scriptingwindow.h @@ -3,6 +3,7 @@ #include "can_structs.h" #include "scriptcontainer.h" +#include "connections/canconnection.h" #include #include @@ -28,12 +29,7 @@ private slots: void saveScript(); void revertScript(); void recompileScript(); - void updatedFrames(int); - -public slots: - -signals: - void sendCANFrame(const CANFrame *, int); + void newFrames(const CANConnection*, const QVector&); private: void closeEvent(QCloseEvent *event); @@ -44,8 +40,6 @@ public slots: QList scripts; ScriptContainer *currentScript; const QVector *modelFrames; - - }; #endif // SCRIPTINGWINDOW_H diff --git a/serialworker.h b/serialworker.h deleted file mode 100644 index 1658c04a..00000000 --- a/serialworker.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef SERIALWORKER_H -#define SERIALWORKER_H - -#include -#include -#include -#include -#include -#include "can_structs.h" -#include "canframemodel.h" - -namespace SERIALSTATE { - -enum STATE //keep this enum synchronized with the Arduino firmware project -{ - IDLE, - GET_COMMAND, - BUILD_CAN_FRAME, - TIME_SYNC, - GET_DIG_INPUTS, - GET_ANALOG_INPUTS, - SET_DIG_OUTPUTS, - SETUP_CANBUS, - GET_CANBUS_PARAMS, - GET_DEVICE_INFO, - SET_SINGLEWIRE_MODE -}; - -} - -using namespace SERIALSTATE; -class SerialWorker : public QObject -{ - Q_OBJECT - -public: - SerialWorker(CANFrameModel *model, QObject *parent = 0); - ~SerialWorker(); - void readSettings(); - void targetFrameID(int); - -signals: //we emit signals - void error(const QString &); - void frameUpdateRapid(int); //sent *much* more rapidly than the above signal - one param for # of frames - void connectionSuccess(int, int); - void connectionFailure(); - void deviceInfo(int, int); - void gotTargettedFrame(int); - -private slots: //we receive things in slots - void readSerialData(); - void connectionTimeout(); - void handleTick(); - void handleReconnect(); - -public slots: - void run(); - void setSerialPort(QSerialPortInfo*); - void closeSerialPort(); - void sendFrame(const CANFrame *, int); - void sendFrameBatch(const QList *); - void updateBaudRates(int, int); - void stopFrameCapture(); - void startFrameCapture(); //only need to call this if previously stopped. Otherwise it's the default - -private: - QString portName; - bool quit; - bool connected; - bool capturing; - bool doValidation; - bool gotValidated; - bool isAutoRestart; - bool continuousTimeSync; - QSerialPort *serial; - QSerialPortInfo *currentPort; - CANFrameModel *canModel; - QTimer *ticker; - QMutex sendBulkMutex; - int framesRapid; - int targetID; - STATE rx_state; - int rx_step; - CANFrame *buildFrame; - int can0Baud, can1Baud; - bool can0Enabled, can1Enabled; - int deviceBuildNum; - int deviceSingleWireMode; - uint64_t txTimestampBasis; - uint32_t buildTimeBasis; - - void procRXChar(unsigned char); - void sendCommValidation(); -}; - -#endif // SERIALTHREAD_H diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 00000000..26abd343 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,21 @@ +#include + +#include "tst_lfqueue.h" +#include "tst_cancon.h" + + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + int status = 0; + auto ASSERT_TEST = [&status, argc, argv](QObject* obj) { + status |= QTest::qExec(obj, argc, argv); + delete obj; + }; + + ASSERT_TEST(new TestLFQueue()); + ASSERT_TEST(new TestCanCon(CANCon::SOCKETCAN, "vcan0", 1)); + + return status; +} diff --git a/test/test.pro b/test/test.pro new file mode 100644 index 00000000..40c53f2b --- /dev/null +++ b/test/test.pro @@ -0,0 +1,33 @@ +QT += core gui serialbus widgets testlib serialbus + + +CONFIG += c++11 + +INCLUDEPATH += ../ ../connections + +SOURCES += \ + tst_lfqueue.cpp \ + main.cpp \ + tst_cancon.cpp \ + ../connections/canconfactory.cpp \ + ../connections/canconnection.cpp \ + ../connections/gvretserial.cpp \ + ../connections/socketcan.cpp \ + ../canbus.cpp + + +#HEADERS += \ +# ../utils/lfqueue.h + +target.path= . +INSTALLS += target + +HEADERS += \ + tst_lfqueue.h \ + tst_cancon.h \ + ../connections/canconconst.h \ + ../connections/canconfactory.h \ + ../connections/canconnection.h \ + ../connections/gvretserial.h \ + ../connections/socketcan.h \ + ../canbus.h diff --git a/test/tst_cancon.cpp b/test/tst_cancon.cpp new file mode 100644 index 00000000..eaf1eac7 --- /dev/null +++ b/test/tst_cancon.cpp @@ -0,0 +1,366 @@ +#include +#include + +#include "tst_cancon.h" +#include "canconnection.h" +#include "canconfactory.h" + + +#define QVERIFYB(statement) \ +do {\ + if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\ + return false;\ +} while (0) + +#define QCOMPAREB(actual, expected) \ +do {\ + if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ + return false;\ +} while (0) + +Q_DECLARE_METATYPE(QVector); + + + +TestCanCon::TestCanCon(CANCon::type pType, QString pPortName, int pNbBus): + mType(pType), + mPortName(pPortName), + mNbBus(pNbBus){} + +void TestCanCon::create() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + /* try to get an element from the queue */ + QVERIFY(conn_p->getQueue().get()); + + if(conn_p) + delete conn_p; +} + +void TestCanCon::connectToDevice() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + QSignalSpy spy(conn_p, SIGNAL(status(CANCon::status))); + + /* start connection */ + conn_p->start(); + + /* wait for a signal */ + for(int i=0 ; (spy.count() != 1) && (i < 10) ; i++) + QTest::qWait(500); + + + QCOMPARE(spy.count(), 1); // make sure the signal was emitted exactly one time + QList arguments = spy.takeFirst(); // take the first signal + + QVERIFY(arguments.at(0).toInt() == CANCon::CONNECTED); // verify the first argument + + /* stop connection */ + conn_p->stop(); + delete conn_p; +} + +void TestCanCon::recvFrames() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + int i; + for(i=0 ; queue.peek() && i<1000 ; i++) + { + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + queue.dequeue(); + } + + QVERIFY(i>0); + + /* stop connection */ + conn_p->stop(); + delete conn_p; +} + + +void TestCanCon::suspend() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + conn_p->suspend(true); + + /* the queue should be flushed */ + canf_p = queue.peek(); + QVERIFY(!canf_p); + + /* restart capture */ + conn_p->suspend(false); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + /* get a frame */ + canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + /* stop connection */ + conn_p->stop(); + delete conn_p; +} + + +void TestCanCon::filter_data() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + /* find 3 different ids */ + QVector ids; + + while( queue.peek() && ids.count()!=3 ) + { + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + if(!ids.contains(canf_p->ID)) + ids.append(canf_p->ID); + + queue.dequeue(); + } + + QCOMPARE(ids.count(), 3); + + /* stop connection */ + conn_p->stop(); + delete conn_p; + + /* prepare test vector */ + + QTest::addColumn>("filters"); + QTest::addColumn("filterOut"); + QTest::addColumn("signalReceived"); + QTest::addColumn>("filtered"); + + QVector filters; + QVector filteredIds; + + /* one filter no signal*/ + filters.clear(); + filteredIds.clear(); + filters.append({ids[0], 0xFFFF, false}); + filteredIds.append(ids[0]); + QTest::newRow("1filternosignal") << filters << false << false << filteredIds; + + /* one filter & signal*/ + filters.clear(); + filteredIds.clear(); + filters.append({ids[0], 0xFFFF, true}); + filteredIds.append(ids[0]); + QTest::newRow("1filtersignal") << filters << false << true << filteredIds; + + /* 3 filters */ + filters.clear(); + filteredIds.clear(); + foreach(quint32 id, ids) { + filters.append({id, 0xFFFF, false}); + filteredIds.append(id); + } + QTest::newRow("3filters") << filters << false << false << filteredIds; +} + + +void TestCanCon::filter() +{ + QFETCH(QVector, filters); + QFETCH(bool, filterOut); + QFETCH(bool, signalReceived); + QFETCH(QVector, filtered); + + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* set filters */ + for(int i=0 ; igetNumBuses() ; i++) + QVERIFY(conn_p->setFilters(i, filters, filterOut)); + + /* spy signal */ + QSignalSpy spy(conn_p, SIGNAL(notify())); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + if(signalReceived) + QVERIFY(spy.count()>0); + + int i; + for(i=0 ; queue.peek() && i<1000 ; i++) + { + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + if(filterOut) + QVERIFY(filtered.contains(canf_p->ID)); + + queue.dequeue(); + } + + QVERIFY(i>0); + + conn_p->stop(); + delete conn_p; +} + + +void TestCanCon::write() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + QList frames; + /* build frames */ + CANFrame frame; + frame.bus = 0; + frame.ID = 0x1DE; + frame.data[0] = 0xDE; + frame.data[1] = 0xAD; + frame.data[2] = 0xC0; + frame.data[3] = 0xDE; + frame.len = 4; + + frames.append(frame); + + frame.data[2] = 0xBE; + frame.data[3] = 0xEF; + frames.append(frame); + + frame.data[2] = 0xDE; + frame.data[3] = 0xAD; + + + /* bad frame length */ + unsigned int oldVal = frame.len; + frame.len = 9; + QCOMPARE(conn_p->sendFrame(frame), false); + frame.len = oldVal; + + /* bad bus id */ + oldVal = frame.bus; + frame.bus = 48; + QCOMPARE(conn_p->sendFrame(frame), false); + frame.bus = oldVal; + + qDebug() << "Sending DE AD DE AD"; + /* send */ + QVERIFY(conn_p->sendFrame(frame)); + + /* leave some time for the frame to be sent */ + QTest::qWait(1000); + + qDebug() << "Sending DE AD C0 DE"; + qDebug() << "Sending DE AD BE EF"; + /* send */ + QVERIFY(conn_p->sendFrames(frames)); + + /* leave some time for the frame to be sent */ + QTest::qWait(1000); + + conn_p->stop(); + delete conn_p; +} + + +/*********************************************************/ + +bool TestCanCon::pCreate(CANConnection*& pConn_p) +{ + pConn_p = CanConFactory::create(mType, mPortName); + QVERIFYB(pConn_p); + + QCOMPAREB(pConn_p->getPort(), mPortName); + QCOMPAREB(pConn_p->getNumBuses(), mNbBus); + QCOMPAREB(pConn_p->getType(), mType); + QCOMPAREB(pConn_p->getStatus(), CANCon::NOT_CONNECTED); + + return true; +} + +bool TestCanCon::pConfig(CANConnection* pConn_p) +{ + /*configure buses */ + CANBus bus; + CANBus retBus; + for(int i=0 ; igetNumBuses() ; i++) + { + /* TODO: fix configuration */ + bus.active = true; + pConn_p->setBusSettings(i, bus); + QVERIFYB(pConn_p->getBusSettings(i, retBus)); + QCOMPAREB(bus, retBus); + } + + return true; +} + +bool TestCanCon::pValidateFrame(CANConnection* pConn_p, CANFrame* pCan_p) +{ + QVERIFYB( pCan_p ); + QVERIFYB( (0<=pCan_p->bus) && (pCan_p->bus <= pConn_p->getNumBuses()) ); + QVERIFYB( pCan_p->isReceived); + QVERIFYB( pCan_p->len<=8 ); + QVERIFYB( (0<=pCan_p->ID) && (pCan_p->ID<2048) ); + + return true; +} diff --git a/test/tst_cancon.h b/test/tst_cancon.h new file mode 100644 index 00000000..2d79bd49 --- /dev/null +++ b/test/tst_cancon.h @@ -0,0 +1,33 @@ +#ifndef TESTCANCON_H +#define TESTCANCON_H + +#include +#include "canconconst.h" +#include "canconnection.h" + +class TestCanCon: public QObject +{ + Q_OBJECT +public: + TestCanCon(CANCon::type, QString pPortName, int pNbBus); +private: + CANCon::type mType; + QString mPortName; + int mNbBus; + +private slots: + void create(); + void connectToDevice(); + void recvFrames(); + void suspend(); + void filter(); + void filter_data(); + void write(); + +private: + bool pCreate(CANConnection*& pConn_p); + bool pConfig(CANConnection* pConn_p); + bool pValidateFrame(CANConnection* pConn_p, CANFrame* pCan_p); +}; + +#endif // TESTCANCON_H diff --git a/test/tst_lfqueue.cpp b/test/tst_lfqueue.cpp new file mode 100644 index 00000000..4343f474 --- /dev/null +++ b/test/tst_lfqueue.cpp @@ -0,0 +1,85 @@ +#include + +#include + +#include "utils/lfqueue.h" +#include "tst_lfqueue.h" + + + +void TestLFQueue::setSize_data() +{ + QTest::addColumn("size"); + QTest::addColumn("result"); + + QTest::newRow("-1") << -1 << false; + QTest::newRow("0") << 0 << true; + QTest::newRow("10") << 10 << true; + QTest::newRow("2000") << 20000 << true; + +} + + +void TestLFQueue::setSize() +{ + QFETCH(int, size); + QFETCH(bool, result); + + LFQueue queue; + QCOMPARE(queue.setSize(size), result); +} + + +void readerThread(LFQueue* pQueue_p, int pSize, bool pSleep) { + int* val_p; + + for(int i=0; ipeek()) ); + QVERIFY(val_p); + + QCOMPARE(*val_p, i); + pQueue_p->dequeue(); + + if(pSleep) + QThread::msleep(1); + } +} + + +void TestLFQueue::exchange_data() +{ + QTest::addColumn("size"); + QTest::addColumn("writerSleep"); + QTest::addColumn("readerSleep"); + + QTest::newRow("nosleep") << 1000 << false << false; + QTest::newRow("readersleep") << 1000 << false << true; + QTest::newRow("writersleep") << 1000 << true << false; +} + + +void TestLFQueue::exchange() +{ + LFQueue queue; + QFETCH(int, size); + QFETCH(bool, writerSleep); + QFETCH(bool, readerSleep); + + int* val_p; + QCOMPARE(queue.setSize(2), true); + + QFuture thread = QtConcurrent::run(readerThread, &queue, size, readerSleep); + + for(int i=0; i + +class TestLFQueue: public QObject +{ + Q_OBJECT +private: + +private slots: + void setSize_data(); + void setSize(); + void exchange_data(); + void exchange(); +}; + +#endif // TST_LFQUEUE_H diff --git a/ui/bisectwindow.ui b/ui/bisectwindow.ui new file mode 100644 index 00000000..439386ba --- /dev/null +++ b/ui/bisectwindow.ui @@ -0,0 +1,223 @@ + + + BisectWindow + + + + 0 + 0 + 692 + 319 + + + + Bisector Window + + + + + + Splitting Strategy: + + + Qt::AlignCenter + + + + + + + + ID Range + + + + + + + + + + TO + + + Qt::AlignCenter + + + + + + + + + + + + + + Frame Number + + + true + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + Percentage + + + + + + + 1 + + + 10000 + + + 10 + + + 100 + + + Qt::Horizontal + + + + + + + + + + + + + + + Save Which Side: + + + Qt::AlignCenter + + + + + + Lower Section + + + true + + + + + + + Upper Section + + + + + + + + + + + + + 12 + + + + Number of Frames in Main List: + + + + + + + + 14 + + + + 0 + + + + + + + + 12 + + + + Saved Frames after split: + + + + + + + + 14 + + + + 0 + + + + + + + + + + + Calculate Split + + + + + + + Save split frames to a new file + + + + + + + Replace main list with split frames + + + + + + + + + + diff --git a/candatagrid.ui b/ui/candatagrid.ui similarity index 100% rename from candatagrid.ui rename to ui/candatagrid.ui diff --git a/ui/connectionwindow.ui b/ui/connectionwindow.ui new file mode 100644 index 00000000..5e7ffc43 --- /dev/null +++ b/ui/connectionwindow.ui @@ -0,0 +1,268 @@ + + + ConnectionWindow + + + + 0 + 0 + 956 + 527 + + + + Connection Settings + + + + + + + + Connections: + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + + + + + + New Connection + + + + + + + Remove Selected Connection + + + + + + + + + + + Activate All Connections + + + + + + + Deactivate All Connections + + + + + + + + + + + + + Connection Type + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + GVRET Serial + + + true + + + + + + + false + + + Kvaser + + + + + + + false + + + SocketCAN + + + + + + + + + + + 0 + 0 + + + + Port: + + + + + + + + 0 + 0 + + + + + 0 + 22 + + + + Qt::LeftToRight + + + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + + + + + 0 + 0 + + + + + 341 + 16777215 + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + Single Wire Mode + + + + + + + Listen Only Mode + + + + + + + Enabled + + + + + + + + + CAN Speed + + + + + + + + + + + + + + Create New Connection + + + + + + + Revert + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/dbcloadsavewindow.ui b/ui/dbcloadsavewindow.ui similarity index 100% rename from dbcloadsavewindow.ui rename to ui/dbcloadsavewindow.ui diff --git a/dbcmaineditor.ui b/ui/dbcmaineditor.ui similarity index 100% rename from dbcmaineditor.ui rename to ui/dbcmaineditor.ui diff --git a/dbcsignaleditor.ui b/ui/dbcsignaleditor.ui similarity index 100% rename from dbcsignaleditor.ui rename to ui/dbcsignaleditor.ui diff --git a/discretestatewindow.ui b/ui/discretestatewindow.ui similarity index 100% rename from discretestatewindow.ui rename to ui/discretestatewindow.ui diff --git a/filecomparatorwindow.ui b/ui/filecomparatorwindow.ui similarity index 100% rename from filecomparatorwindow.ui rename to ui/filecomparatorwindow.ui diff --git a/firmwareuploaderwindow.ui b/ui/firmwareuploaderwindow.ui similarity index 98% rename from firmwareuploaderwindow.ui rename to ui/firmwareuploaderwindow.ui index c49903a6..27a4983a 100644 --- a/firmwareuploaderwindow.ui +++ b/ui/firmwareuploaderwindow.ui @@ -11,7 +11,7 @@ - Dialog + Firmware Updater diff --git a/flowviewwindow.ui b/ui/flowviewwindow.ui similarity index 100% rename from flowviewwindow.ui rename to ui/flowviewwindow.ui diff --git a/frameinfowindow.ui b/ui/frameinfowindow.ui similarity index 100% rename from frameinfowindow.ui rename to ui/frameinfowindow.ui diff --git a/frameplaybackwindow.ui b/ui/frameplaybackwindow.ui similarity index 100% rename from frameplaybackwindow.ui rename to ui/frameplaybackwindow.ui diff --git a/framesenderwindow.ui b/ui/framesenderwindow.ui similarity index 100% rename from framesenderwindow.ui rename to ui/framesenderwindow.ui diff --git a/fuzzingwindow.ui b/ui/fuzzingwindow.ui similarity index 100% rename from fuzzingwindow.ui rename to ui/fuzzingwindow.ui diff --git a/graphingwindow.ui b/ui/graphingwindow.ui similarity index 100% rename from graphingwindow.ui rename to ui/graphingwindow.ui diff --git a/isotp_interpreterwindow.ui b/ui/isotp_interpreterwindow.ui similarity index 100% rename from isotp_interpreterwindow.ui rename to ui/isotp_interpreterwindow.ui diff --git a/mainsettingsdialog.ui b/ui/mainsettingsdialog.ui similarity index 100% rename from mainsettingsdialog.ui rename to ui/mainsettingsdialog.ui diff --git a/mainwindow.ui b/ui/mainwindow.ui similarity index 96% rename from mainwindow.ui rename to ui/mainwindow.ui index 64946bc1..a0c47ee0 100644 --- a/mainwindow.ui +++ b/ui/mainwindow.ui @@ -103,6 +103,9 @@ Suspend Capturing + + false + @@ -197,7 +200,7 @@ 0 0 800 - 27 + 19 @@ -211,6 +214,8 @@ + + @@ -247,7 +252,6 @@ Connection - @@ -352,7 +356,7 @@ - Set Port + Open Connection WIndow @@ -395,6 +399,11 @@ ISO-TP Decoder + + + Sniffer + + Firmware Update @@ -405,6 +414,11 @@ MotorControlConfig + + + Capture Bisector + + diff --git a/motorcontrollerconfigwindow.ui b/ui/motorcontrollerconfigwindow.ui similarity index 100% rename from motorcontrollerconfigwindow.ui rename to ui/motorcontrollerconfigwindow.ui diff --git a/newgraphdialog.ui b/ui/newgraphdialog.ui similarity index 100% rename from newgraphdialog.ui rename to ui/newgraphdialog.ui diff --git a/rangestatewindow.ui b/ui/rangestatewindow.ui similarity index 100% rename from rangestatewindow.ui rename to ui/rangestatewindow.ui diff --git a/scriptingwindow.ui b/ui/scriptingwindow.ui similarity index 100% rename from scriptingwindow.ui rename to ui/scriptingwindow.ui diff --git a/ui/snifferwindow.ui b/ui/snifferwindow.ui new file mode 100644 index 00000000..44d36a03 --- /dev/null +++ b/ui/snifferwindow.ui @@ -0,0 +1,188 @@ + + + snifferWindow + + + + 0 + 0 + 602 + 752 + + + + Sniffer + + + + QLayout::SetDefaultConstraint + + + + + QAbstractItemView::NoSelection + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Notch + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Unnotch + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Filters: + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 75 + 16777215 + + + + All + + + + + + + + 75 + 16777215 + + + + None + + + + + + + + + + + + + + + + + diff --git a/udsscanwindow.ui b/ui/udsscanwindow.ui similarity index 100% rename from udsscanwindow.ui rename to ui/udsscanwindow.ui diff --git a/utility.h b/utility.h index d5614e89..e2792add 100644 --- a/utility.h +++ b/utility.h @@ -23,7 +23,7 @@ class Utility if (input.length() < 3) temp = 0; else temp = input.right(input.size() - 2).toLongLong(NULL, 16); } - else if (input.startsWith("B")) //binary number + else if (input.startsWith("0B") || input.startsWith("B")) //binary number { input = input.right(input.size() - 1); //remove the B for (int i = 0; i < input.length(); i++) @@ -44,6 +44,17 @@ class Utility return ParseStringToNum(input.toUtf8()); } + static uint ParseStringToNum2(QString pInput, bool* pOk_p = NULL) + { + if(pInput.startsWith("0b")) + { + pInput.remove(0, 2); + return pInput.toUInt(pOk_p, 2); + } + + return pInput.toUInt(pOk_p, 0); + } + static long GetTimeMS() { QDateTime stamp = QDateTime::currentDateTime(); diff --git a/utils/lfqueue.h b/utils/lfqueue.h new file mode 100644 index 00000000..8a7d6d0b --- /dev/null +++ b/utils/lfqueue.h @@ -0,0 +1,91 @@ +#ifndef LFQUEUE_H +#define LFQUEUE_H + +#include +#include + + +/* macros */ +#define IS_EMPTY() ( mWIdx.load() == mRIdx.load() ) +#define IS_FULL() ( (mWIdx.load()+1)%mSize == mRIdx.load() ) + + +template +class LFQueue +{ +public: + LFQueue() : mSize(0), mArray(NULL){} + + ~LFQueue() {setSize(0);} + + bool setSize(int size) { + if(size<0) + return false; + + if(mArray) { + delete[] mArray; + mArray = NULL; + } + + if(size>0) { + mArray = new T[size]; + if(mArray) + mSize = size; + return ( mArray!=NULL ); + } + + return true; + } + + void flush() { + mRIdx.store(0); + mWIdx.store(0); + } + + T* get() { + if(IS_FULL()) + return NULL; + + return &(mArray[mWIdx.loadAcquire()]); /* prevent memory reordering (belt and braces) */ + } + + + void queue() { + #ifdef QT_DEBUG + if(IS_FULL()) + qCritical() << "BUG: queueing in full queue"; + #endif + + int wIdx = mWIdx.load(); + mWIdx.storeRelease((wIdx+1)%mSize); + } + + + T* peek() { + if(IS_EMPTY()) + return NULL; + + return &(mArray[mRIdx.loadAcquire()]); /* prevent memory reordering (belt and braces) */ + } + + + void dequeue() { + #ifdef QT_DEBUG + if(IS_EMPTY()) + qCritical() << "BUG: dequeueing an empty queue"; + #endif + + int rIdx = mRIdx.load(); + mRIdx.storeRelease((rIdx+1)%mSize); + } + + +private: + int mSize; + T* mArray; + + QAtomicInt mRIdx; + QAtomicInt mWIdx; +}; + +#endif // LFQUEUE_H