Merge pull request #67 from collin80/WIP2

Merge WIP2 changes into Master
This commit is contained in:
Collin Kidder
2017-01-02 17:55:45 -05:00
committed by GitHub
115 changed files with 5475 additions and 1412 deletions
+14 -8
View File
@@ -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
+86 -63
View File
@@ -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 +=
+154
View File
@@ -0,0 +1,154 @@
#include "bisectwindow.h"
#include "ui_bisectwindow.h"
#include "mainwindow.h"
#include "framefileio.h"
#include <QDebug>
#include <algorithm>
BisectWindow::BisectWindow(const QVector<CANFrame> *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));
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef BISECTWINDOW_H
#define BISECTWINDOW_H
#include <QDialog>
#include "can_structs.h"
namespace Ui {
class BisectWindow;
}
class BisectWindow : public QDialog
{
Q_OBJECT
public:
explicit BisectWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
~BisectWindow();
void showEvent(QShowEvent*);
signals:
void sendCANFrame(const CANFrame *, int);
void sendFrameBatch(const QList<CANFrame> *);
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<CANFrame> *modelFrames;
QVector<CANFrame> splitFrames;
QList<int> foundID;
void refreshIDList();
void refreshFrameNumbers();
};
#endif // BISECTWINDOW_H
+21 -5
View File
@@ -1,21 +1,37 @@
#ifndef CAN_STRUCTS_H
#define CAN_STRUCTS_H
#include <QObject>
#include <QVector>
#include <stdint.h>
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 @@ public:
struct ISOTP_MESSAGE
{
public:
int ID;
uint32_t ID;
int bus;
bool extended;
bool isReceived;
+1 -1
View File
@@ -10,7 +10,7 @@ public:
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;
+39 -35
View File
@@ -3,6 +3,15 @@
#include <QFile>
#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<CANFrame>& 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<CANFrame> &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;
+10 -5
View File
@@ -7,7 +7,8 @@
#include <QDebug>
#include <QMutex>
#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 @@ public:
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 @@ public:
void recalcOverwrite();
bool needsFilterRefresh();
void insertFrames(const QVector<CANFrame> &newFrames);
int getIndexFromTimeID(int ID, double timestamp);
int getIndexFromTimeID(unsigned int ID, double timestamp);
const QVector<CANFrame> *getListReference() const; //thou shalt not modify these frames externally!
const QVector<CANFrame> *getFilteredListReference() const; //Thus saith the Lord, NO.
const QMap<int, bool> *getFiltersReference() const; //this neither
public slots:
void addFrame(const CANFrame&, bool);
void addFrames(const CANConnection*, const QVector<CANFrame>&);
signals:
void updatedFiltersList();
+2 -2
View File
@@ -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
+76
View File
@@ -0,0 +1,76 @@
#include <QObject>
#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;
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef CANBus_H
#define CANBus_H
#include <QDataStream>
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
+24
View File
@@ -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
+19
View File
@@ -0,0 +1,19 @@
#include <QString>
#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;
}
+13
View File
@@ -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
+234
View File
@@ -0,0 +1,234 @@
#include <QDateTime>
#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<CANConnection*>& 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<CANFrame> 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<CANFrame>& 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;
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef CANCONMANAGER_H
#define CANCONMANAGER_H
#include <QObject>
#include <QTimer>
#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<CANConnection*>& 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<CANFrame>& 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<CANFrame>& pFrames);
void connectionStatusUpdated(int conns);
private slots:
void refreshCanList();
private:
explicit CANConManager(QObject *parent = 0);
void refreshConnection(CANConnection* pConn_p);
static CANConManager* mInstance;
QList<CANConnection*> mConns;
QTimer mTimer;
uint64_t mTimestampBasis;
};
#endif // CANCONNECTIONMODEL_H
+363
View File
@@ -0,0 +1,363 @@
#include <QThread>
#include "canconnection.h"
struct BusData {
CANBus mBus;
bool mConfigured;
QVector<CANFlt> 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>("CANBus");
qRegisterMetaType<CANFrame>("CANFrame");
qRegisterMetaType<CANCon::status>("CANCon::status");
qRegisterMetaType<CANFlt>("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 ; i<mNumBuses ; i++) {
mBusData_p[i].mConfigured = false;
}
/* if needed, create a thread and move ourself into it */
if(pUseThread) {
mThread_p = new QThread();
}
}
CANConnection::~CANConnection()
{
/* stop and delete thread */
if(mThread_p) {
mThread_p->quit();
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<CANFrame>& 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<CANFrame>&, 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<CANFrame>& 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<CANFrame>& pFrames)
{
foreach(const CANFrame& frame, pFrames)
{
if(!piSendFrame(frame))
return false;
}
return true;
}
+296
View File
@@ -0,0 +1,296 @@
#ifndef CANCONNECTION_H
#define CANCONNECTION_H
#include <Qt>
#include <QObject>
#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<CANFrame>& 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<CANFrame>& 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<CANFrame>&);
private:
LFQueue<CANFrame> 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
+190
View File
@@ -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<CANConnection*>& 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<CANConnection*>& 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<int>(Qt::DisplayRole));
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef CANCONNECTIONMODEL_H
#define CANCONNECTIONMODEL_H
#include <QAbstractTableModel>
#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
+512
View File
@@ -0,0 +1,512 @@
#include <QCanBus>
#include <QThread>
#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>("CANBus");
qRegisterMetaType<const CANFrame *>("const CANFrame *");
qRegisterMetaType<const QList<CANFrame> *>("const QList<CANFrame> *");
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<CANConnection*>& 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<CANConnection*>& conns = CANConManager::getInstance()->getConnections();
foreach(CANConnection* conn_p, conns)
conn_p->suspend(pSuspend);
connModel->refresh();
}
void ConnectionWindow::setActiveAll(bool pActive)
{
CANBus bus;
QList<CANConnection*>& conns = CANConManager::getInstance()->getConnections();
foreach(CANConnection* conn_p, conns)
{
for(int i=0 ; i<conn_p->getNumBuses() ; 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 ; i<conn_p->getNumBuses() ; 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 &current, 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<QVector<QString>>();
qRegisterMetaTypeStreamOperators<QVector<int>>();
qRegisterMetaTypeStreamOperators<CANBus>();
qRegisterMetaTypeStreamOperators<QList<CANBus>>();
QSettings settings;
/* fill connection list */
QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>();
QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>();
QList<CANBus> busses = settings.value("connections/busses").value<QList<CANBus>>();
for(int i=0 ; i<portNames.count() ; i++)
{
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i]);
if(conn_p)
{
for(int j=0 ; j<conn_p->getNumBuses() ; 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<CANConnection*>& conns = CANConManager::getInstance()->getConnections();
QSettings settings;
QVector<QString> portNames;
QVector<int> devTypes;
QList<CANBus> busses;
/* save connections */
foreach(CANConnection* conn_p, conns)
{
portNames.append(conn_p->getPort());
devTypes.append(conn_p->getType());
for(int i=0 ; i<conn_p->getNumBuses() ; 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));
}
+76
View File
@@ -0,0 +1,76 @@
#ifndef CONNECTIONWINDOW_H
#define CONNECTIONWINDOW_H
#include <QSerialPortInfo>
#include <QDialog>
#include <QDebug>
#include <QSettings>
#include <QTimer>
#include <QItemSelection>
#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 &current, const QModelIndex &previous);
void handleRemoveConn();
void handleEnableAll();
void handleDisableAll();
void handleRevert();
void handleNewConn();
void connectionStatus(CANCon::status);
private:
Ui::ConnectionWindow *ui;
QList<QSerialPortInfo> 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
+314 -208
View File
@@ -1,56 +1,190 @@
#include "serialworker.h"
#include <QSerialPort>
#include <QObject>
#include <QDebug>
#include <QTimer>
#include <QCanBusFrame>
#include <QSerialPortInfo>
#include <QSettings>
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;
}
serial->disconnect(); //disconnect all signals
delete serial;
else can0Enabled = false;
if (bus.isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
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()
{
//one second after trying to connect are we actually connected?
if (!connected) //no?
void GVRetSerial::disconnectDevice() {
if (serial != NULL)
{
//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();
if (serial->isOpen())
{
serial->clear();
serial->close();
}
serial->disconnect(); //disconnect all signals
delete serial;
serial = NULL;
}
}
void SerialWorker::readSerialData()
void GVRetSerial::connectionTimeout()
{
//one second after trying to connect are we actually connected?
//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";
disconnectDevice();
}
}
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<CANFrame> *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;
if (connected)
/*
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;
}
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;
}
+93
View File
@@ -0,0 +1,93 @@
#ifndef GVRETSERIAL_H
#define GVRETSERIAL_H
#include <QSerialPort>
#include <QCanBusDevice>
#include <QThread>
#include <QTimer>
/*************/
#include <QDateTime>
/*************/
#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
+240
View File
@@ -0,0 +1,240 @@
#include <QObject>
#include <QDebug>
#include <QCanBusFrame>
#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;
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef SocketCan_H
#define SocketCan_H
#include <QObject>
#include <QCanBus>
#include <QTimer>
#include <qthread.h>
#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
-247
View File
@@ -1,247 +0,0 @@
#include "connectionwindow.h"
#include "ui_connectionwindow.h"
#include <QtNetwork/QNetworkInterface>
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("<Default>"));
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("<Default>"));
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<QNetworkInterface> 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;
}
-62
View File
@@ -1,62 +0,0 @@
#ifndef CONNECTIONWINDOW_H
#define CONNECTIONWINDOW_H
#include <QSerialPortInfo>
#include <QDialog>
#include <QDebug>
#include <QSettings>
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<QSerialPortInfo> ports;
QSettings *settings;
ConnectionType::ConnectionType currentConnType;
QString currentPortName;
int currentSpeed1, currentSpeed2;
void getSerialPorts();
void getKvaserPorts();
void getSocketcanPorts();
};
#endif // CONNECTIONWINDOW_H
-117
View File
@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConnectionWindow</class>
<widget class="QWidget" name="ConnectionWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>335</width>
<height>235</height>
</rect>
</property>
<property name="windowTitle">
<string>Connection Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Connection Type</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="rbGVRET">
<property name="text">
<string>GVRET Serial</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbKvaser">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Kvaser</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbSocketCAN">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>SocketCAN</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbPort"/>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>CAN0 Speed</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>CAN1 Speed</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="cbSpeed0"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cbSpeed1"/>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="ckSingleWire">
<property name="text">
<string>Set CAN1 to Single Wire Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnOK">
<property name="text">
<string>Update Settings</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
View File
+7 -5
View File
@@ -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;
+2 -2
View File
@@ -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();
@@ -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();
}
+96 -104
View File
@@ -5,6 +5,8 @@
#include <QMessageBox>
#include <QSettings>
#define MT_COLUMN_COUNT 5
DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
ui(new Ui::DBCMainEditor)
@@ -26,7 +28,7 @@ DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector<CANFrame> *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)
{
QTableWidgetItem* item = NULL;
bool ret = false;
DBC_MESSAGE *msg = NULL;
uint msgID;
if (inhibitCellChanged) return;
qDebug() << "Editing row: " << row << " col: " << col;
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 ; i<MT_COLUMN_COUNT ; i++)
{
QMessageBox msg;
msg.setParent(0);
msg.setText("An existing msg with that name already exists! Aborting!");
msg.exec();
item = ui->MessagesTable->item(row, i);
item->setFlags(item->flags() | Qt::ItemIsEditable);
}
/* set length */
item = ui->MessagesTable->item(row, 2);
item->setText(QString::number(newMsg.len));
inhibitCellChanged = false;
/* insert a new row */
insertBlankRow();
break;
}
case 1: //msg name
{
QString msgName = ui->MessagesTable->item(row, 1)->text().simplified().replace(' ', '_');
if (msgName.length() == 0) return;
if( ret && (msg!=NULL) )
msg->name = msgName;
break;
}
case 2: //data length
{
bool parseOk = false;
uint msgLen = ui->MessagesTable->item(row, col)->text().toUInt(&parseOk);
/* sanity checks */
if(!parseOk)
{
ui->MessagesTable->item(row, col)->setText("");
return;
}
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;
if (msgLen > 8)
{
msgLen = 8;
ui->MessagesTable->item(row, col)->setText(QString::number(msgLen));
}
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);
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->len = msgLen;
QString msgComment = ui->MessagesTable->item(row, col)->text().simplified();
if( ret && (msgComment!=NULL) )
msg->comment = msgComment;
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
{
DBC_MESSAGE newMsg;
newMsg.ID = -1;
newMsg.name = "";
newMsg.len = 0;
newMsg.comment = msgComment;
newMsg.sender = node;
dbcFile->messageHandler->addMessage(newMsg);
}
else //editing an existing record
{
if (msg != NULL) msg->comment = msgComment;
}
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 ; i<MT_COLUMN_COUNT ; i++)
{
QTableWidgetItem *item = new QTableWidgetItem("");
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
ui->MessagesTable->setItem(rowIdx, i, item);
}
}
+1
View File
@@ -46,6 +46,7 @@ private:
void closeEvent(QCloseEvent *event);
void readSettings();
void writeSettings();
void insertBlankRow();
};
@@ -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));
-24
View File
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeltaWindow</class>
<widget class="QDialog" name="DeltaWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>978</width>
<height>654</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="tableView"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+17 -13
View File
@@ -25,7 +25,7 @@ FirmwareUploaderWindow::FirmwareUploaderWindow(const QVector<CANFrame> *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<CANFrame> *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)")));
+3 -3
View File
@@ -4,8 +4,8 @@
#include <QDialog>
#include <QTimer>
#include "can_structs.h"
#include "connections/canconmanager.h"
#include "utility.h"
#include "serialworker.h"
namespace Ui {
class FirmwareUploaderWindow;
@@ -20,10 +20,10 @@ public:
~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();
+31 -32
View File
@@ -246,6 +246,8 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames
bool FrameFileIO::saveVehicleSpyFile(QString filename, const QVector<CANFrame> *frames)
{
Q_UNUSED(filename);
Q_UNUSED(frames);
return true;
}
@@ -324,7 +326,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* 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<CANFrame>* 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<CANFrame>* frames)
thisFrame.bus = 0;
thisFrame.extended = false;
QList<QByteArray> 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* frames
QList<QByteArray> 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<CANFrame>*
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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<CANFrame>* 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<QByteArray> 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<CANFrame> * 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(' ');
+8 -2
View File
@@ -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<CANFrame>*);
static bool saveFrameFile(QString &, const QVector<CANFrame>*);
//These do the actual loading and saving and can be used directly if you'd prefer
static bool loadCRTDFile(QString, QVector<CANFrame>*);
static bool loadNativeCSVFile(QString, QVector<CANFrame>*);
static bool loadGenericCSVFile(QString, QVector<CANFrame>*);
@@ -40,8 +48,6 @@ public:
static bool saveIXXATFile(QString, const QVector<CANFrame>*);
static bool saveCANDOFile(QString, const QVector<CANFrame>*);
static bool saveVehicleSpyFile(QString, const QVector<CANFrame>*);
static bool loadFrameFile(QString &, QVector<CANFrame>*);
static bool saveFrameFile(QString &, const QVector<CANFrame>*);
static bool loadCanDumpFile(QString, QVector<CANFrame>*);
static bool loadPCANFile(QString, QVector<CANFrame>*);
+24 -29
View File
@@ -4,6 +4,7 @@
#include <QFileDialog>
#include <QMenu>
#include <QSettings>
#include "connections/canconmanager.h"
/*
* Notes about new functionality:
@@ -18,22 +19,21 @@
*
*/
FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, SerialWorker *worker, QWidget *parent) :
FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *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<CANFrame> *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<CANFrame>*)), worker, SLOT(sendFrameBatch(const QList<CANFrame>*)), 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);
}
else if (whichBusSend == (ui->comboCANBus->count() - 2)) //all
{
for (int c = 0; c < ui->comboCANBus->count() - 2; c++)
{
thisFrame->bus = c;
sendingBuffer.append(*thisFrame);
}
}
else //from file so retain original bus and send as-is
{
sendingBuffer.append(*thisFrame);
}
if (whichBusSend & 1)
{
thisFrame->bus = 0;
sendingBuffer.append(*thisFrame);
}
if (whichBusSend & 2)
{
thisFrame->bus = 1;
sendingBuffer.append(*thisFrame);
}
thisFrame->bus = originalBus;
updateFrameLabel();
}
}
+1 -7
View File
@@ -5,7 +5,6 @@
#include <QListWidget>
#include <QTimer>
#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<CANFrame> *frames, SerialWorker *worker, QWidget *parent = 0);
explicit FramePlaybackWindow(const QVector<CANFrame> *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<CANFrame> *);
private:
Ui::FramePlaybackWindow *ui;
QList<int> foundID;
@@ -65,7 +60,6 @@ private:
const QVector<CANFrame> *modelFrames;
int currentPosition;
QTimer *playbackTimer;
SerialWorker *serialWorker;
bool playbackActive;
bool playbackForward;
int whichBusSend;
+8 -8
View File
@@ -5,6 +5,7 @@
#include <QFileDialog>
#include <QDebug>
#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(" ");
-3
View File
@@ -30,9 +30,6 @@ private slots:
void loadGrid();
void updatedFrames(int);
signals:
void sendCANFrame(const CANFrame *, int);
private:
Ui::FrameSenderWindow *ui;
QList<FrameSendData> sendingData;
+96 -192
View File
@@ -4,9 +4,8 @@
#include <QDateTime>
#include <QFileDialog>
#include <QtSerialPort/QSerialPortInfo>
#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);
lbStatusConnected.setText(tr("Not connected"));
connect(CANConManager::getInstance(), &CANConManager::framesReceived, model, &CANFrameModel::addFrames);
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<QSerialPortInfo> 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;
rxFrames = model->sendBulkRefresh();
//if(rxFrames>0)
//{
int elapsed = elapsedTime->elapsed();
if(elapsed) {
framesPerSec = rxFrames * 1000 / elapsed;
elapsedTime->restart();
}
else
framesPerSec = 0;
model->sendBulkRefresh(rxFrames);
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?
}
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?
}
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();
}
emit suspendCapturing(!allowCapture);
}
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;
}
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<CANFrame>*)), worker, SLOT(sendFrameBatch(const QList<CANFrame>*)));
}
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<CANFrame>*)), worker, SLOT(sendFrameBatch(const QList<CANFrame>*)));
//connect(motorctrlConfigWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int)));
//connect(motorctrlConfigWindow, SIGNAL(sendFrameBatch(const QList<CANFrame>*)), worker, SLOT(sendFrameBatch(const QList<CANFrame>*)));
}
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();
}
+23 -29
View File
@@ -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 @@ public:
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 @@ private:
//canbus related data
CANFrameModel *model;
DBCHandler *dbcHandler;
QThread serialWorkerThread;
SerialWorker *worker;
QByteArray inputBuffer;
QTimer updateTimer;
QTime *elapsedTime;
@@ -146,7 +141,9 @@ private:
FuzzingWindow *fuzzingWindow;
UDSScanWindow *udsScanWindow;
ISOTP_InterpreterWindow *isoWindow;
SnifferWindow* snifferWindow;
MotorControllerConfigWindow *motorctrlConfigWindow;
BisectWindow* bisectWindow;
//various private storage
QLabel lbStatusConnected;
@@ -154,9 +151,6 @@ private:
QLabel lbStatusDatabase;
int normalRowHeight;
bool isConnected;
QSerialPortInfo portInfo;
QString connType, portName;
int canSpeed0, canSpeed1;
//private methods
void saveDecodedTextFile(QString);
@@ -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--)
{
@@ -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];
+5 -5
View File
@@ -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);
}
@@ -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();
+17 -13
View File
@@ -3,6 +3,7 @@
#include "utility.h"
#include <QDebug>
#include "mainwindow.h"
#include "connections/canconmanager.h"
FuzzingWindow::FuzzingWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
@@ -36,9 +37,10 @@ FuzzingWindow::FuzzingWindow(const QVector<CANFrame> *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);
}
+1 -1
View File
@@ -29,7 +29,7 @@ public:
~FuzzingWindow();
signals:
void sendCANFrame(const CANFrame *, int);
void sendCANFrame(const CANFrame *);
void sendFrameBatch(const QList<CANFrame> *);
private slots:
+4 -1
View File
@@ -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()
+1 -1
View File
@@ -3,7 +3,7 @@
#include "qcustomplot.h"
#include "can_structs.h"
#include "dbchandler.h"
#include "dbc/dbchandler.h"
#include <QDialog>
+2 -2
View File
@@ -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;
@@ -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;
+1 -1
View File
@@ -3,7 +3,7 @@
#include <QDialog>
#include "graphingwindow.h"
#include "dbchandler.h"
#include "dbc/dbchandler.h"
namespace Ui {
class NewGraphDialog;
@@ -171,7 +171,7 @@ void RangeStateWindow::refreshFilterList()
void RangeStateWindow::recalcButton()
{
QHash<int, bool>::iterator iter;
int id;
uint32_t id;
ui->listCandidates->clear();
foundSignals.clear();
@@ -376,7 +376,7 @@ void RangeStateWindow::createGraph(QVector<int> 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;
+86
View File
@@ -0,0 +1,86 @@
#include <QVariant>
#include <QDebug>
#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<mCurrent.len &&
((uchar*) &mLastMarker.data)[i] &&
!((uchar*) &mNotch)[i] )
{
return ((uchar*) &mCurrent.data)[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;
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef SNIFFERITEM_H
#define SNIFFERITEM_H
#include <QVariant>
#include <QTime>
#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
+267
View File
@@ -0,0 +1,267 @@
#include <QDebug>
#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<quint32, SnifferItem*>& 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<SnifferItem*>(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<quint32, SnifferItem*>& 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<quint32, SnifferItem*>::const_iterator iter;
int i;
for(iter = map.begin(), i=0 ; i<row ; ++i, ++iter);
return createIndex(row, column, iter.value());
}
QModelIndex SnifferModel::parent(const QModelIndex &) const
{
return QModelIndex();
}
void SnifferModel::clear()
{
beginResetModel();
qDeleteAll(mMap);
mMap.clear();
mFilters.clear();
mFilter = false;
endResetModel();
}
void SnifferModel::refresh()
{
QMap<quint32, SnifferItem*>::iterator i;
QVector<quint32> 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<int>(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<CANFrame>& 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<quint32, SnifferItem*>& map = mFilter ? mFilters : mMap;
foreach(SnifferItem* item, map)
item->notch(true);
}
void SnifferModel::unNotch()
{
QMap<quint32, SnifferItem*>& map = mFilter ? mFilters : mMap;
foreach(SnifferItem* item, map)
item->notch(false);
}
+58
View File
@@ -0,0 +1,58 @@
#ifndef SNIFFERMODEL_H
#define SNIFFERMODEL_H
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include <QTimer>
#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<CANFrame>&);
void notch();
void unNotch();
signals:
void idChange(int, bool);
private:
QMap<quint32, SnifferItem*> mMap;
QMap<quint32, SnifferItem*> mFilters;
bool mFilter;
};
#endif // SNIFFERMODEL_H
+132
View File
@@ -0,0 +1,132 @@
#include <QDebug>
#include <QListWidgetItem>
#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;
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef SNIFFER_H
#define SNIFFER_H
#include <QDialog>
#include <QListWidgetItem>
#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<int, QListWidgetItem*> mMap;
bool mFilter;
};
#endif // SNIFFER_H
+25 -19
View File
@@ -1,6 +1,7 @@
#include "udsscanwindow.h"
#include "ui_udsscanwindow.h"
#include "mainwindow.h"
#include "connections/canconmanager.h"
UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
@@ -20,10 +21,9 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *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
-3
View File
@@ -17,9 +17,6 @@ public:
explicit UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
~UDSScanWindow();
signals:
void sendCANFrame(const CANFrame *, int);
private slots:
void updatedFrames(int numFrames);
void rapidFrames(int numFrames);
+36 -15
View File
@@ -1,14 +1,12 @@
#include "scriptcontainer.h"
#include <QJSValueIterator>
#include <QDebug>
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 ; i<conn_p->getNumBuses() ; 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
+2 -4
View File
@@ -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;
+27 -21
View File
@@ -3,9 +3,10 @@
#include <QFile>
#include <QFileDialog>
#include <QSettings>
#include <Qsci/qscilexerjavascript.h>
#include "mainwindow.h"
#include "connections/canconmanager.h"
ScriptingWindow::ScriptingWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
@@ -23,7 +24,8 @@ ScriptingWindow::ScriptingWindow(const QVector<CANFrame> *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<CANFrame>& 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<CANConnection*> 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<CANConnection*> 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;
+2 -8
View File
@@ -3,6 +3,7 @@
#include "can_structs.h"
#include "scriptcontainer.h"
#include "connections/canconnection.h"
#include <QDialog>
#include <QJSEngine>
@@ -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<CANFrame>&);
private:
void closeEvent(QCloseEvent *event);
@@ -44,8 +40,6 @@ private:
QList<ScriptContainer *> scripts;
ScriptContainer *currentScript;
const QVector<CANFrame> *modelFrames;
};
#endif // SCRIPTINGWINDOW_H
-96
View File
@@ -1,96 +0,0 @@
#ifndef SERIALWORKER_H
#define SERIALWORKER_H
#include <QDateTime>
#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QTimer>
#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<CANFrame> *);
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
+21
View File
@@ -0,0 +1,21 @@
#include <QtTest>
#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;
}
+33
View File
@@ -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
+366
View File
@@ -0,0 +1,366 @@
#include <QtTest>
#include <QVector>
#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<CANFlt>);
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<QVariant> 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<CANFrame>& 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<CANFrame>& 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<CANFrame>& queue = conn_p->getQueue();
/* wait for frames to arrive */
QTest::qWait(1000);
/* find 3 different ids */
QVector<quint32> 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<QVector<CANFlt>>("filters");
QTest::addColumn<bool>("filterOut");
QTest::addColumn<bool>("signalReceived");
QTest::addColumn<QVector<quint32>>("filtered");
QVector<CANFlt> filters;
QVector<quint32> 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<CANFlt>, filters);
QFETCH(bool, filterOut);
QFETCH(bool, signalReceived);
QFETCH(QVector<quint32>, filtered);
CANConnection* conn_p;
QVERIFY(pCreate(conn_p));
/* start connection */
conn_p->start();
/* set filters */
for(int i=0 ; i<conn_p->getNumBuses() ; i++)
QVERIFY(conn_p->setFilters(i, filters, filterOut));
/* spy signal */
QSignalSpy spy(conn_p, SIGNAL(notify()));
/* configure */
QVERIFY(pConfig(conn_p));
LFQueue<CANFrame>& 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<CANFrame> 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 ; i<pConn_p->getNumBuses() ; 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;
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef TESTCANCON_H
#define TESTCANCON_H
#include <QObject>
#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
+85
View File
@@ -0,0 +1,85 @@
#include <QtTest>
#include <QtConcurrent/qtconcurrentrun.h>
#include "utils/lfqueue.h"
#include "tst_lfqueue.h"
void TestLFQueue::setSize_data()
{
QTest::addColumn<int>("size");
QTest::addColumn<bool>("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<void*> queue;
QCOMPARE(queue.setSize(size), result);
}
void readerThread(LFQueue<int>* pQueue_p, int pSize, bool pSleep) {
int* val_p;
for(int i=0; i<pSize ; i++) {
while(! (val_p = pQueue_p->peek()) );
QVERIFY(val_p);
QCOMPARE(*val_p, i);
pQueue_p->dequeue();
if(pSleep)
QThread::msleep(1);
}
}
void TestLFQueue::exchange_data()
{
QTest::addColumn<int>("size");
QTest::addColumn<bool>("writerSleep");
QTest::addColumn<bool>("readerSleep");
QTest::newRow("nosleep") << 1000 << false << false;
QTest::newRow("readersleep") << 1000 << false << true;
QTest::newRow("writersleep") << 1000 << true << false;
}
void TestLFQueue::exchange()
{
LFQueue<int> queue;
QFETCH(int, size);
QFETCH(bool, writerSleep);
QFETCH(bool, readerSleep);
int* val_p;
QCOMPARE(queue.setSize(2), true);
QFuture<void> thread = QtConcurrent::run(readerThread, &queue, size, readerSleep);
for(int i=0; i<size ; i++) {
while(! (val_p = queue.get()) );
QVERIFY(val_p);
*val_p = i;
queue.queue();
if(writerSleep)
QThread::msleep(1);
}
thread.waitForFinished();
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef TST_LFQUEUE_H
#define TST_LFQUEUE_H
#include <QObject>
class TestLFQueue: public QObject
{
Q_OBJECT
private:
private slots:
void setSize_data();
void setSize();
void exchange_data();
void exchange();
};
#endif // TST_LFQUEUE_H
+223
View File
@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BisectWindow</class>
<widget class="QDialog" name="BisectWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>692</width>
<height>319</height>
</rect>
</property>
<property name="windowTitle">
<string>Bisector Window</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Splitting Strategy:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QRadioButton" name="rbIDRange">
<property name="text">
<string>ID Range</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbIDLower"/>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TO</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbIDUpper"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,10,3">
<item>
<widget class="QRadioButton" name="rbFrameNumber">
<property name="text">
<string>Frame Number</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="slideFrameNumber">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="editFrameNumber"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,10,3">
<item>
<widget class="QRadioButton" name="rbPercentage">
<property name="text">
<string>Percentage</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="slidePercentage">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="pageStep">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="editPercentage"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Save Which Side:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="rbLowerSection">
<property name="text">
<string>Lower Section</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbUpperSection">
<property name="text">
<string>Upper Section</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Number of Frames in Main List:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelMainListNum">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Saved Frames after split:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelSplitNum">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QPushButton" name="btnCalculate">
<property name="text">
<string>Calculate Split</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSaveFrames">
<property name="text">
<string>Save split frames to a new file</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnReplaceFrames">
<property name="text">
<string>Replace main list with split frames</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+268
View File
@@ -0,0 +1,268 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConnectionWindow</class>
<widget class="QWidget" name="ConnectionWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>956</width>
<height>527</height>
</rect>
</property>
<property name="windowTitle">
<string>Connection Settings</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="2,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Connections:</string>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableConnections">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="btnNewConn">
<property name="text">
<string>New Connection</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemoveBus">
<property name="text">
<string>Remove Selected Connection</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="btnActivateAll">
<property name="text">
<string>Activate All Connections</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDeactivateAll">
<property name="text">
<string>Deactivate All Connections</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="gbType">
<property name="title">
<string>Connection Type</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="rbGVRET">
<property name="text">
<string>GVRET Serial</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbKvaser">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Kvaser</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbSocketCAN">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>SocketCAN</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="lPort">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stPort">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>22</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="cbPage">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QComboBox" name="cbPort">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>341</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="etPage">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLineEdit" name="lePort">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckSingleWire">
<property name="text">
<string>Single Wire Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckListenOnly">
<property name="text">
<string>Listen Only Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckEnabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>CAN Speed</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSpeed"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="btnOK">
<property name="text">
<string>Create New Connection</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRevert">
<property name="text">
<string>Revert</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
<string>Firmware Updater</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignHCenter">

Some files were not shown because too many files have changed in this diff Show More