Merge pull request #57 from canpadawan/WIP2

Wip2
This commit is contained in:
Collin Kidder
2016-06-18 16:35:01 -04:00
committed by GitHub
31 changed files with 2368 additions and 585 deletions
+13 -5
View File
@@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core gui
QT += core gui serialbus
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets serialport printsupport qml
@@ -50,8 +50,11 @@ SOURCES += main.cpp\
isotp_interpreterwindow.cpp \
isotp_handler.cpp \
canconnectionmodel.cpp \
canconnection.cpp \
canconnectioncontainer.cpp
canbus.cpp \
connections/canconnection.cpp \
connections/socketcan.cpp \
connections/canconfactory.cpp \
connections/gvretserial.cpp
HEADERS += mainwindow.h \
can_structs.h \
@@ -88,8 +91,13 @@ HEADERS += mainwindow.h \
isotp_interpreterwindow.h \
isotp_handler.h \
canconnectionmodel.h \
canconnection.h \
canconnectioncontainer.h
canbus.h \
utils/lfqueue.h \
connections/canconnection.h \
connections/socketcan.h \
connections/canconconst.h \
connections/canconfactory.h \
connections/gvretserial.h
FORMS += mainwindow.ui \
graphingwindow.ui \
+1 -1
View File
@@ -4,7 +4,7 @@
#include <QVector>
#include <stdint.h>
class CANFrame
struct CANFrame
{
public:
int ID;
+67
View File
@@ -0,0 +1,67 @@
#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==(CANBus& bus) {
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;
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef CANBus_H
#define CANBus_H
class CANBus
{
public:
CANBus();
CANBus(const CANBus&);
bool operator==(CANBus&);
virtual ~CANBus(){}; /*TODO: remove connection from CANBus and add CANBus as an element of CANConnection */
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();
};
#endif // CANBus_H
-133
View File
@@ -1,133 +0,0 @@
#include "canconnection.h"
CAN_Bus::CAN_Bus()
{
speed = 250000;
listenOnly = false;
singleWire = false;
active = false;
connection = NULL;
busNum = 0;
}
void CAN_Bus::setSpeed(int newSpeed)
{
speed = newSpeed;
}
void CAN_Bus::setListenOnly(bool mode)
{
listenOnly = mode;
}
void CAN_Bus::setSingleWire(bool mode)
{
singleWire = mode;
}
void CAN_Bus::setEnabled(bool mode)
{
active = mode;
}
void CAN_Bus::setConnection(CANConnection *conn)
{
connection = conn;
}
void CAN_Bus::setBusNum(int num)
{
busNum = num;
}
int CAN_Bus::getSpeed()
{
return speed;
}
int CAN_Bus::getBusNum()
{
return busNum;
}
bool CAN_Bus::isListenOnly()
{
return listenOnly;
}
bool CAN_Bus::isSingleWire()
{
return singleWire;
}
bool CAN_Bus::isActive()
{
return active;
}
CANConnection* CAN_Bus::getConnection()
{
return connection;
}
CANConnection::CANConnection(CANFrameModel *pModel, int base)
{
model = pModel;
numBuses = getNumBuses();
busBase = base;
}
int CANConnection::getNumBuses()
{
return 1;
}
int CANConnection::getBusBase()
{
return busBase;
}
QString CANConnection::getConnTypeName()
{
return QString("Generic");
}
QString CANConnection::getConnPortName()
{
return portName;
}
void CANConnection::run()
{
}
void CANConnection::sendFrame(const CANFrame * frame)
{
}
void CANConnection::sendFrameBatch(const QList<CANFrame> *frames)
{
}
void CANConnection::updatePortName(QString portName)
{
this->portName = portName;
}
void CANConnection::stopFrameCapture(int bus)
{
}
void CANConnection::startFrameCapture(int bus)
{
}
void CANConnection::updateBusSettings(CAN_Bus *bus)
{
}
-85
View File
@@ -1,85 +0,0 @@
#ifndef CANCONNECTION_H
#define CANCONNECTION_H
#include <Qt>
#include <QObject>
#include "can_structs.h"
#include "canframemodel.h"
class CANConnection;
class CAN_Bus
{
public:
CAN_Bus();
int busNum;
int speed;
bool listenOnly;
bool singleWire;
bool active; //is this bus turned on?
CANConnection *connection;
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.
void setConnection(CANConnection *);
void setBusNum(int);
int getSpeed();
int getBusNum();
bool isListenOnly();
bool isSingleWire();
bool isActive();
CANConnection *getConnection();
};
//Gentle reminder, CANConnection objects run in their own thread (each one, different thread)
//so, for the love of God, do not try to access them directly.
//Use the signal/slots system to do indirect calls.
//Please and thank you.
class CANConnection : public QObject
{
Q_OBJECT
public:
CANConnection(CANFrameModel *, int);
virtual int getNumBuses();
int getBusBase();
virtual QString getConnTypeName();
QString getConnPortName();
signals:
void error(const QString &);
void frameUpdateRapid(int);
void frameUpdate(int);
void connectionSuccess(CANConnection *);
void connectionFailure(CANConnection *);
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);
public slots:
virtual void run();
virtual void sendFrame(const CANFrame *);
virtual void sendFrameBatch(const QList<CANFrame> *);
virtual void updatePortName(QString); //string version of the port to connect to. This base doesnt know a thing about this value
virtual void stopFrameCapture(int); //pass bus number
virtual void startFrameCapture(int); //pass bus number. Only if stopped. Defaults to started anyway
virtual void updateBusSettings(CAN_Bus *bus); //reference to the bus that changed.
protected:
bool quit;
int numBuses;
int busBase; //first bus this class is supposed to handle
QString portName; //for easy access later on
QString connType; //what kind of connection this is (socketcan, kvaser, etc)
bool isConnected; //is the whole device connected? (Is the code connected to the device itself)
CANFrameModel *model;
};
#endif // CANCONNECTION_H
-28
View File
@@ -1,28 +0,0 @@
#include "canconnection.h"
#include "canconnectioncontainer.h"
CANConnectionContainer::CANConnectionContainer(CANConnection *conn)
{
thread = new QThread();
connection = conn;
connection->moveToThread(thread);
connect(thread, &QThread::finished, conn, &QObject::deleteLater);
connect(thread, &QThread::started, conn, &CANConnection::run); //setup timers within the proper thread
connect(conn, &CANConnection::frameUpdateRapid, MainWindow::getReference(), &MainWindow::gotFrames, Qt::QueuedConnection);
connect(MainWindow::getReference(), &MainWindow::sendCANFrame, conn, &CANConnection::sendFrame, Qt::QueuedConnection);
thread->start();
thread->setPriority(QThread::HighPriority);
}
CANConnectionContainer::~CANConnectionContainer()
{
//have to stop the actual execution first before deleting
delete thread;
delete connection;
}
CANConnection* CANConnectionContainer::getRef()
{
return connection;
}
-23
View File
@@ -1,23 +0,0 @@
#ifndef CANCONNECTIONCONTAINER_H
#define CANCONNECTIONCONTAINER_H
#include "canconnection.h"
#include <Qt>
#include <QThread>
#include "mainwindow.h"
class CANConnectionContainer : public QObject
{
Q_OBJECT
public:
CANConnectionContainer(CANConnection *conn);
~CANConnectionContainer();
CANConnection* getRef();
private:
CANConnection *connection;
QThread *thread;
};
#endif // CANCONNECTIONCONTAINER_H
+88 -67
View File
@@ -1,5 +1,4 @@
#include "canconnection.h"
#include "canconnectioncontainer.h"
#include "connections/canconnection.h"
#include "canconnectionmodel.h"
CANConnectionModel::CANConnectionModel(QObject *parent)
@@ -7,11 +6,6 @@ CANConnectionModel::CANConnectionModel(QObject *parent)
{
}
void CANConnectionModel::refreshView()
{
beginResetModel();
endResetModel();
}
QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation, int role) const
{
@@ -41,6 +35,9 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation
return QString(tr("Single Wire"));
break;
case 6:
return QString(tr("Status"));
break;
case 7:
return QString(tr("Active"));
break;
}
@@ -52,100 +49,124 @@ QVariant CANConnectionModel::headerData(int section, Qt::Orientation orientation
return QVariant();
}
int CANConnectionModel::rowCount(const QModelIndex &parent) const
{
return buses.count();
}
int CANConnectionModel::columnCount(const QModelIndex &parent) const
{
return 7;
}
int CANConnectionModel::rowCount(const QModelIndex &parent) const {
int rows=0;
QList<CANConnection*>::const_iterator iter;
for (iter = mConns.begin() ; iter != mConns.end() ; ++iter) {
rows+=(*iter)->getNumBuses();
}
return rows;
}
QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= (buses.count()))
return QVariant();
if (role == Qt::DisplayRole) {
CAN_Bus bus = buses[index.row()];
CANConnection *conn = bus.connection;
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(bus.busNum);
break;
case 1: //type
if (conn) return conn->getConnTypeName();
else qDebug() << "Tried to show connection type but connection was NULL";
break;
case 2: //port
if (conn) return conn->getConnPortName();
else qDebug() << "Tried to show connection port but connection was NULL";
break;
case 3: //speed
return QString::number(bus.speed);
break;
case 4: //Listen Only
if (bus.listenOnly) return QString("True");
else return QString("False");
break;
case 5: //Single Wire
if (bus.singleWire) return QString("True");
else return QString("False");
break;
case 6: //Active
if (bus.active) return QString("True");
else return QString("False");
break;
default:
return QVariant();
case 0: //bus
return QString::number(busId);
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: {}
}
}
else
return QVariant();
return QVariant();
}
void CANConnectionModel::addConnection(CANConnection *conn)
{
CAN_Bus bus;
CANConnectionContainer *cont = new CANConnectionContainer(conn);
connections.append(cont);
}
void CANConnectionModel::addBus(CAN_Bus &bus)
void CANConnectionModel::add(CANConnection* pConn_p)
{
beginResetModel();
buses.append(bus);
mConns.append(pConn_p);
endResetModel();
}
CAN_Bus* CANConnectionModel::getBus(int bus)
void CANConnectionModel::remove(CANConnection* pConn_p)
{
if (bus < 0) return NULL;
if (bus >= buses.count()) return NULL;
return &buses[bus];
beginResetModel();
mConns.removeOne(pConn_p);
endResetModel();
}
CANConnection* CANConnectionModel::getConnection(int conn)
QList<CANConnection*>& CANConnectionModel::getConnections()
{
if (conn < 0) return NULL;
if (conn >= connections.count()) return NULL;
return connections[conn]->getRef();
return mConns;
}
CAN_Bus* CANConnectionModel::findBusByNum(int bus)
CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const
{
for (int i = 0; i < buses.count(); i++)
{
if (buses[i].busNum == bus)
{
return &buses[i];
if (pIdx < 0)
return NULL;
int i=0;
QList<CANConnection*>::const_iterator iter = mConns.begin();
for (iter = mConns.begin() ; iter != mConns.end() ; ++iter) {
if( i <= pIdx && pIdx < i+(*iter)->getNumBuses() ) {
pBusId = pIdx - i;
return (*iter);
}
i+= (*iter)->getNumBuses();
}
return NULL;
}
void CANConnectionModel::refreshView()
{
beginResetModel();
endResetModel();
}
+12 -12
View File
@@ -1,12 +1,13 @@
#ifndef CANCONNECTIONMODEL_H
#define CANCONNECTIONMODEL_H
#include "canconnection.h"
#include "canconnectioncontainer.h"
#include <QAbstractTableModel>
class CANConnectionContainer;
#include "canbus.h"
#include "connections/canconnection.h"
#include "connectionwindow.h"
class CANConnectionModel : public QAbstractTableModel
{
@@ -18,22 +19,21 @@ public:
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void addConnection(CANConnection *conn);
void addBus(CAN_Bus &bus);
CAN_Bus* getBus(int bus);
CANConnection* getConnection(int conn);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
void add(CANConnection* pConn_p);
void remove(CANConnection* pConn_p);
QList<CANConnection*>& getConnections();
CANConnection* getAtIdx(int, int&) const;
void refreshView();
private:
QList<CANConnectionContainer *> connections;
QList<CAN_Bus> buses;
CAN_Bus *findBusByNum(int bus);
QList<CANConnection*> mConns;
};
#endif // CANCONNECTIONMODEL_H
+3 -1
View File
@@ -281,8 +281,10 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation,
return QVariant();
}
void CANFrameModel::addFrame(const CANFrame &frame, bool autoRefresh = false)
void CANFrameModel::addFrame(CANFrame& frame, bool autoRefresh = false)
{
/*TODO: remove mutex */
mutex.lock();
CANFrame tempFrame;
tempFrame = frame;
+3 -1
View File
@@ -23,7 +23,6 @@ public:
int columnCount(const QModelIndex &) const;
int totalFrameCount();
void addFrame(const CANFrame &, bool);
void sendRefresh();
void sendRefresh(int);
void sendBulkRefresh(int);
@@ -46,6 +45,9 @@ public:
const QVector<CANFrame> *getFilteredListReference() const; //Thus saith the Lord, NO.
const QMap<int, bool> *getFiltersReference() const; //this neither
public slots:
void addFrame(CANFrame&, bool);
signals:
void updatedFiltersList();
+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
+245
View File
@@ -0,0 +1,245 @@
#include <QThread>
#include "canconnection.h"
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),
mThread_p(NULL)
{
qDebug() << "CANConnection()";
/* register types */
qRegisterMetaType<CANBus>("CANBus");
qRegisterMetaType<CANFrame>("CANFrame");
qRegisterMetaType<CANCon::status>("CANCon::status");
/* set queue size */
mQueue.setSize(pQueueLen); /*TODO add check on returned value */
/* allocate buses */
mBus = new CANBus[mNumBuses];
mConfigured = new bool[mNumBuses];
for(int i=0 ; i<mNumBuses ; i++)
mConfigured[i] = false;
/* if needed, create a thread and move ourself into it */
if(pUseThread) {
mThread_p = new QThread();
}
}
CANConnection::~CANConnection()
{
qDebug() << "~CANConnection()";
/* stop and delete thread */
if(mThread_p) {
mThread_p->quit();
mThread_p->wait();
delete mThread_p;
mThread_p = NULL;
}
/* delete bus table */
delete[] mBus;
mBus = NULL;
/* configured table */
delete[] mConfigured;
mConfigured = 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;
}
/* 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 && (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);
}
void CANConnection::sendFrame(const CANFrame& pFrame)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "sendFrame",
Qt::BlockingQueuedConnection,
Q_ARG(const CANFrame&, pFrame));
return;
}
return piSendFrame(pFrame);
}
void CANConnection::sendFrameBatch(const QList<CANFrame>& pFrames)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "sendFrameBatch",
Qt::BlockingQueuedConnection,
Q_ARG(const QList<CANFrame>&, pFrames));
return;
}
return piSendFrameBatch(pFrames);
}
int CANConnection::getNumBuses() {
return mNumBuses;
}
bool CANConnection::isConfigured(int pBusId) {
if( pBusId < 0 || pBusId >= mNumBuses)
return false;
return mConfigured[pBusId];
}
void CANConnection::setConfigured(int pBusId, bool pConfigured) {
if( pBusId < 0 || pBusId >= mNumBuses)
return;
mConfigured[pBusId] = pConfigured;
}
bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) {
if( pBusId < 0 || pBusId >= mNumBuses || !isConfigured(pBusId))
return false;
pBus = mBus[pBusId];
return true;
}
void CANConnection::setBusConfig(int pBusId, CANBus& pBus) {
if( pBusId < 0 || pBusId >= mNumBuses)
return;
mConfigured[pBusId] = true;
mBus[pBusId] = 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;
}
+252
View File
@@ -0,0 +1,252 @@
#ifndef CANCONNECTION_H
#define CANCONNECTION_H
#include <Qt>
#include <QObject>
#include "utils/lfqueue.h"
#include "can_structs.h"
#include "canbus.h"
#include "canconconst.h"
class CANConnection : public QObject
{
Q_OBJECT
public:
/**
* @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);
/**
* @brief CANConnection destructor
*/
virtual ~CANConnection();
/**
* @brief getNumBuses
* @return returns the number of buses of the device
*/
int getNumBuses();
/**
* @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 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, it is then safe for callee to flush the queue
*/
void suspend(bool pSuspend);
/**
* @brief provides device with the frame to send
* @param pFrame: the frame to send
* @note this calls piSendFrame (in the working thread context if one has been started)
*/
void sendFrame(const CANFrame& pFrame);
/**
* @brief provides device with a list of frames to send
* @param pFrame: the list of frames to send
* @note this calls piSendFrameBatch (in the working thread context if one has been started)
*/
void sendFrameBatch(const QList<CANFrame>& pFrames);
protected:
/**
* @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
*/
virtual void piSendFrame(const CANFrame&) = 0;
/**
* @brief provides device with a list of frames to send
* @param pFrame: the list of frames to send
*/
virtual void piSendFrameBatch(const QList<CANFrame>&) = 0;
private:
CANBus* mBus;
bool* mConfigured;
LFQueue<CANFrame> mQueue;
const int mNumBuses;
const QString mPort;
const CANCon::type mType;
bool mIsCapSuspended;
QAtomicInt mStatus;
QThread* mThread_p;
};
#endif // CANCONNECTION_H
+578
View File
@@ -0,0 +1,578 @@
#include <QObject>
#include <QDebug>
#include <QCanBusFrame>
#include <QSerialPortInfo>
#include <QSettings>
#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;
gotValidated = true;
isAutoRestart = false;
txTimestampBasis = QDateTime::currentMSecsSinceEpoch();
readSettings();
}
GVRetSerial::~GVRetSerial()
{
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)
{
can0Baud = bus.getSpeed();
can0Baud |= 0x80000000;
if (bus.isActive())
{
can0Baud |= 0x40000000;
can0Enabled = true;
}
else can0Enabled = false;
if (bus.isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
else can0ListenOnly = false;
}
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 GVRetSerial::piSendFrame(const CANFrame&) {}
void GVRetSerial::piSendFrameBatch(const QList<CANFrame>&){}
/****************************************************************/
void GVRetSerial::readSettings()
{
QSettings settings;
if (settings.value("Main/ValidateComm", true).toBool())
{
doValidation = true;
}
else doValidation = false;
}
void GVRetSerial::connectDevice()
{
QSettings settings;
/* disconnect device */
if(serial)
disconnectDevice();
/* open new device */
serial = new QSerialPort(QSerialPortInfo(getPort()));
if(!serial) {
qDebug() << "can't open serial port " << getPort();
return;
}
/* configure */
serial->setDataBits(serial->Data8);
serial->setFlowControl(serial->HardwareControl); //this is important though
if (!serial->open(QIODevice::ReadWrite))
{
qDebug() << serial->errorString();
}
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);
output.append((char)0xF1); //signal we want to issue a command
output.append((char)0x06); //request canbus stats from the board
output.append((char)0xF1); //another command to the GVRET
output.append((char)0x07); //request device information
output.append((char)0xF1);
output.append((char)0x08); //setting singlewire mode
if (settings.value("Main/SingleWireMode", false).toBool())
{
output.append((char)0x10); //signal that we do want single wire mode
}
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
output.append((char)0xF1); //and another command
output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try
continuousTimeSync = true;
serial->write(output);
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()));
}
void GVRetSerial::disconnectDevice() {
if (serial != NULL)
{
if (serial->isOpen())
{
serial->clear();
serial->close();
}
serial->disconnect(); //disconnect all signals
delete serial;
serial = NULL;
}
}
void GVRetSerial::connectionTimeout()
{
//one second after trying to connect are we actually connected?
if (CANCon::NOT_CONNECTED==getStatus()) //no?
{
//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;
//qDebug() << (tr("Got data from serial. Len = %0").arg(data.length()));
for (int i = 0; i < data.length(); i++)
{
c = data.at(i);
procRXChar(c);
}
}
void GVRetSerial::procRXChar(unsigned char c)
{
switch (rx_state)
{
case IDLE:
if (c == 0xF1) rx_state = GET_COMMAND;
break;
case GET_COMMAND:
switch (c)
{
case 0: //receiving a can frame
rx_state = BUILD_CAN_FRAME;
rx_step = 0;
break;
case 1: //time sync
rx_state = TIME_SYNC;
rx_step = 0;
break;
case 2: //process a return reply for digital input states.
rx_state = GET_DIG_INPUTS;
rx_step = 0;
break;
case 3: //process a return reply for analog inputs
rx_state = GET_ANALOG_INPUTS;
break;
case 4: //we set digital outputs we don't accept replies so nothing here.
rx_state = IDLE;
break;
case 5: //we set canbus specs we don't accept replies.
rx_state = IDLE;
break;
case 6: //get canbus parameters from GVRET
rx_state = GET_CANBUS_PARAMS;
rx_step = 0;
break;
case 7: //get device info
rx_state = GET_DEVICE_INFO;
rx_step = 0;
break;
case 9:
gotValidated = true;
//qDebug() << "Got validated";
rx_state = IDLE;
break;
}
break;
case BUILD_CAN_FRAME:
switch (rx_step)
{
case 0:
buildFrame.timestamp = c;
break;
case 1:
buildFrame.timestamp |= (uint)(c << 8);
break;
case 2:
buildFrame.timestamp |= (uint)c << 16;
break;
case 3:
buildFrame.timestamp |= (uint)c << 24;
break;
case 4:
buildFrame.ID = c;
break;
case 5:
buildFrame.ID |= c << 8;
break;
case 6:
buildFrame.ID |= c << 16;
break;
case 7:
buildFrame.ID |= c << 24;
if ((buildFrame.ID & 1 << 31) == 1 << 31)
{
buildFrame.ID &= 0x7FFFFFFF;
buildFrame.extended = true;
}
else buildFrame.extended = false;
break;
case 8:
buildFrame.len = c & 0xF;
if (buildFrame.len > 8) buildFrame.len = 8;
buildFrame.bus = (c & 0xF0) >> 4;
break;
default:
if (rx_step < buildFrame.len + 9)
{
buildFrame.data[rx_step - 9] = c;
}
else
{
rx_state = IDLE;
rx_step = 0;
buildFrame.isReceived = true;
if (!isCapSuspended())
{
/* get frame from queue */
CANFrame* frame_p = getQueue().get();
if(frame_p) {
/* copy frame */
*frame_p = 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);
}
}
break;
}
rx_step++;
break;
case TIME_SYNC: //gives a pretty good base guess for the proper timestamp. Can be refined when traffic starts to flow (if wanted)
switch (rx_step)
{
case 0:
buildTimeBasis = c;
break;
case 1:
buildTimeBasis += ((uint32_t)c << 8);
break;
case 2:
buildTimeBasis += ((uint32_t)c << 16);
break;
case 3:
buildTimeBasis += ((uint32_t)c << 24);
qDebug() << "GVRET firmware reports timestamp of " << buildTimeBasis;
txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - ((uint64_t)buildTimeBasis / (uint64_t)1000ull);
continuousTimeSync = false;
rx_state = IDLE;
break;
}
rx_step++;
break;
case GET_ANALOG_INPUTS: //get 9 bytes - 2 per analog input plus checksum
switch (rx_step)
{
case 0:
break;
}
rx_step++;
break;
case GET_DIG_INPUTS: //get two bytes. One for digital in status and one for checksum.
switch (rx_step)
{
case 0:
break;
case 1:
rx_state = IDLE;
break;
}
rx_step++;
break;
case GET_CANBUS_PARAMS:
switch (rx_step)
{
case 0:
can0Enabled = (c & 0xF);
can0ListenOnly = (c >> 4);
break;
case 1:
can0Baud = c;
break;
case 2:
can0Baud |= c << 8;
break;
case 3:
can0Baud |= c << 16;
break;
case 4:
can0Baud |= c << 24;
break;
case 5:
can1Enabled = (c & 0xF);
can1ListenOnly = (c >> 4);
deviceSingleWireMode = (c >> 6);
break;
case 6:
can1Baud = c;
break;
case 7:
can1Baud |= c << 8;
break;
case 8:
can1Baud |= c << 16;
break;
case 9:
can1Baud |= c << 24;
rx_state = IDLE;
qDebug() << "Baud 0 = " << can0Baud;
qDebug() << "Baud 1 = " << 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++;
break;
case GET_DEVICE_INFO:
switch (rx_step)
{
case 0:
deviceBuildNum = c;
break;
case 1:
deviceBuildNum |= c << 8;
break;
case 2:
break; //don't care about eeprom version
case 3:
break; //don't care about file type
case 4:
break; //don't care about whether it auto logs or not
case 5:
deviceSingleWireMode = c;
rx_state = IDLE;
qDebug() << "build num: " << deviceBuildNum;
qDebug() << "single wire can: " << deviceSingleWireMode;
emit deviceInfo(deviceBuildNum, deviceSingleWireMode);
break;
}
rx_step++;
break;
case SET_DIG_OUTPUTS:
rx_state = IDLE;
break;
case SETUP_CANBUS:
rx_state = IDLE;
break;
case SET_SINGLEWIRE_MODE:
rx_state = IDLE;
break;
}
}
void GVRetSerial::handleTick()
{
//qDebug() << "Tick!";
if( CANCon::CONNECTED == getStatus() )
{
if (!gotValidated && doValidation)
{
if (serial == NULL) return;
if (serial->isOpen()) //if it's still false we have a problem...
{
qDebug() << "Comm validation failed. ";
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(connectDevice()));
return;
}
}
}
if (doValidation && serial && serial->isOpen()) sendCommValidation();
}
void GVRetSerial::sendCommValidation()
{
QByteArray output;
gotValidated = false;
output.append((char)0xF1); //another command to the GVRET
output.append((char)0x09); //request a reply to get validation
//send it twice for good measure.
output.append((char)0xF1); //another command to the GVRET
output.append((char)0x09); //request a reply to get validation
serial->write(output);
}
+105
View File
@@ -0,0 +1,105 @@
#ifndef GVRETSERIAL_H
#define GVRETSERIAL_H
#include <QSerialPort>
#include <QCanBusDevice>
#include <QThread>
#include <QTimer>
/*************/
#include <QDateTime>
/*************/
#include "canframemodel.h"
#include "canconnection.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();
signals:
void error(const QString &);
void status(CANCon::status);
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);
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 void piSendFrame(const CANFrame&) ;
virtual void piSendFrameBatch(const QList<CANFrame>&);
void disconnectDevice();
private slots:
void connectDevice();
void connectionTimeout();
void readSerialData();
void handleTick();
private:
void readSettings();
void procRXChar(unsigned char);
void sendCommValidation();
protected:
QTimer mTimer;
QThread mThread;
bool doValidation;
bool gotValidated;
bool isAutoRestart;
bool continuousTimeSync;
QSerialPort *serial;
int framesRapid;
STATE rx_state;
int rx_step;
CANFrame buildFrame;
int can0Baud, can1Baud;
bool can0Enabled, can1Enabled;
bool can0ListenOnly, can1ListenOnly;
int deviceBuildNum;
int deviceSingleWireMode;
uint64_t txTimestampBasis;
uint32_t buildTimeBasis;
};
#endif // GVRETSERIAL_H
+223
View File
@@ -0,0 +1,223 @@
#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 */
{
qDebug() << "SocketCan()";
}
SocketCan::~SocketCan()
{
stop();
qDebug() << "~SocketCan()";
}
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);
}*/
/* connect device */
if (!mDev_p->connectDevice()) {
disconnectDevice();
qDebug() << "can't connect device";
}
}
void SocketCan::piSendFrame(const CANFrame&) {}
void SocketCan::piSendFrameBatch(const QList<CANFrame>&){}
/***********************************/
/**** 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)
{
qDebug() << "Number of frames written:" << count;
}
void SocketCan::framesReceived()
{
/* sanity checks */
if(!mDev_p)
return;
/* read frame */
while(true)
{
const QCanBusFrame recFrame = mDev_p->readFrame();
/* exit case */
if(!recFrame.isValid())
return;
/* 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();
/* enqueue frame */
getQueue().queue();
}
else
qDebug() << "can't get a frame, ERROR";
}
else {
qDebug() << "invalid frame";
}
}
}
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;
}
+57
View File
@@ -0,0 +1,57 @@
#ifndef SocketCan_H
#define SocketCan_H
#include <QObject>
#include <QCanBus>
#include <QTimer>
#include <qthread.h>
#include "canframemodel.h"
#include "canconnection.h"
class SocketCan : public CANConnection
{
Q_OBJECT
public:
SocketCan(QString portName);
virtual ~SocketCan();
signals:
void error(const QString &);
void status(CANCon::status);
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);
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 void piSendFrame(const CANFrame&) ;
virtual void piSendFrameBatch(const QList<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
+240 -116
View File
@@ -1,6 +1,9 @@
#include <QCanBus>
#include "connectionwindow.h"
#include "ui_connectionwindow.h"
#include <QtNetwork/QNetworkInterface>
#include "connections/canconfactory.h"
ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) :
QDialog(parent),
@@ -10,7 +13,7 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) :
settings = new QSettings();
qRegisterMetaType<CAN_Bus *>("CAN_Bus *");
qRegisterMetaType<CANBus>("CANBus");
qRegisterMetaType<const CANFrame *>("const CANFrame *");
qRegisterMetaType<const QList<CANFrame> *>("const QList<CANFrame> *");
@@ -22,10 +25,11 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) :
ui->tableConnections->setColumnWidth(0, 50);
ui->tableConnections->setColumnWidth(1, 110);
ui->tableConnections->setColumnWidth(2, 110);
ui->tableConnections->setColumnWidth(3, 150);
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);
int temp = settings->value("Main/DefaultConnectionType", 0).toInt();
@@ -36,7 +40,6 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) :
ui->ckSingleWire->setChecked(settings->value("Main/SingleWireMode", false).toBool());
ui->cbSpeed->addItem(tr("<Default>"));
ui->cbSpeed->addItem(tr("Disabled"));
ui->cbSpeed->addItem(tr("125000"));
ui->cbSpeed->addItem(tr("250000"));
ui->cbSpeed->addItem(tr("500000"));
@@ -44,7 +47,7 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) :
ui->cbSpeed->addItem(tr("33333"));
#ifdef Q_OS_LINUX
ui->rbSocketCAN->setEnabled(true);
ui->rbSocketCAN->setEnabled(isSocketCanAvailable());
#endif
#ifdef Q_OS_WIN
@@ -57,14 +60,38 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) :
connect(ui->rbSocketCAN, &QAbstractButton::toggled, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->btnRevert, &QPushButton::clicked, this, &ConnectionWindow::handleRevert);
connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ConnectionWindow::handleConnSelectionChanged);
connect(connModel, &QAbstractItemModel::modelReset, this, &ConnectionWindow::handleConnSelectionChanged);
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);
qDebug() << "Serial worker thread starting";
connect(&mTicker, SIGNAL(timeout()), this, SLOT(refreshCanList()));
/* tick frequency has a huge impact on performances */
/* TODO: make this configurable and part of the connection constructor to let connection configure the length of the queue */
mTicker.setInterval(500); /*tick twice a second */
mTicker.setSingleShot(false);
mTicker.start();
}
ConnectionWindow::~ConnectionWindow()
{
QList<CANConnection*>& conns = connModel->getConnections();
CANConnection* conn_p;
/* delete connections */
while(!conns.isEmpty()) {
conn_p = conns.takeFirst();
conn_p->stop();
delete conn_p;
}
delete connModel;
mTicker.stop();
delete settings;
delete ui;
}
@@ -76,6 +103,20 @@ void ConnectionWindow::showEvent(QShowEvent* event)
handleConnTypeChanged();
}
void ConnectionWindow::refreshCanList() {
QList<CANConnection*>::iterator conn_p;
QList<CANConnection*>& conns = connModel->getConnections();
CANFrame* frame_p = NULL;
for (conn_p = conns.begin(); conn_p != conns.end(); ++conn_p) {
while( (frame_p = (*conn_p)->getQueue().peek() ) ) {
canModel->addFrame(*frame_p, true);
(*conn_p)->getQueue().dequeue();
}
}
}
void ConnectionWindow::handleNewConn()
{
ui->tableConnections->selectionModel()->clearSelection();
@@ -83,100 +124,113 @@ void ConnectionWindow::handleNewConn()
handleConnSelectionChanged();
}
void ConnectionWindow::setSuspendAll(bool pSuspend)
{
qDebug() << "setSuspendAll";
QList<CANConnection*>::iterator iter;
QList<CANConnection*>& conns = connModel->getConnections();
for (iter = conns.begin(); iter != conns.end(); ++iter)
(*iter)->suspend(pSuspend);
}
void ConnectionWindow::setActiveAll(bool pActive)
{
QList<CANConnection*>::iterator iter;
QList<CANConnection*>& conns = connModel->getConnections();
CANBus bus;
for (iter = conns.begin(); iter != conns.end(); ++iter) {
for(int i=0 ; i<(*iter)->getNumBuses() ; i++) {
if( (*iter)->getBusSettings(i, bus) ) {
bus.active = pActive;
(*iter)->setBusSettings(i, bus);
}
}
}
}
void ConnectionWindow::handleEnableAll()
{
setActiveAll(true);
}
void ConnectionWindow::handleDisableAll()
{
setActiveAll(false);
}
void ConnectionWindow::handleConnTypeChanged()
{
if (ui->rbGVRET->isChecked()) getSerialPorts();
if (ui->rbKvaser->isChecked()) getKvaserPorts();
if (ui->rbSocketCAN->isChecked()) getSocketcanPorts();
if (ui->rbGVRET->isChecked()) selectSerial();
if (ui->rbKvaser->isChecked()) selectKvaser();
if (ui->rbSocketCAN->isChecked()) selectSocketCan();
}
void ConnectionWindow::connectionSuccess(CANConnection *conn)
/* status */
void ConnectionWindow::connectionStatus(CANCon::status pStatus)
{
CAN_Bus bus;
bus.active = true;
bus.busNum = conn->getBusBase();
bus.connection = conn;
bus.listenOnly = ui->ckListenOnly->isChecked();
bus.singleWire = ui->ckSingleWire->isChecked();
if (ui->cbSpeed->currentIndex() < 1) bus.speed = 0; //default speed
else if (ui->cbSpeed->currentIndex() == 1)
{
bus.speed = 0;
bus.active = false;
}
else bus.speed = ui->cbSpeed->currentText().toInt();
connModel->addBus(bus);
int numBuses = conn->getNumBuses();
for (int i = 1; i < numBuses; i++)
{
bus.active = false;
bus.listenOnly = false;
bus.singleWire = false;
bus.speed = 250000;
bus.busNum = conn->getBusBase() + i;
bus.connection = conn;
connModel->addBus(bus);
qDebug() << "Added bus " << bus.busNum;
}
qDebug() << "Connectionstatus changed";
connModel->refreshView();
}
void ConnectionWindow::handleOKButton()
{
QString conn;
int connType = 0;
int whichRow = ui->tableConnections->selectionModel()->currentIndex().row();
qDebug() << "OK pressed. Row " << whichRow;
CANConnection* conn_p = NULL;
if (whichRow > -1)
{
//load settings from GUI into appropriate CAN_Bus entry and then send it off to the appropriate
//CANConnection object
CAN_Bus *bus = connModel->getBus(whichRow);
bus->setListenOnly(ui->ckListenOnly->isChecked());
bus->setSingleWire(ui->ckSingleWire->isChecked());
bus->setEnabled(ui->ckEnabled->isChecked());
if (ui->cbSpeed->currentIndex() == 1)
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());
if (ui->cbSpeed->currentIndex() == 0)
{
bus->speed = 0;
bus->setEnabled(false);
bus.speed = 0;
bus.setEnabled(false);
}
else if (ui->cbSpeed->currentIndex() > 1)
else if (ui->cbSpeed->currentIndex() >= 1)
{
bus->setSpeed(ui->cbSpeed->currentText().toInt());
bus.setSpeed(ui->cbSpeed->currentText().toInt());
}
//call through signal/slot interface without using connect
QMetaObject::invokeMethod(bus->connection, "updateBusSettings",
Qt::QueuedConnection,
Q_ARG(CAN_Bus *, bus));
/* update bus settings */
conn_p->setBusSettings(busId, bus);
connModel->refreshView();
}
else //new connection
{
#if 0
if (ui->rbGVRET->isChecked())
{
{
SerialWorker *serial = new SerialWorker(canModel, connModel->rowCount());
connect(serial, SIGNAL(busStatus(int,int,int)), this, SLOT(receiveBusStatus(int,int,int)));
connect(serial, SIGNAL(connectionSuccess(CANConnection*)), this, SLOT(connectionSuccess(CANConnection*)));
connModel->addConnection(serial);
CANConnectionContainer* container = new CANConnectionContainer(serial);
qDebug() << "Setup initial connection object";
CAN_Bus bus;
CANBus bus;
bus.active = ui->ckEnabled->isChecked();
bus.busNum = serial->getBusBase();
bus.connection = serial;
bus.container = container;
bus.listenOnly = ui->ckListenOnly->isChecked();
bus.singleWire = ui->ckSingleWire->isChecked();
@@ -187,6 +241,7 @@ void ConnectionWindow::handleOKButton()
bus.active = false;
}
else bus.speed = ui->cbSpeed->currentText().toInt();
connModel->addBus(bus);
int numBuses = serial->getNumBuses();
@@ -197,7 +252,7 @@ void ConnectionWindow::handleOKButton()
bus.singleWire = false;
bus.speed = 250000;
bus.busNum = serial->getBusBase() + i;
bus.connection = serial;
bus.container = container;
connModel->addBus(bus);
qDebug() << "Added bus " << bus.busNum;
}
@@ -206,22 +261,45 @@ void ConnectionWindow::handleOKButton()
QMetaObject::invokeMethod(serial, "updatePortName",
Qt::QueuedConnection,
Q_ARG(QString, ui->cbPort->currentText()));
}
else if (ui->rbKvaser->isChecked())
{
#endif
}
else if (ui->rbSocketCAN->isChecked())
{
/* create connection */
conn_p = CanConFactory::create(getConnectionType(), getPortName());
if(!conn_p)
return;
/* connect signal */
connect(conn_p, SIGNAL(status(CANCon::status)),
this, SLOT(connectionStatus(CANCon::status)));
/*TODO add return value and checks */
conn_p->start();
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();
if (ui->cbSpeed->currentIndex() < 1) bus.speed = 0;
else bus.speed = ui->cbSpeed->currentText().toInt();
/* update bus settings */
conn_p->setBusSettings(i, bus);
}
/* add connection to model */
connModel->add(conn_p);
}
}
void ConnectionWindow::receiveBusStatus(int bus, int speed, int status)
{
#if 0
qDebug() << "bus " << bus << " speed " << speed << " status " << status;
CAN_Bus *busRef = connModel->getBus(bus);
CANBus *busRef = connModel->getBus(bus);
if (status & 40) busRef->setSpeed(speed);
if (status & 8) //update enabled status
{
@@ -236,19 +314,22 @@ void ConnectionWindow::receiveBusStatus(int bus, int speed, int status)
busRef->setListenOnly((status & 4)?true:false);
}
connModel->refreshView();
#endif
}
void ConnectionWindow::handleConnSelectionChanged()
{
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
qDebug() << "Selection: " << selIdx;
if (selIdx == -1)
{
ui->btnOK->setText(tr("Create New Connection"));
ui->cbPort->setEnabled(true);
ui->rbGVRET->setEnabled(true);
ui->rbKvaser->setEnabled(true);
ui->rbSocketCAN->setEnabled(true);
ui->cbSpeed->setEnabled(false);
ui->cbPort->setCurrentIndex(0);
ui->ckListenOnly->setChecked(false);
ui->ckSingleWire->setChecked(false);
@@ -256,25 +337,43 @@ void ConnectionWindow::handleConnSelectionChanged()
}
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->cbPort->setEnabled(false);
ui->rbGVRET->setEnabled(false);
ui->rbKvaser->setEnabled(false);
ui->rbSocketCAN->setEnabled(false);
CAN_Bus *bus = connModel->getBus(selIdx);
if (bus->connection->getConnTypeName() == "GVRET") ui->rbGVRET->setChecked(true);
if (bus->connection->getConnTypeName() == "KVASER") ui->rbKvaser->setChecked(true);
if (bus->connection->getConnTypeName() == "SOCKETCAN") ui->rbSocketCAN->setChecked(true);
ui->ckListenOnly->setChecked(bus->isListenOnly());
ui->ckSingleWire->setChecked(bus->isSingleWire());
ui->ckEnabled->setChecked(bus->isActive());
int speed = bus->getSpeed();
ui->rbSocketCAN->setEnabled(false);
ui->cbSpeed->setEnabled(true);
switch(conn_p->getType()) {
case CANCon::GVRET_SERIAL: ui->rbGVRET->setChecked(true); break;
case CANCon::KVASER: ui->rbKvaser->setChecked(true); break;
case CANCon::SOCKETCAN: ui->rbSocketCAN->setChecked(true); break;
default: {}
}
ui->ckListenOnly->setChecked(bus.isListenOnly());
ui->ckSingleWire->setChecked(bus.isSingleWire());
ui->ckEnabled->setChecked(bus.isActive());
int speed = bus.getSpeed();
setSpeed(speed);
}
}
void ConnectionWindow::getSerialPorts()
void ConnectionWindow::selectSerial()
{
/* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage);
ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts();
@@ -285,28 +384,19 @@ void ConnectionWindow::getSerialPorts()
}
}
void ConnectionWindow::getKvaserPorts()
void ConnectionWindow::selectKvaser()
{
#ifdef Q_OS_WIN
/* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage);
#endif
}
void ConnectionWindow::getSocketcanPorts()
void ConnectionWindow::selectSocketCan()
{
#ifdef Q_OS_LINUX
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);
}
}
/* set edit text page visible */
ui->stPort->setCurrentWidget(ui->etPage);
#endif
}
@@ -355,16 +445,30 @@ int ConnectionWindow::getSpeed()
QString ConnectionWindow::getPortName()
{
return (ui->cbPort->currentText());
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 "";
}
ConnectionType::ConnectionType ConnectionWindow::getConnectionType()
CANCon::type ConnectionWindow::getConnectionType()
{
if (ui->rbGVRET->isChecked()) return ConnectionType::GVRET_SERIAL;
if (ui->rbKvaser->isChecked()) return ConnectionType::KVASER;
if (ui->rbSocketCAN->isChecked()) return ConnectionType::SOCKETCAN;
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);
@@ -378,7 +482,21 @@ bool ConnectionWindow::getSWMode()
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 */
connModel->remove(conn_p);
/* stop and delete connection */
conn_p->stop();
delete conn_p;
}
void ConnectionWindow::handleRevert()
@@ -386,31 +504,37 @@ void ConnectionWindow::handleRevert()
}
void ConnectionWindow::handleEnableAll()
{
}
void ConnectionWindow::handleDisableAll()
{
}
void ConnectionWindow::sendFrame(const CANFrame *frame)
{
CAN_Bus *bus = connModel->getBus(frame->bus);
#if 0
CANBus *bus = connModel->getBus(frame->bus);
if (bus == NULL) return;
QMetaObject::invokeMethod(bus->connection, "sendFrame",
QMetaObject::invokeMethod(bus->getContainer()->getRef(), "sendFrame",
Qt::QueuedConnection,
Q_ARG(const CANFrame *, frame));
#endif
}
void ConnectionWindow::sendFrameBatch(const QList<CANFrame> *frames)
{
#if 0
if (frames->count() == 0) return;
CAN_Bus *bus = connModel->getBus(frames->at(0).bus);
CANBus *bus = connModel->getBus(frames->at(0).bus);
if (bus == NULL) return;
QMetaObject::invokeMethod(bus->connection, "sendFrameBatch",
QMetaObject::invokeMethod(bus->getContainer()->getRef(), "sendFrameBatch",
Qt::QueuedConnection,
Q_ARG(const QList<CANFrame> *, frames));
#endif
}
bool ConnectionWindow::isSocketCanAvailable()
{
#ifdef Q_OS_LINUX
foreach (const QByteArray &backend, QCanBus::instance()->plugins()) {
if (backend == "socketcan") {
return true;
}
}
#endif
return false;
}
+20 -20
View File
@@ -1,14 +1,18 @@
#ifndef CONNECTIONWINDOW_H
#define CONNECTIONWINDOW_H
#include "canconnectionmodel.h"
#include <QSerialPortInfo>
#include <QDialog>
#include <QDebug>
#include <QSettings>
#include "canconnection.h"
#include "serialworker.h"
#include <QTimer>
//#include "canconnection_old.h"
//#include "serialworker.h"
#include "canconnectionmodel.h"
#include "canframemodel.h"
class CANConnectionModel;
@@ -16,15 +20,6 @@ namespace Ui {
class ConnectionWindow;
}
namespace ConnectionType
{
enum ConnectionType
{
GVRET_SERIAL,
KVASER,
SOCKETCAN
};
}
class ConnectionWindow : public QDialog
{
@@ -36,11 +31,11 @@ public:
void showEvent(QShowEvent *);
int getSpeed();
QString getPortName(); //name of port to connect to
ConnectionType::ConnectionType getConnectionType();
CANCon::type getConnectionType();
bool getSWMode();
signals:
void updateBusSettings(CAN_Bus *bus);
void updateBusSettings(CANBus *bus);
void updatePortName(QString port);
public slots:
@@ -48,6 +43,8 @@ public slots:
void setSWMode(bool mode);
void sendFrame(const CANFrame *);
void sendFrameBatch(const QList<CANFrame> *);
void setSuspendAll(bool);
private slots:
void handleOKButton();
@@ -58,10 +55,10 @@ private slots:
void handleDisableAll();
void handleRevert();
void handleNewConn();
void handleEnableAll();
void handleDisableAll();
void receiveBusStatus(int bus, int speed, int status);
void connectionSuccess(CANConnection *conn);
void connectionStatus(CANCon::status);
void refreshCanList();
private:
Ui::ConnectionWindow *ui;
@@ -69,11 +66,14 @@ private:
QSettings *settings;
CANConnectionModel *connModel;
CANFrameModel *canModel;
QTimer mTicker;
void getSerialPorts();
void getKvaserPorts();
void getSocketcanPorts();
void selectSerial();
void selectKvaser();
void selectSocketCan();
bool isSocketCanAvailable();
void setActiveAll(bool pActive);
};
#endif // CONNECTIONWINDOW_H
+65 -3
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1009</width>
<height>433</height>
<width>956</width>
<height>527</height>
</rect>
</property>
<property name="windowTitle">
@@ -129,7 +129,69 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="cbPort"/>
<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">
+6 -8
View File
@@ -47,7 +47,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();
@@ -180,6 +181,7 @@ MainWindow::MainWindow(QWidget *parent) :
//Automatically create the connection window so it can be updated even if we never opened it.
connectionWindow = new ConnectionWindow(model);
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()
@@ -510,7 +512,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();
@@ -712,15 +714,11 @@ 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)
+1 -2
View File
@@ -92,8 +92,7 @@ public slots:
signals:
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
+94 -76
View File
@@ -5,13 +5,14 @@
#include <QTimer>
#include <QSettings>
#if 0
SerialWorker::SerialWorker(CANFrameModel *model, int base) : CANConnection(model, base)
{
qDebug() << "Serial Worker constructor";
serial = NULL;
rx_state = IDLE;
rx_step = 0;
buildFrame = new CANFrame;
buildFrame;
ticker = NULL;
framesRapid = 0;
gotValidated = true;
@@ -166,8 +167,13 @@ void SerialWorker::sendFrame(const CANFrame *frame)
//qDebug() << "Sending out frame with id " << frame->ID;
//show our sent frames in the list too. This happens even if we're not connected.
model->addFrame(tempFrame, false);
//show our sent frames in the list too. This happens even if we're not connected.
/* model lives in UI thread, we need to call invokeMethod */
QMetaObject::invokeMethod(model, "addFrame",
Qt::QueuedConnection,
Q_ARG(CANFrame, tempFrame),
Q_ARG(bool, false));
framesRapid++;
if (serial == NULL) return;
@@ -275,56 +281,61 @@ 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;
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) == 1 << 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;
//qDebug() << "emit from serial handler to main form id: " << buildFrame.ID;
//if (capturing)
//{
buildFrame->isReceived = true;
model->addFrame(*buildFrame, false);
buildFrame.isReceived = true;
/* model lives in UI thread, we need to call invokeMethod */
QMetaObject::invokeMethod(model, "addFrame",
Qt::QueuedConnection,
Q_ARG(CANFrame, buildFrame),
Q_ARG(bool, false));
//take the time the frame came in and try to resync the time base.
if (continuousTimeSync) txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - (buildFrame->timestamp / 1000);
if (continuousTimeSync) txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - (buildFrame.timestamp / 1000);
framesRapid++;
//}
}
@@ -566,6 +577,64 @@ void SerialWorker::updatePortName(QString portName)
}
}
void SerialWorker::updateBusSettings(CANBus bus)
{
int busNum = bus.busNum - busBase;
if (busNum < 0) return;
if (busNum >= numBuses) return;
qDebug() << "About to update bus " << busNum << " on GVRET";
if (busNum == 0)
{
can0Baud = bus.getSpeed();
can0Baud |= 0x80000000;
if (bus.isActive())
{
can0Baud |= 0x40000000;
can0Enabled = true;
}
else can0Enabled = false;
if (bus.isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
else can0ListenOnly = false;
}
if (busNum == 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;
}
updateBaudRates(can0Baud,can1Baud);
}
/************************************/
int SerialWorker::getNumBuses()
{
return 2;
@@ -576,55 +645,4 @@ QString SerialWorker::getConnTypeName()
return QString("GVRET");
}
void SerialWorker::updateBusSettings(CAN_Bus *bus)
{
int busNum = bus->busNum - busBase;
if (busNum < 0) return;
if (busNum >= numBuses) return;
qDebug() << "About to update bus " << busNum << " on GVRET";
if (busNum == 0)
{
can0Baud = bus->getSpeed();
can0Baud |= 0x80000000;
if (bus->isActive())
{
can0Baud |= 0x40000000;
can0Enabled = true;
}
else can0Enabled = false;
if (bus->isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
else can0ListenOnly = false;
}
if (busNum == 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;
}
updateBaudRates(can0Baud,can1Baud);
}
#endif
+6 -4
View File
@@ -8,7 +8,8 @@
#include <QTimer>
#include "can_structs.h"
#include "canframemodel.h"
#include "canconnection.h"
//#include "canconnection_old.h"
namespace SERIALSTATE {
@@ -29,6 +30,7 @@ enum STATE //keep this enum synchronized with the Arduino firmware project
}
#if 0
using namespace SERIALSTATE;
class SerialWorker : public CANConnection
{
@@ -57,7 +59,7 @@ public slots:
//void stopFrameCapture(int) override;
//void startFrameCapture(int) override;
void updatePortName(QString) override; //string version of the port to connect to. This base doesnt know a thing about this value
void updateBusSettings(CAN_Bus *bus) override;
void updateBusSettings(CANBus) override;
private:
bool doValidation;
@@ -71,7 +73,7 @@ private:
int framesRapid;
STATE rx_state;
int rx_step;
CANFrame *buildFrame;
CANFrame buildFrame;
int can0Baud, can1Baud;
bool can0Enabled, can1Enabled;
bool can0ListenOnly, can1ListenOnly;
@@ -83,5 +85,5 @@ private:
void procRXChar(unsigned char);
void sendCommValidation();
};
#endif
#endif // SERIALTHREAD_H
+16
View File
@@ -0,0 +1,16 @@
QT += widgets testlib
QT -= gui
CONFIG += c++11
INCLUDEPATH += ../utils
SOURCES += \
tst_lfqueue.cpp
#HEADERS += \
# ../utils/lfqueue.h
target.path= .
INSTALLS += target
+98
View File
@@ -0,0 +1,98 @@
#include <QtTest/QtTest>
#include <QtConcurrent/qtconcurrentrun.h>
#include "lfqueue.h"
class TestLFQueue: public QObject
{
Q_OBJECT
private:
private slots:
void setSize_data();
void setSize();
void exchange_data();
void exchange();
};
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();
}
QTEST_MAIN(TestLFQueue)
#include "tst_lfqueue.moc"
+91
View File
@@ -0,0 +1,91 @@
#ifndef LFQUEUE_H
#define LFQUEUE_H
#include <QObject>
#include <QDebug>
/* macros */
#define IS_EMPTY() ( mWIdx.load() == mRIdx.load() )
#define IS_FULL() ( (mWIdx.load()+1)%mSize == mRIdx.load() )
template<class T>
class LFQueue
{
public:
LFQueue() : mSize(0), mArray(NULL){}
~LFQueue() {setSize(0);}
bool setSize(int size) {
if(size<0)
return false;
if(mArray) {
delete[] mArray;
mArray = NULL;
}
if(size>0) {
mArray = new T[size];
if(mArray)
mSize = size;
return ( mArray!=NULL );
}
return true;
}
void flush() {
mRIdx.store(0);
mWIdx.store(0);
}
T* get() {
if(IS_FULL())
return NULL;
return &(mArray[mWIdx.loadAcquire()]); /* prevent memory reordering (belt and braces) */
}
void queue() {
#ifdef QT_DEBUG
if(IS_FULL())
qCritical() << "BUG: queueing in full queue";
#endif
int wIdx = mWIdx.load();
mWIdx.storeRelease((wIdx+1)%mSize);
}
T* peek() {
if(IS_EMPTY())
return NULL;
return &(mArray[mRIdx.loadAcquire()]); /* prevent memory reordering (belt and braces) */
}
void dequeue() {
#ifdef QT_DEBUG
if(IS_EMPTY())
qCritical() << "BUG: dequeueing an empty queue";
#endif
int rIdx = mRIdx.load();
mRIdx.storeRelease((rIdx+1)%mSize);
}
private:
int mSize;
T* mArray;
QAtomicInt mRIdx;
QAtomicInt mWIdx;
};
#endif // LFQUEUE_H