From 97db24b69818f10252f42d3e20ab175deecf9c65 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:30:44 +0200 Subject: [PATCH 01/30] initial support for socketcan --- canbus.cpp | 6 ++ canbus.h | 11 +++ socketcanconnection.cpp | 157 ++++++++++++++++++++++++++++++++++++++++ socketcanconnection.h | 44 +++++++++++ 4 files changed, 218 insertions(+) create mode 100644 canbus.cpp create mode 100644 canbus.h create mode 100644 socketcanconnection.cpp create mode 100644 socketcanconnection.h diff --git a/canbus.cpp b/canbus.cpp new file mode 100644 index 0000000..882ca33 --- /dev/null +++ b/canbus.cpp @@ -0,0 +1,6 @@ +#include "canbus.h" + +CAN_Bus::CAN_Bus() +{ + +} diff --git a/canbus.h b/canbus.h new file mode 100644 index 0000000..d27d955 --- /dev/null +++ b/canbus.h @@ -0,0 +1,11 @@ +#ifndef CAN_BUS_H +#define CAN_BUS_H + + +class CAN_Bus +{ +public: + CAN_Bus(); +}; + +#endif // CAN_BUS_H \ No newline at end of file diff --git a/socketcanconnection.cpp b/socketcanconnection.cpp new file mode 100644 index 0000000..c39c7c0 --- /dev/null +++ b/socketcanconnection.cpp @@ -0,0 +1,157 @@ +#include +#include +#include + + +#include "canframemodel.h" +#include "canconnection.h" +#include "socketcanconnection.h" + +/***********************************/ +/**** nested class ****/ +/***********************************/ + + +BUSConfig::BUSConfig():isConfigured(false){} + +void BUSConfig::reset() { + isConfigured = false; +} + +bool BUSConfig::operator==(CANBus& bus) { + return isConfigured && speed == bus.speed && + listenOnly == bus.listenOnly && active == bus.active; +} + +void BUSConfig::operator=(CANBus& bus) { + isConfigured = true; + speed = bus.speed; + listenOnly = bus.listenOnly; + active = bus.active; +} + + + +/***********************************/ +/**** class definition ****/ +/***********************************/ + +SocketCanConnection::SocketCanConnection(CANFrameModel *model, int base) : CANConnection(model, base), mDev_p(NULL) +{ + qDebug() << "SocketCanConnection()"; + qRegisterMetaType("CANFrame"); +} + +SocketCanConnection::~SocketCanConnection() +{ + qDebug() << "~SocketCanConnection()"; + /* stop device */ +} + +void SocketCanConnection::updateBusSettings(CANBus bus) +{ + qDebug()<<"updateBusSettings"; + + if(mConf == bus) return; + + /* disconnect device if we have one connected */ + if(mDev_p) disconnect(); + + /* if bus is not active we are done */ + if(!bus.active) return; + + /* create device */ + mDev_p = QCanBus::instance()->createDevice("socketcan", portName); + if (!mDev_p) { + qDebug() << "can't create device"; + return; + } + + /* connect slots */ + connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SocketCanConnection::errorReceived); + connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCanConnection::framesReceived); + connect(mDev_p, &QCanBusDevice::framesWritten, this, &SocketCanConnection::framesWritten); + + /* set configuration */ + /*if (p.useConfigurationEnabled) { + foreach (const SettingsDialog::ConfigurationItem &item, p.configurations) + mDev->setConfigurationParameter(item.first, item.second); + }*/ + + /* connect device */ + if (!mDev_p->connectDevice()) { + disconnect(); + qDebug() << "can't connect device"; + } +} + + +/***********************************/ +/**** private methods ****/ +/***********************************/ + + +/* connect device */ +void SocketCanConnection::disconnect() { + if(mDev_p) { + mDev_p->disconnectDevice(); + delete mDev_p; + mDev_p = Q_NULLPTR; + } +} + + +void SocketCanConnection::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 SocketCanConnection::framesWritten(qint64 count) +{ + qDebug() << "Number of frames written:" << count; +} + +void SocketCanConnection::framesReceived() +{ + /* sanity checks */ + if(!mDev_p) return; + + /* read frame */ + while(true) + { + const QCanBusFrame recFrame = mDev_p->readFrame(); + /* exit case */ + if(!recFrame.isValid()) return; + + if(!recFrame.payload().isEmpty() && + recFrame.payload().length()<=8) + { + CANFrame frame; + frame.len = recFrame.payload().length(); + frame.bus = 0; + memcpy(frame.data, recFrame.payload().data(), frame.len); + frame.extended = false; + frame.ID = recFrame.frameId(); + frame.isReceived = true; + frame.timestamp = recFrame.timeStamp().microSeconds(); + + /* send frame */ + QMetaObject::invokeMethod(model, "addFrame", + Qt::QueuedConnection, + Q_ARG(CANFrame, frame), + Q_ARG(bool, false)); + } + else { + qDebug() << "invalid frame"; + } + } +} diff --git a/socketcanconnection.h b/socketcanconnection.h new file mode 100644 index 0000000..18f5251 --- /dev/null +++ b/socketcanconnection.h @@ -0,0 +1,44 @@ +#ifndef SOCKETCANCONNECTION_H +#define SOCKETCANCONNECTION_H + +#include +#include + +#include "canframemodel.h" +#include "canconnection.h" + +class BUSConfig { +public: + BUSConfig(); + void reset(); + bool operator ==(CANBus&); + void operator =(CANBus&); + bool isConfigured; + int speed; + bool listenOnly; + bool active; +}; + + +class SocketCanConnection : public CANConnection +{ + Q_OBJECT + +public: + SocketCanConnection(CANFrameModel *, int); + virtual ~SocketCanConnection() override; + +public slots: + virtual void updateBusSettings(CANBus) override; + +private: + void errorReceived(QCanBusDevice::CanBusError error) const; + void framesWritten(qint64 count); + void framesReceived(); + void disconnect(); + + QCanBusDevice* mDev_p; + BUSConfig mConf; +}; + +#endif // SOCKETCANCONNECTION_H From 38d3b348323d5162e66e77a0131e648b9615a0ea Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:31:49 +0200 Subject: [PATCH 02/30] mv canbus to its own file --- canbus.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++- canbus.h | 33 +++++++++++++++++++---- 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/canbus.cpp b/canbus.cpp index 882ca33..6a8b35b 100644 --- a/canbus.cpp +++ b/canbus.cpp @@ -1,6 +1,81 @@ +#include #include "canbus.h" -CAN_Bus::CAN_Bus() +CANBus::CANBus() { + speed = 250000; + listenOnly = false; + singleWire = false; + active = false; + container = Q_NULLPTR; + busNum = 0; +} +CANBus::CANBus(const CANBus& pBus) : + speed(pBus.speed), + listenOnly(pBus.listenOnly), + singleWire(pBus.singleWire), + active(pBus.active), + container(pBus.container), /* TODO: check if container is really needed */ + busNum(pBus.busNum) {} + + +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; +} + +void CANBus::setContainer(CANConnectionContainer* pContainer) +{ + container = pContainer; +} + +void CANBus::setBusNum(int num) +{ + busNum = num; +} + +int CANBus::getSpeed() +{ + return speed; +} + +int CANBus::getBusNum() +{ + return busNum; +} + +bool CANBus::isListenOnly() +{ + return listenOnly; +} + +bool CANBus::isSingleWire() +{ + return singleWire; +} + +bool CANBus::isActive() +{ + return active; +} + +CANConnectionContainer* CANBus::getContainer() +{ + return container; } diff --git a/canbus.h b/canbus.h index d27d955..a343c92 100644 --- a/canbus.h +++ b/canbus.h @@ -1,11 +1,34 @@ -#ifndef CAN_BUS_H -#define CAN_BUS_H +#ifndef CANBus_H +#define CANBus_H -class CAN_Bus +class CANConnectionContainer; + +class CANBus { public: - CAN_Bus(); + CANBus(); + CANBus(const CANBus&); + virtual ~CANBus(){}; /*TODO: remove connection from CANBus and add CANBus as an element of CANConnection */ + int busNum; + int speed; + bool listenOnly; + bool singleWire; + bool active; //is this bus turned on? + CANConnectionContainer* container; + + 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 setContainer(CANConnectionContainer *); + CANConnectionContainer* getContainer(); + void setBusNum(int); + int getSpeed(); + int getBusNum(); + bool isListenOnly(); + bool isSingleWire(); + bool isActive(); }; -#endif // CAN_BUS_H \ No newline at end of file +#endif // CANBus_H From e9f4dac3a1819a91d9caef05d4d31ed56270eed1 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:32:50 +0200 Subject: [PATCH 03/30] class to struct as the others --- can_structs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can_structs.h b/can_structs.h index 0326947..d118dc8 100644 --- a/can_structs.h +++ b/can_structs.h @@ -4,7 +4,7 @@ #include #include -class CANFrame +struct CANFrame { public: int ID; From 9ae3d4f9791401ee758a93bfe08ba93472d45958 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:34:15 +0200 Subject: [PATCH 04/30] removed can_bus and change slot from pointer to object as the object might have been deallocated when the slot is activated --- canconnection.cpp | 70 +---------------------------------------------- canconnection.h | 31 ++------------------- 2 files changed, 4 insertions(+), 97 deletions(-) diff --git a/canconnection.cpp b/canconnection.cpp index fb9ac11..70cf602 100644 --- a/canconnection.cpp +++ b/canconnection.cpp @@ -1,74 +1,6 @@ #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) { @@ -127,7 +59,7 @@ void CANConnection::startFrameCapture(int bus) } -void CANConnection::updateBusSettings(CAN_Bus *bus) +void CANConnection::updateBusSettings(CANBus bus) { } diff --git a/canconnection.h b/canconnection.h index 2a824cb..d2aa0cb 100644 --- a/canconnection.h +++ b/canconnection.h @@ -4,35 +4,9 @@ #include #include #include "can_structs.h" +#include "canbus.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. @@ -70,7 +44,8 @@ public slots: 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. + /* this is not safe to use pointers with QueuedConnection */ + virtual void updateBusSettings(CANBus); //reference to the bus that changed. protected: bool quit; From 39e07dc3a7d0e53f9055aba96f2ecd0f431810d8 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:35:00 +0200 Subject: [PATCH 05/30] fixed thread deletion --- canconnectioncontainer.cpp | 6 +++++- canconnectioncontainer.h | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/canconnectioncontainer.cpp b/canconnectioncontainer.cpp index 63a5069..302a3be 100644 --- a/canconnectioncontainer.cpp +++ b/canconnectioncontainer.cpp @@ -1,5 +1,6 @@ #include "canconnection.h" #include "canconnectioncontainer.h" +#include "mainwindow.h" CANConnectionContainer::CANConnectionContainer(CANConnection *conn) { @@ -7,7 +8,6 @@ CANConnectionContainer::CANConnectionContainer(CANConnection *conn) 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); @@ -18,6 +18,10 @@ CANConnectionContainer::CANConnectionContainer(CANConnection *conn) CANConnectionContainer::~CANConnectionContainer() { //have to stop the actual execution first before deleting + thread->quit(); + if(!thread->wait()) { + qDebug() << "can't stop thread"; + } delete thread; delete connection; } diff --git a/canconnectioncontainer.h b/canconnectioncontainer.h index 9ff2b22..8a4a429 100644 --- a/canconnectioncontainer.h +++ b/canconnectioncontainer.h @@ -1,10 +1,9 @@ #ifndef CANCONNECTIONCONTAINER_H #define CANCONNECTIONCONTAINER_H -#include "canconnection.h" #include #include -#include "mainwindow.h" +#include "canconnection.h" class CANConnectionContainer : public QObject { From 7165b113994267ac66d33ab1ff879721efba6e0e Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:36:26 +0200 Subject: [PATCH 06/30] change slot parameter from pointer to object as the object might have been deallocated when the slot is activated --- canframemodel.cpp | 3 ++- canframemodel.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index fe54877..57d542d 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -281,7 +281,8 @@ 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) { mutex.lock(); CANFrame tempFrame; diff --git a/canframemodel.h b/canframemodel.h index 7e93007..f53db11 100644 --- a/canframemodel.h +++ b/canframemodel.h @@ -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 *getFilteredListReference() const; //Thus saith the Lord, NO. const QMap *getFiltersReference() const; //this neither +public slots: + void addFrame(CANFrame, bool); + signals: void updatedFiltersList(); From 18b1a86a5658ed8082b20719c0ef01f21e3a96c2 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:45:17 +0200 Subject: [PATCH 07/30] under heavy work... --- canconnectionmodel.cpp | 31 ++++----- canconnectionmodel.h | 13 ++-- connectionwindow.cpp | 148 ++++++++++++++++++++++++++++------------- connectionwindow.h | 5 +- connectionwindow.ui | 68 ++++++++++++++++++- mainwindow.cpp | 5 +- 6 files changed, 194 insertions(+), 76 deletions(-) diff --git a/canconnectionmodel.cpp b/canconnectionmodel.cpp index 8510f8d..7ec8ca7 100644 --- a/canconnectionmodel.cpp +++ b/canconnectionmodel.cpp @@ -71,8 +71,8 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const return QVariant(); if (role == Qt::DisplayRole) { - CAN_Bus bus = buses[index.row()]; - CANConnection *conn = bus.connection; + CANBus bus = buses[index.row()]; + CANConnection *conn = bus.getContainer()->getRef(); switch (index.column()) { case 0: //bus @@ -109,35 +109,32 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const 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::addBus(CANBus &bus) { beginResetModel(); buses.append(bus); endResetModel(); } -CAN_Bus* CANConnectionModel::getBus(int bus) +void CANConnectionModel::removeBus(int busIdx) +{ + if (busIdx>=0 && busIdx < buses.count()) { + beginResetModel(); + buses.removeAt(busIdx); + endResetModel(); + } +} + +CANBus* CANConnectionModel::getBus(int bus) { if (bus < 0) return NULL; if (bus >= buses.count()) return NULL; return &buses[bus]; } -CANConnection* CANConnectionModel::getConnection(int conn) -{ - if (conn < 0) return NULL; - if (conn >= connections.count()) return NULL; - return connections[conn]->getRef(); -} -CAN_Bus* CANConnectionModel::findBusByNum(int bus) +CANBus* CANConnectionModel::findBusByNum(int bus) { for (int i = 0; i < buses.count(); i++) { diff --git a/canconnectionmodel.h b/canconnectionmodel.h index 1e0410e..22dacdc 100644 --- a/canconnectionmodel.h +++ b/canconnectionmodel.h @@ -2,6 +2,7 @@ #define CANCONNECTIONMODEL_H #include "canconnection.h" +#include "canbus.h" #include "canconnectioncontainer.h" #include @@ -23,17 +24,19 @@ public: 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); + void addConnection(CANConnectionContainer *conn); + void removeConnection(CANConnection*); + void addBus(CANBus &bus); + void removeBus(int busIdx); + CANBus* getBus(int bus); CANConnection* getConnection(int conn); void refreshView(); private: QList connections; - QList buses; + QList buses; - CAN_Bus *findBusByNum(int bus); + CANBus *findBusByNum(int bus); }; #endif // CANCONNECTIONMODEL_H diff --git a/connectionwindow.cpp b/connectionwindow.cpp index 1ee5c74..8014093 100644 --- a/connectionwindow.cpp +++ b/connectionwindow.cpp @@ -1,6 +1,10 @@ +#include + #include "connectionwindow.h" #include "ui_connectionwindow.h" -#include +#include "socketcanconnection.h" + + ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : QDialog(parent), @@ -10,7 +14,7 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : settings = new QSettings(); - qRegisterMetaType("CAN_Bus *"); + qRegisterMetaType("CANBus"); qRegisterMetaType("const CANFrame *"); qRegisterMetaType *>("const QList *"); @@ -44,7 +48,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,6 +61,7 @@ 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); @@ -102,7 +107,8 @@ void ConnectionWindow::handleConnTypeChanged() void ConnectionWindow::connectionSuccess(CANConnection *conn) { - CAN_Bus bus; +#if 0 + CANBus bus; bus.active = true; bus.busNum = conn->getBusBase(); bus.connection = conn; @@ -130,6 +136,7 @@ void ConnectionWindow::connectionSuccess(CANConnection *conn) connModel->addBus(bus); qDebug() << "Added bus " << bus.busNum; } +#endif } void ConnectionWindow::handleOKButton() @@ -141,9 +148,9 @@ void ConnectionWindow::handleOKButton() if (whichRow > -1) { - //load settings from GUI into appropriate CAN_Bus entry and then send it off to the appropriate + //load settings from GUI into appropriate CANBus entry and then send it off to the appropriate //CANConnection object - CAN_Bus *bus = connModel->getBus(whichRow); + CANBus *bus = connModel->getBus(whichRow); bus->setListenOnly(ui->ckListenOnly->isChecked()); bus->setSingleWire(ui->ckSingleWire->isChecked()); bus->setEnabled(ui->ckEnabled->isChecked()); @@ -157,9 +164,9 @@ void ConnectionWindow::handleOKButton() bus->setSpeed(ui->cbSpeed->currentText().toInt()); } //call through signal/slot interface without using connect - QMetaObject::invokeMethod(bus->connection, "updateBusSettings", + QMetaObject::invokeMethod(bus->getContainer()->getRef(), "updateBusSettings", Qt::QueuedConnection, - Q_ARG(CAN_Bus *, bus)); + Q_ARG(CANBus, *bus)); connModel->refreshView(); } else //new connection @@ -169,14 +176,15 @@ void ConnectionWindow::handleOKButton() 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 +195,7 @@ void ConnectionWindow::handleOKButton() bus.active = false; } else bus.speed = ui->cbSpeed->currentText().toInt(); + connModel->addBus(bus); int numBuses = serial->getNumBuses(); @@ -197,7 +206,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; } @@ -213,7 +222,42 @@ void ConnectionWindow::handleOKButton() } else if (ui->rbSocketCAN->isChecked()) { + /* TODO: sanity checks here */ + /* text, port, etc, ... */ + /* factorize code with other probes */ + /* create connection */ + SocketCanConnection* conn = new SocketCanConnection(canModel, 0); /* what is base? (second param) */ + + /* set port name */ + conn->updatePortName(ui->lePort->text()); + + /* add connection to a container (this creates the thread) */ + CANConnectionContainer* container = new CANConnectionContainer(conn); + + /* set bus configuration */ + CANBus bus; + bus.active = ui->ckEnabled->isChecked(); + bus.busNum = 0; // not used + bus.container = container; + 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(); + + /* add bus to model */ + connModel->addBus(bus); + + /* set bus settings (send message to thread) */ + QMetaObject::invokeMethod(conn, "updateBusSettings", + Qt::QueuedConnection, + Q_ARG(CANBus, bus)); } } } @@ -221,7 +265,7 @@ void ConnectionWindow::handleOKButton() void ConnectionWindow::receiveBusStatus(int bus, int speed, int status) { 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 { @@ -261,10 +305,10 @@ void ConnectionWindow::handleConnSelectionChanged() 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); + CANBus *bus = connModel->getBus(selIdx); + if (bus->getContainer()->getRef()->getConnTypeName() == "GVRET") ui->rbGVRET->setChecked(true); + if (bus->getContainer()->getRef()->getConnTypeName() == "KVASER") ui->rbKvaser->setChecked(true); + if (bus->getContainer()->getRef()->getConnTypeName() == "SOCKETCAN") ui->rbSocketCAN->setChecked(true); ui->ckListenOnly->setChecked(bus->isListenOnly()); ui->ckSingleWire->setChecked(bus->isSingleWire()); ui->ckEnabled->setChecked(bus->isActive()); @@ -273,8 +317,12 @@ void ConnectionWindow::handleConnSelectionChanged() } } +/*TODO: rename the 3 following functions */ void ConnectionWindow::getSerialPorts() { + /* set combobox page visible */ + ui->stPort->setCurrentWidget(ui->cbPage); + ui->cbPort->clear(); ports = QSerialPortInfo::availablePorts(); @@ -287,26 +335,17 @@ void ConnectionWindow::getSerialPorts() void ConnectionWindow::getKvaserPorts() { - +#ifdef Q_OS_WIN + /* set combobox page visible */ + ui->stPort->setCurrentWidget(ui->cbPage); +#endif } void ConnectionWindow::getSocketcanPorts() { #ifdef Q_OS_LINUX - QList interfaces = QNetworkInterface::allInterfaces(); - QString interfaceName; - - ui->cbPort->clear(); - - foreach (QNetworkInterface interface, interfaces) - { - interfaceName = interface.name().toLower(); - qDebug() << "Interface: " << interface.name(); - if (interfaceName.contains("can")) - { - ui->cbPort->addItem(interfaceName); - } - } + /* set edit text page visible */ + ui->stPort->setCurrentWidget(ui->etPage); #endif } @@ -378,7 +417,22 @@ bool ConnectionWindow::getSWMode() void ConnectionWindow::handleRemoveConn() { +#if 0 + int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); + if (selIdx <=0) return; + CANBus* bus = conModel->getBus(selIdx); + if(!bus) return; + + /* remove connection to model (this creates the thread) */ + connModel->removeConnection(bus->connection); + + /* remove connection and reset model */ + conModel->removeBus(selIdx); + qDebug() << "remove connection at index: " << selIdx; + + selIdx +#endif } void ConnectionWindow::handleRevert() @@ -386,21 +440,11 @@ void ConnectionWindow::handleRevert() } -void ConnectionWindow::handleEnableAll() -{ - -} - -void ConnectionWindow::handleDisableAll() -{ - -} - void ConnectionWindow::sendFrame(const CANFrame *frame) { - CAN_Bus *bus = connModel->getBus(frame->bus); + 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)); } @@ -408,9 +452,21 @@ void ConnectionWindow::sendFrame(const CANFrame *frame) void ConnectionWindow::sendFrameBatch(const QList *frames) { 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 *, frames)); } + +bool ConnectionWindow::isSocketCanAvailable() +{ +#ifdef Q_OS_LINUX + foreach (const QByteArray &backend, QCanBus::instance()->plugins()) { + if (backend == "socketcan") { + return true; + } + } +#endif + return false; +} diff --git a/connectionwindow.h b/connectionwindow.h index 6d91216..5b0d9c0 100644 --- a/connectionwindow.h +++ b/connectionwindow.h @@ -40,7 +40,7 @@ public: bool getSWMode(); signals: - void updateBusSettings(CAN_Bus *bus); + void updateBusSettings(CANBus *bus); void updatePortName(QString port); public slots: @@ -58,8 +58,6 @@ private slots: void handleDisableAll(); void handleRevert(); void handleNewConn(); - void handleEnableAll(); - void handleDisableAll(); void receiveBusStatus(int bus, int speed, int status); void connectionSuccess(CANConnection *conn); @@ -74,6 +72,7 @@ private: void getSerialPorts(); void getKvaserPorts(); void getSocketcanPorts(); + bool isSocketCanAvailable(); }; #endif // CONNECTIONWINDOW_H diff --git a/connectionwindow.ui b/connectionwindow.ui index f157991..f3a5b39 100644 --- a/connectionwindow.ui +++ b/connectionwindow.ui @@ -6,8 +6,8 @@ 0 0 - 1009 - 433 + 956 + 527 @@ -129,7 +129,69 @@ - + + + + 0 + 0 + + + + + 0 + 22 + + + + Qt::LeftToRight + + + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + + + + + 0 + 0 + + + + + 341 + 16777215 + + + + + + + + + + + + + 0 + 0 + + + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index 07aa433..68e27c0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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(); @@ -510,7 +511,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(); From 64079e8dcf6c02a84779132ab2548fc7d156e026 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:46:07 +0200 Subject: [PATCH 08/30] slight changes due to change of pointer for object --- serialworker.cpp | 76 +++++++++++++++++++++++++++--------------------- serialworker.h | 5 ++-- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/serialworker.cpp b/serialworker.cpp index 36c26e7..281c050 100644 --- a/serialworker.cpp +++ b/serialworker.cpp @@ -11,7 +11,7 @@ SerialWorker::SerialWorker(CANFrameModel *model, int base) : CANConnection(model serial = NULL; rx_state = IDLE; rx_step = 0; - buildFrame = new CANFrame; + buildFrame; ticker = NULL; framesRapid = 0; gotValidated = true; @@ -166,8 +166,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 +280,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++; //} } @@ -576,24 +586,24 @@ QString SerialWorker::getConnTypeName() return QString("GVRET"); } -void SerialWorker::updateBusSettings(CAN_Bus *bus) +void SerialWorker::updateBusSettings(CANBus bus) { - int busNum = bus->busNum - busBase; + 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 = bus.getSpeed(); can0Baud |= 0x80000000; - if (bus->isActive()) + if (bus.isActive()) { can0Baud |= 0x40000000; can0Enabled = true; } else can0Enabled = false; - if (bus->isListenOnly()) + if (bus.isListenOnly()) { can0Baud |= 0x20000000; can0ListenOnly = true; @@ -602,23 +612,23 @@ void SerialWorker::updateBusSettings(CAN_Bus *bus) } if (busNum == 1) { - can1Baud = bus->getSpeed(); + can1Baud = bus.getSpeed(); can1Baud |= 0x80000000; - if (bus->isActive()) + if (bus.isActive()) { can1Baud |= 0x40000000; can1Enabled = true; } else can1Enabled = false; - if (bus->isListenOnly()) + if (bus.isListenOnly()) { can1Baud |= 0x20000000; can1ListenOnly = true; } else can1ListenOnly = false; - if (bus->isSingleWire()) + if (bus.isSingleWire()) { can1Baud |= 0x10000000; deviceSingleWireMode = 1; diff --git a/serialworker.h b/serialworker.h index 9505281..f9e57ec 100644 --- a/serialworker.h +++ b/serialworker.h @@ -10,6 +10,7 @@ #include "canframemodel.h" #include "canconnection.h" + namespace SERIALSTATE { enum STATE //keep this enum synchronized with the Arduino firmware project @@ -57,7 +58,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 +72,7 @@ private: int framesRapid; STATE rx_state; int rx_step; - CANFrame *buildFrame; + CANFrame buildFrame; int can0Baud, can1Baud; bool can0Enabled, can1Enabled; bool can0ListenOnly, can1ListenOnly; From f36d432b501356facacae66dafa3bc731a4e81e9 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 8 Jun 2016 11:51:54 +0200 Subject: [PATCH 09/30] update .pro --- SavvyCAN.pro | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/SavvyCAN.pro b/SavvyCAN.pro index ef81cb2..5dcd015 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui +QT += core gui serialbus greaterThan(QT_MAJOR_VERSION, 4): QT += widgets serialport printsupport qml @@ -51,7 +51,9 @@ SOURCES += main.cpp\ isotp_handler.cpp \ canconnectionmodel.cpp \ canconnection.cpp \ - canconnectioncontainer.cpp + canconnectioncontainer.cpp \ + socketcanconnection.cpp \ + canbus.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -89,7 +91,9 @@ HEADERS += mainwindow.h \ isotp_handler.h \ canconnectionmodel.h \ canconnection.h \ - canconnectioncontainer.h + canconnectioncontainer.h \ + socketcanconnection.h \ + canbus.h FORMS += mainwindow.ui \ graphingwindow.ui \ From 80719b253b8ae4490ca796bba7d81dc7021ff6e6 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:18:56 +0200 Subject: [PATCH 10/30] add lock free queue --- canconnection.cpp => canconnection_old.cpp | 0 canconnection.h => canconnection_old.h | 0 connections/canconconst.h | 4 + connections/canconfactory.cpp | 6 + connections/canconfactory.h | 11 ++ connections/canconnection.cpp | 6 + connections/canconnection.h | 11 ++ connections/gvretserial.cpp | 6 + connections/gvretserial.h | 11 ++ connections/socketcan.cpp | 157 +++++++++++++++++++++ connections/socketcan.h | 44 ++++++ test/test.pro | 12 ++ test/tst_lfqueue.cpp | 8 ++ utils/lfqueue.h | 91 ++++++++++++ 14 files changed, 367 insertions(+) rename canconnection.cpp => canconnection_old.cpp (100%) rename canconnection.h => canconnection_old.h (100%) create mode 100644 connections/canconconst.h create mode 100644 connections/canconfactory.cpp create mode 100644 connections/canconfactory.h create mode 100644 connections/canconnection.cpp create mode 100644 connections/canconnection.h create mode 100644 connections/gvretserial.cpp create mode 100644 connections/gvretserial.h create mode 100644 connections/socketcan.cpp create mode 100644 connections/socketcan.h create mode 100644 test/test.pro create mode 100644 test/tst_lfqueue.cpp create mode 100644 utils/lfqueue.h diff --git a/canconnection.cpp b/canconnection_old.cpp similarity index 100% rename from canconnection.cpp rename to canconnection_old.cpp diff --git a/canconnection.h b/canconnection_old.h similarity index 100% rename from canconnection.h rename to canconnection_old.h diff --git a/connections/canconconst.h b/connections/canconconst.h new file mode 100644 index 0000000..73cf76a --- /dev/null +++ b/connections/canconconst.h @@ -0,0 +1,4 @@ +#ifndef CANCONCONST_H +#define CANCONCONST_H + +#endif // CANCONCONST_H diff --git a/connections/canconfactory.cpp b/connections/canconfactory.cpp new file mode 100644 index 0000000..54095ab --- /dev/null +++ b/connections/canconfactory.cpp @@ -0,0 +1,6 @@ +#include "canconfactory.h" + +CanConFactory::CanConFactory() +{ + +} diff --git a/connections/canconfactory.h b/connections/canconfactory.h new file mode 100644 index 0000000..a2d8cbc --- /dev/null +++ b/connections/canconfactory.h @@ -0,0 +1,11 @@ +#ifndef CANCONFACTORY_H +#define CANCONFACTORY_H + + +class CanConFactory +{ +public: + CanConFactory(); +}; + +#endif // CANCONFACTORY_H \ No newline at end of file diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp new file mode 100644 index 0000000..8d3d73c --- /dev/null +++ b/connections/canconnection.cpp @@ -0,0 +1,6 @@ +#include "canconnection.h" + +CanConnection::CanConnection() +{ + +} diff --git a/connections/canconnection.h b/connections/canconnection.h new file mode 100644 index 0000000..8d740b7 --- /dev/null +++ b/connections/canconnection.h @@ -0,0 +1,11 @@ +#ifndef CANCONNECTION_H +#define CANCONNECTION_H + + +class CanConnection +{ +public: + CanConnection(); +}; + +#endif // CANCONNECTION_H \ No newline at end of file diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp new file mode 100644 index 0000000..6e163d7 --- /dev/null +++ b/connections/gvretserial.cpp @@ -0,0 +1,6 @@ +#include "cvretserial.h" + +CVRetSerial::CVRetSerial() +{ + +} diff --git a/connections/gvretserial.h b/connections/gvretserial.h new file mode 100644 index 0000000..12857c0 --- /dev/null +++ b/connections/gvretserial.h @@ -0,0 +1,11 @@ +#ifndef CVRETSERIAL_H +#define CVRETSERIAL_H + + +class CVRetSerial +{ +public: + CVRetSerial(); +}; + +#endif // CVRETSERIAL_H \ No newline at end of file diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp new file mode 100644 index 0000000..94eb4b7 --- /dev/null +++ b/connections/socketcan.cpp @@ -0,0 +1,157 @@ +#include +#include +#include + + +#include "canframemodel.h" +#include "canconnection_old.h" +#include "socketcanconnection.h" + +/***********************************/ +/**** nested class ****/ +/***********************************/ + + +BUSConfig::BUSConfig():isConfigured(false){} + +void BUSConfig::reset() { + isConfigured = false; +} + +bool BUSConfig::operator==(CANBus& bus) { + return isConfigured && speed == bus.speed && + listenOnly == bus.listenOnly && active == bus.active; +} + +void BUSConfig::operator=(CANBus& bus) { + isConfigured = true; + speed = bus.speed; + listenOnly = bus.listenOnly; + active = bus.active; +} + + + +/***********************************/ +/**** class definition ****/ +/***********************************/ + +SocketCanConnection::SocketCanConnection(CANFrameModel *model, int base) : CANConnection(model, base), mDev_p(NULL) +{ + qDebug() << "SocketCanConnection()"; + qRegisterMetaType("CANFrame"); +} + +SocketCanConnection::~SocketCanConnection() +{ + qDebug() << "~SocketCanConnection()"; + /* stop device */ +} + +void SocketCanConnection::updateBusSettings(CANBus bus) +{ + qDebug()<<"updateBusSettings"; + + if(mConf == bus) return; + + /* disconnect device if we have one connected */ + if(mDev_p) disconnect(); + + /* if bus is not active we are done */ + if(!bus.active) return; + + /* create device */ + mDev_p = QCanBus::instance()->createDevice("socketcan", portName); + if (!mDev_p) { + qDebug() << "can't create device"; + return; + } + + /* connect slots */ + connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SocketCanConnection::errorReceived); + connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCanConnection::framesReceived); + connect(mDev_p, &QCanBusDevice::framesWritten, this, &SocketCanConnection::framesWritten); + + /* set configuration */ + /*if (p.useConfigurationEnabled) { + foreach (const SettingsDialog::ConfigurationItem &item, p.configurations) + mDev->setConfigurationParameter(item.first, item.second); + }*/ + + /* connect device */ + if (!mDev_p->connectDevice()) { + disconnect(); + qDebug() << "can't connect device"; + } +} + + +/***********************************/ +/**** private methods ****/ +/***********************************/ + + +/* connect device */ +void SocketCanConnection::disconnect() { + if(mDev_p) { + mDev_p->disconnectDevice(); + delete mDev_p; + mDev_p = Q_NULLPTR; + } +} + + +void SocketCanConnection::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 SocketCanConnection::framesWritten(qint64 count) +{ + qDebug() << "Number of frames written:" << count; +} + +void SocketCanConnection::framesReceived() +{ + /* sanity checks */ + if(!mDev_p) return; + + /* read frame */ + while(true) + { + const QCanBusFrame recFrame = mDev_p->readFrame(); + /* exit case */ + if(!recFrame.isValid()) return; + + if(!recFrame.payload().isEmpty() && + recFrame.payload().length()<=8) + { + CANFrame frame; + frame.len = recFrame.payload().length(); + frame.bus = 0; + memcpy(frame.data, recFrame.payload().data(), frame.len); + frame.extended = false; + frame.ID = recFrame.frameId(); + frame.isReceived = true; + frame.timestamp = recFrame.timeStamp().microSeconds(); + + /* send frame */ + QMetaObject::invokeMethod(model, "addFrame", + Qt::QueuedConnection, + Q_ARG(CANFrame, frame), + Q_ARG(bool, false)); + } + else { + qDebug() << "invalid frame"; + } + } +} diff --git a/connections/socketcan.h b/connections/socketcan.h new file mode 100644 index 0000000..1662501 --- /dev/null +++ b/connections/socketcan.h @@ -0,0 +1,44 @@ +#ifndef SOCKETCANCONNECTION_H +#define SOCKETCANCONNECTION_H + +#include +#include + +#include "canframemodel.h" +#include "canconnection_old.h" + +class BUSConfig { +public: + BUSConfig(); + void reset(); + bool operator ==(CANBus&); + void operator =(CANBus&); + bool isConfigured; + int speed; + bool listenOnly; + bool active; +}; + + +class SocketCanConnection : public CANConnection +{ + Q_OBJECT + +public: + SocketCanConnection(CANFrameModel *, int); + virtual ~SocketCanConnection() override; + +public slots: + virtual void updateBusSettings(CANBus) override; + +private: + void errorReceived(QCanBusDevice::CanBusError error) const; + void framesWritten(qint64 count); + void framesReceived(); + void disconnect(); + + QCanBusDevice* mDev_p; + BUSConfig mConf; +}; + +#endif // SOCKETCANCONNECTION_H diff --git a/test/test.pro b/test/test.pro new file mode 100644 index 0000000..58486c6 --- /dev/null +++ b/test/test.pro @@ -0,0 +1,12 @@ +QT += core +QT -= gui + +CONFIG += c++11 + +TARGET = test +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += main.cpp diff --git a/test/tst_lfqueue.cpp b/test/tst_lfqueue.cpp new file mode 100644 index 0000000..470a030 --- /dev/null +++ b/test/tst_lfqueue.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + return a.exec(); +} diff --git a/utils/lfqueue.h b/utils/lfqueue.h new file mode 100644 index 0000000..8a7d6d0 --- /dev/null +++ b/utils/lfqueue.h @@ -0,0 +1,91 @@ +#ifndef LFQUEUE_H +#define LFQUEUE_H + +#include +#include + + +/* macros */ +#define IS_EMPTY() ( mWIdx.load() == mRIdx.load() ) +#define IS_FULL() ( (mWIdx.load()+1)%mSize == mRIdx.load() ) + + +template +class LFQueue +{ +public: + LFQueue() : mSize(0), mArray(NULL){} + + ~LFQueue() {setSize(0);} + + bool setSize(int size) { + if(size<0) + return false; + + if(mArray) { + delete[] mArray; + mArray = NULL; + } + + if(size>0) { + mArray = new T[size]; + if(mArray) + mSize = size; + return ( mArray!=NULL ); + } + + return true; + } + + void flush() { + mRIdx.store(0); + mWIdx.store(0); + } + + T* get() { + if(IS_FULL()) + return NULL; + + return &(mArray[mWIdx.loadAcquire()]); /* prevent memory reordering (belt and braces) */ + } + + + void queue() { + #ifdef QT_DEBUG + if(IS_FULL()) + qCritical() << "BUG: queueing in full queue"; + #endif + + int wIdx = mWIdx.load(); + mWIdx.storeRelease((wIdx+1)%mSize); + } + + + T* peek() { + if(IS_EMPTY()) + return NULL; + + return &(mArray[mRIdx.loadAcquire()]); /* prevent memory reordering (belt and braces) */ + } + + + void dequeue() { + #ifdef QT_DEBUG + if(IS_EMPTY()) + qCritical() << "BUG: dequeueing an empty queue"; + #endif + + int rIdx = mRIdx.load(); + mRIdx.storeRelease((rIdx+1)%mSize); + } + + +private: + int mSize; + T* mArray; + + QAtomicInt mRIdx; + QAtomicInt mWIdx; +}; + +#endif // LFQUEUE_H From b83af0cfbde2d7e32c8bf78dfaffbb0dc2098a01 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:20:26 +0200 Subject: [PATCH 11/30] removed old files --- canconnection_old.cpp | 65 ------------------------------------------- canconnection_old.h | 60 --------------------------------------- 2 files changed, 125 deletions(-) delete mode 100644 canconnection_old.cpp delete mode 100644 canconnection_old.h diff --git a/canconnection_old.cpp b/canconnection_old.cpp deleted file mode 100644 index 70cf602..0000000 --- a/canconnection_old.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "canconnection.h" - - - -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 *frames) -{ - -} - -void CANConnection::updatePortName(QString portName) -{ - this->portName = portName; -} - -void CANConnection::stopFrameCapture(int bus) -{ - -} - -void CANConnection::startFrameCapture(int bus) -{ - -} - -void CANConnection::updateBusSettings(CANBus bus) -{ - -} diff --git a/canconnection_old.h b/canconnection_old.h deleted file mode 100644 index d2aa0cb..0000000 --- a/canconnection_old.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef CANCONNECTION_H -#define CANCONNECTION_H - -#include -#include -#include "can_structs.h" -#include "canbus.h" -#include "canframemodel.h" - - -//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 *); - 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 - /* this is not safe to use pointers with QueuedConnection */ - virtual void updateBusSettings(CANBus); //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 From 7192e11f38c095fa7edb09d9954121eaf490c9c6 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:21:41 +0200 Subject: [PATCH 12/30] removed old socketcanconnection --- socketcanconnection.cpp | 157 ---------------------------------------- socketcanconnection.h | 44 ----------- 2 files changed, 201 deletions(-) delete mode 100644 socketcanconnection.cpp delete mode 100644 socketcanconnection.h diff --git a/socketcanconnection.cpp b/socketcanconnection.cpp deleted file mode 100644 index c39c7c0..0000000 --- a/socketcanconnection.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include -#include -#include - - -#include "canframemodel.h" -#include "canconnection.h" -#include "socketcanconnection.h" - -/***********************************/ -/**** nested class ****/ -/***********************************/ - - -BUSConfig::BUSConfig():isConfigured(false){} - -void BUSConfig::reset() { - isConfigured = false; -} - -bool BUSConfig::operator==(CANBus& bus) { - return isConfigured && speed == bus.speed && - listenOnly == bus.listenOnly && active == bus.active; -} - -void BUSConfig::operator=(CANBus& bus) { - isConfigured = true; - speed = bus.speed; - listenOnly = bus.listenOnly; - active = bus.active; -} - - - -/***********************************/ -/**** class definition ****/ -/***********************************/ - -SocketCanConnection::SocketCanConnection(CANFrameModel *model, int base) : CANConnection(model, base), mDev_p(NULL) -{ - qDebug() << "SocketCanConnection()"; - qRegisterMetaType("CANFrame"); -} - -SocketCanConnection::~SocketCanConnection() -{ - qDebug() << "~SocketCanConnection()"; - /* stop device */ -} - -void SocketCanConnection::updateBusSettings(CANBus bus) -{ - qDebug()<<"updateBusSettings"; - - if(mConf == bus) return; - - /* disconnect device if we have one connected */ - if(mDev_p) disconnect(); - - /* if bus is not active we are done */ - if(!bus.active) return; - - /* create device */ - mDev_p = QCanBus::instance()->createDevice("socketcan", portName); - if (!mDev_p) { - qDebug() << "can't create device"; - return; - } - - /* connect slots */ - connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SocketCanConnection::errorReceived); - connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCanConnection::framesReceived); - connect(mDev_p, &QCanBusDevice::framesWritten, this, &SocketCanConnection::framesWritten); - - /* set configuration */ - /*if (p.useConfigurationEnabled) { - foreach (const SettingsDialog::ConfigurationItem &item, p.configurations) - mDev->setConfigurationParameter(item.first, item.second); - }*/ - - /* connect device */ - if (!mDev_p->connectDevice()) { - disconnect(); - qDebug() << "can't connect device"; - } -} - - -/***********************************/ -/**** private methods ****/ -/***********************************/ - - -/* connect device */ -void SocketCanConnection::disconnect() { - if(mDev_p) { - mDev_p->disconnectDevice(); - delete mDev_p; - mDev_p = Q_NULLPTR; - } -} - - -void SocketCanConnection::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 SocketCanConnection::framesWritten(qint64 count) -{ - qDebug() << "Number of frames written:" << count; -} - -void SocketCanConnection::framesReceived() -{ - /* sanity checks */ - if(!mDev_p) return; - - /* read frame */ - while(true) - { - const QCanBusFrame recFrame = mDev_p->readFrame(); - /* exit case */ - if(!recFrame.isValid()) return; - - if(!recFrame.payload().isEmpty() && - recFrame.payload().length()<=8) - { - CANFrame frame; - frame.len = recFrame.payload().length(); - frame.bus = 0; - memcpy(frame.data, recFrame.payload().data(), frame.len); - frame.extended = false; - frame.ID = recFrame.frameId(); - frame.isReceived = true; - frame.timestamp = recFrame.timeStamp().microSeconds(); - - /* send frame */ - QMetaObject::invokeMethod(model, "addFrame", - Qt::QueuedConnection, - Q_ARG(CANFrame, frame), - Q_ARG(bool, false)); - } - else { - qDebug() << "invalid frame"; - } - } -} diff --git a/socketcanconnection.h b/socketcanconnection.h deleted file mode 100644 index 18f5251..0000000 --- a/socketcanconnection.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef SOCKETCANCONNECTION_H -#define SOCKETCANCONNECTION_H - -#include -#include - -#include "canframemodel.h" -#include "canconnection.h" - -class BUSConfig { -public: - BUSConfig(); - void reset(); - bool operator ==(CANBus&); - void operator =(CANBus&); - bool isConfigured; - int speed; - bool listenOnly; - bool active; -}; - - -class SocketCanConnection : public CANConnection -{ - Q_OBJECT - -public: - SocketCanConnection(CANFrameModel *, int); - virtual ~SocketCanConnection() override; - -public slots: - virtual void updateBusSettings(CANBus) override; - -private: - void errorReceived(QCanBusDevice::CanBusError error) const; - void framesWritten(qint64 count); - void framesReceived(); - void disconnect(); - - QCanBusDevice* mDev_p; - BUSConfig mConf; -}; - -#endif // SOCKETCANCONNECTION_H From 4553dd59ee19c9785fae7a2804b8898acc63118c Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:22:39 +0200 Subject: [PATCH 13/30] new connection interface --- connections/canconconst.h | 20 ++++ connections/canconnection.cpp | 99 +++++++++++++++++- connections/canconnection.h | 186 +++++++++++++++++++++++++++++++++- 3 files changed, 301 insertions(+), 4 deletions(-) diff --git a/connections/canconconst.h b/connections/canconconst.h index 73cf76a..707355d 100644 --- a/connections/canconconst.h +++ b/connections/canconconst.h @@ -1,4 +1,24 @@ #ifndef CANCONCONST_H #define CANCONCONST_H +namespace CANCon { + + /** + * @brief The status enum + */ + enum status + { + NOT_CONNECTED, /*!< device is not connected */ + CONNECTED /*!< device is connected */ + }; + + enum type + { + GVRET_SERIAL, + KVASER, + SOCKETCAN, + NONE + }; +} + #endif // CANCONCONST_H diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 8d3d73c..b3059b8 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -1,6 +1,103 @@ #include "canconnection.h" -CanConnection::CanConnection() +CANConnection::CANConnection(QString pPort, CANCon::type pType, int pNumBuses) : + mQueue(), + mNumBuses(pNumBuses), + mPort(pPort), + mType(pType), + mIsCapSuspended(false), + mStatus(CANCon::NOT_CONNECTED) { + qDebug() << "CANConnection()"; + /* register types */ + qRegisterMetaType("CANBus"); + qRegisterMetaType("CANCon::status"); + + mBus = new CANBus[mNumBuses]; + mConfigured = new bool[mNumBuses]; + + for(int i=0 ; i= 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& 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; +} + diff --git a/connections/canconnection.h b/connections/canconnection.h index 8d740b7..5c9c68f 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -1,11 +1,191 @@ #ifndef CANCONNECTION_H #define CANCONNECTION_H +#include +#include +#include "utils/lfqueue.h" +#include "can_structs.h" +#include "canbus.h" +#include "canconconst.h" -class CanConnection + +class CANConnection : public QObject { + Q_OBJECT + public: - CanConnection(); + + /** + * @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 + */ + CANConnection(QString pPort, CANCon::type pType, int pNumBuses); + /** + * @brief CANConnection destructor + */ + + virtual ~CANConnection(); + + /** + * @brief getNumBuses + * @return returns the number of buses of the device + * @note multithread safe + */ + int getNumBuses(); + + /** + * @brief getPort + * @return returns the port name of the device + * @note multithread safe + */ + QString getPort(); + + /** + * @brief getQueue is call by reader to get a reference on the queue to monitor + * @return the lock free queue of the device + * @note multithread safe + */ + LFQueue& getQueue(); + + /** + * @brief getType + * @return the @ref CANCon::type of the device + * @note multithread safe + */ + CANCon::type getType(); + + /** + * @brief getStatus + * @return the @ref CANCon::status of the device (either connected or not) + * @note multithread safe + */ + CANCon::status getStatus(); + + /** + * @brief start the device + * @note start a working thread here if needed + */ + virtual void start() = 0; + + /** + * @brief stop the device + * @note stop the working thread here if one has been started + */ + virtual void stop() = 0; + + +signals: + 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 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: + + virtual void sendFrame(const CANFrame *) = 0; + virtual void sendFrameBatch(const QList *) = 0; + + /** + * @brief setBusSettings + * @param pBusIdx: the index of the bus for which settings have to be set + * @param pBus: the settings to set + */ + virtual void setBusSettings(int pBusIdx, CANBus pBus) = 0; + + /** + * @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 + */ + virtual bool getBusSettings(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 suspend(bool pSuspend) = 0; + +protected: + + /** + * @brief setStatus + * @param pStatus: the status to set + * @note multithread safe (can be used while another thread calls @ref getStatus) + */ + void setStatus(CANCon::status pStatus); + + /** + * @brief isConfigured + * @param pBusId + * @return true if bus is configured + * @note NOT multithread safe + */ + 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 + * @note NOT multithread safe + */ + 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 + * @note NOT multithread safe + */ + 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 + * @note NOT multithread safe + */ + void setBusConfig(int pBusId, CANBus& pBus); + + /** + * @brief isCapSuspended + * @return true if the capture is suspended + * @note NOT multithread safe + */ + bool isCapSuspended(); + + /** + * @brief setCapSuspended + * @param pIsSuspended + * @note NOT multithread safe + */ + void setCapSuspended(bool pIsSuspended); + +private: + CANBus* mBus; + bool* mConfigured; + LFQueue mQueue; + const int mNumBuses; + const QString mPort; + const CANCon::type mType; + bool mIsCapSuspended; + QAtomicInt mStatus; }; -#endif // CANCONNECTION_H \ No newline at end of file +#endif // CANCONNECTION_H From cdff06ebe31bd1eaf0cf0448b54c089e99007502 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:23:21 +0200 Subject: [PATCH 14/30] new socketcan connection --- connections/socketcan.cpp | 221 ++++++++++++++++++++++++++++---------- connections/socketcan.h | 62 +++++++---- 2 files changed, 203 insertions(+), 80 deletions(-) diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 94eb4b7..76b6fe3 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -2,33 +2,7 @@ #include #include - -#include "canframemodel.h" -#include "canconnection_old.h" -#include "socketcanconnection.h" - -/***********************************/ -/**** nested class ****/ -/***********************************/ - - -BUSConfig::BUSConfig():isConfigured(false){} - -void BUSConfig::reset() { - isConfigured = false; -} - -bool BUSConfig::operator==(CANBus& bus) { - return isConfigured && speed == bus.speed && - listenOnly == bus.listenOnly && active == bus.active; -} - -void BUSConfig::operator=(CANBus& bus) { - isConfigured = true; - speed = bus.speed; - listenOnly = bus.listenOnly; - active = bus.active; -} +#include "socketcan.h" @@ -36,41 +10,120 @@ void BUSConfig::operator=(CANBus& bus) { /**** class definition ****/ /***********************************/ -SocketCanConnection::SocketCanConnection(CANFrameModel *model, int base) : CANConnection(model, base), mDev_p(NULL) +SocketCanConnection::SocketCanConnection(QString portName) : + CANConnection(portName, CANCon::SOCKETCAN, 1), + mDev_p(NULL), + mThread(NULL) { + getQueue().setSize(2000); /*TODO add check on returned value */ + /* move ourself to the thread */ + moveToThread(&mThread); + qDebug() << "SocketCanConnection()"; - qRegisterMetaType("CANFrame"); } + SocketCanConnection::~SocketCanConnection() { + stop(); qDebug() << "~SocketCanConnection()"; - /* stop device */ } -void SocketCanConnection::updateBusSettings(CANBus bus) -{ - qDebug()<<"updateBusSettings"; - if(mConf == bus) return; +void SocketCanConnection::start() { + + qDebug() << "enter thread"; + mThread.start(QThread::HighPriority); + + connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection())); + mTimer.setInterval(1000); + mTimer.setSingleShot(false); //keep ticking + mTimer.start(); +} + + +void SocketCanConnection::suspend(bool pSuspend) { + /* make sure we execute in mThread context */ + if(QThread::currentThread() != &mThread) { + QMetaObject::invokeMethod(this, "suspend", + Qt::BlockingQueuedConnection, + Q_ARG(bool, pSuspend)); + return; + } + + /* update capSuspended */ + setCapSuspended(pSuspend); + + /* flush queue if we are suspended */ + if(isCapSuspended()) + getQueue().flush(); +} + + +void SocketCanConnection::stop() { + mTimer.stop(); + mThread.quit(); + if(!mThread.wait()) { + qDebug() << "can't stop thread"; + } + disconnectDevice(); +} + + +bool SocketCanConnection::getBusSettings(int pBusIdx, CANBus& pBus) { + /* make sure we execute in mThread context */ + if(QThread::currentThread() != &mThread) { + bool ret; + QMetaObject::invokeMethod(this, "getBusSettings", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int , pBusIdx), + Q_ARG(CANBus& , pBus)); + return ret; + } + + return getBusConfig(pBusIdx, pBus); +} + + +void SocketCanConnection::setBusSettings(int pBusIdx, CANBus bus) +{ + /* make sure we execute in mThread context */ + if(QThread::currentThread() != &mThread) { + QMetaObject::invokeMethod(this, "setBusSettings", + Qt::BlockingQueuedConnection, + Q_ARG(int, pBusIdx), + Q_ARG(CANBus, bus)); + return; + } + + /* sanity checks */ + if(0 != pBusIdx) + return; /* disconnect device if we have one connected */ - if(mDev_p) disconnect(); + if(mDev_p) + disconnectDevice(); + + /* copy bus config */ + setBusConfig(0, bus); /* if bus is not active we are done */ - if(!bus.active) return; + if(!bus.active) + return; /* create device */ - mDev_p = QCanBus::instance()->createDevice("socketcan", portName); + mDev_p = QCanBus::instance()->createDevice("socketcan", getPort()); if (!mDev_p) { - qDebug() << "can't create device"; - return; + disconnectDevice(); + qDebug() << "can't create device"; + return; } /* connect slots */ connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SocketCanConnection::errorReceived); - connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCanConnection::framesReceived); connect(mDev_p, &QCanBusDevice::framesWritten, this, &SocketCanConnection::framesWritten); + connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCanConnection::framesReceived); /* set configuration */ /*if (p.useConfigurationEnabled) { @@ -80,19 +133,23 @@ void SocketCanConnection::updateBusSettings(CANBus bus) /* connect device */ if (!mDev_p->connectDevice()) { - disconnect(); + disconnectDevice(); qDebug() << "can't connect device"; } } +void SocketCanConnection::sendFrame(const CANFrame *) {} +void SocketCanConnection::sendFrameBatch(const QList *){} + + /***********************************/ /**** private methods ****/ /***********************************/ -/* connect device */ -void SocketCanConnection::disconnect() { +/* disconnect device */ +void SocketCanConnection::disconnectDevice() { if(mDev_p) { mDev_p->disconnectDevice(); delete mDev_p; @@ -123,35 +180,81 @@ void SocketCanConnection::framesWritten(qint64 count) void SocketCanConnection::framesReceived() { /* sanity checks */ - if(!mDev_p) return; + if(!mDev_p) + return; /* read frame */ while(true) { const QCanBusFrame recFrame = mDev_p->readFrame(); - /* exit case */ - if(!recFrame.isValid()) return; + /* 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; - frame.len = recFrame.payload().length(); - frame.bus = 0; - memcpy(frame.data, recFrame.payload().data(), frame.len); - frame.extended = false; - frame.ID = recFrame.frameId(); - frame.isReceived = true; - frame.timestamp = recFrame.timeStamp().microSeconds(); + 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(); - /* send frame */ - QMetaObject::invokeMethod(model, "addFrame", - Qt::QueuedConnection, - Q_ARG(CANFrame, frame), - Q_ARG(bool, false)); + /* enqueue frame */ + getQueue().queue(); + } + else + qDebug() << "can't get a frame, ERROR"; } else { qDebug() << "invalid frame"; } } } + + +void SocketCanConnection::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()) { + + /* try to reconnect */ + CANBus bus; + if(getBusConfig(0, bus)) + setBusSettings(0, bus); + + /* disconnect test instance */ + dev_p->disconnectDevice(); + + setStatus(CANCon::CONNECTED); + emit status(getStatus()); + } + break; + default: {} + } + + if(dev_p) + delete dev_p; +} diff --git a/connections/socketcan.h b/connections/socketcan.h index 1662501..eea37a9 100644 --- a/connections/socketcan.h +++ b/connections/socketcan.h @@ -3,21 +3,11 @@ #include #include +#include +#include #include "canframemodel.h" -#include "canconnection_old.h" - -class BUSConfig { -public: - BUSConfig(); - void reset(); - bool operator ==(CANBus&); - void operator =(CANBus&); - bool isConfigured; - int speed; - bool listenOnly; - bool active; -}; +#include "canconnection.h" class SocketCanConnection : public CANConnection @@ -25,20 +15,50 @@ class SocketCanConnection : public CANConnection Q_OBJECT public: - SocketCanConnection(CANFrameModel *, int); - virtual ~SocketCanConnection() override; + SocketCanConnection(QString portName); + virtual ~SocketCanConnection(); + + virtual void start(); + virtual void stop(); + + +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); + public slots: - virtual void updateBusSettings(CANBus) override; -private: - void errorReceived(QCanBusDevice::CanBusError error) const; + virtual void sendFrame(const CANFrame *); + virtual void sendFrameBatch(const QList *); + + virtual void setBusSettings(int, CANBus); + virtual bool getBusSettings(int pBusIdx, CANBus& pBus); + + virtual void suspend(bool); + +protected: + void disconnectDevice(); + +private slots: + void errorReceived(QCanBusDevice::CanBusError) const; void framesWritten(qint64 count); void framesReceived(); - void disconnect(); + void testConnection(); - QCanBusDevice* mDev_p; - BUSConfig mConf; +protected: + QCanBusDevice* mDev_p; + QTimer mTimer; + QThread mThread; }; + #endif // SOCKETCANCONNECTION_H From 6e623015dd39c83a2ce496e273ba901d6dd8ba79 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:24:01 +0200 Subject: [PATCH 15/30] attempt to adapt GVRET to the new interface --- connections/gvretserial.cpp | 609 +++++++++++++++++++++++++++++++++++- connections/gvretserial.h | 114 ++++++- 2 files changed, 715 insertions(+), 8 deletions(-) diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index 6e163d7..96666d5 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -1,6 +1,611 @@ -#include "cvretserial.h" +#include +#include +#include +#include +#include -CVRetSerial::CVRetSerial() +#include "gvretserial.h" + +GVRetSerial::GVRetSerial(QString portName) : + CANConnection(portName, CANCon::GVRET_SERIAL, 2), + mThread(NULL) { + getQueue().setSize(2000); /*TODO add check on returned value */ + /* move ourself to the thread */ + moveToThread(&mThread); + 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::start() +{ + qDebug() << "enter thread"; + /* start thread */ + mThread.start(QThread::HighPriority); + /* connect device in thread context */ + connect(&mThread, SIGNAL(started()), this, SLOT(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::suspend(bool pSuspend) { + /* make sure we execute in mThread context */ + if(QThread::currentThread() != &mThread) { + QMetaObject::invokeMethod(this, "suspend", + Qt::BlockingQueuedConnection, + Q_ARG(bool, pSuspend)); + return; + } + + /* update capSuspended */ + setCapSuspended(pSuspend); + + /* flush queue if we are suspended */ + if(isCapSuspended()) + getQueue().flush(); +} + + +void GVRetSerial::stop() { + mTimer.stop(); + mThread.quit(); + if(!mThread.wait()) { + qDebug() << "can't stop thread"; + } + disconnectDevice(); +} + + +bool GVRetSerial::getBusSettings(int pBusIdx, CANBus& pBus) { + /* make sure we execute in mThread context */ + if(QThread::currentThread() != &mThread) { + bool ret; + QMetaObject::invokeMethod(this, "getBusSettings", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int , pBusIdx), + Q_ARG(CANBus& , pBus)); + return ret; + } + + return getBusConfig(pBusIdx, pBus); +} + + +void GVRetSerial::sendFrame(const CANFrame *) {} +void GVRetSerial::sendFrameBatch(const QList *){} + + + +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); +} + + +void GVRetSerial::setBusSettings(int pBusIdx, CANBus bus) +{ + /* make sure we execute in mThread context */ + if(QThread::currentThread() != &mThread) { + QMetaObject::invokeMethod(this, "setBusSettings", + Qt::BlockingQueuedConnection, + Q_ARG(int, pBusIdx), + Q_ARG(CANBus, bus)); + return; + } + + /* 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); } diff --git a/connections/gvretserial.h b/connections/gvretserial.h index 12857c0..94f90e1 100644 --- a/connections/gvretserial.h +++ b/connections/gvretserial.h @@ -1,11 +1,113 @@ -#ifndef CVRETSERIAL_H -#define CVRETSERIAL_H +#ifndef GVRETSERIAL_H +#define GVRETSERIAL_H + +#include +#include +#include +#include + +/*************/ +#include +#include +/*************/ -class CVRetSerial +#include "canframemodel.h" +#include "canconnection.h" + + +namespace SERIALSTATE { + +enum STATE //keep this enum synchronized with the Arduino firmware project { -public: - CVRetSerial(); + 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 }; -#endif // CVRETSERIAL_H \ No newline at end of file +} + + +using namespace SERIALSTATE; +class GVRetSerial : public CANConnection +{ + Q_OBJECT + +public: + GVRetSerial(QString portName); + virtual ~GVRetSerial(); + + virtual void start(); + virtual void stop(); + + +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); + + +public slots: + + virtual void sendFrame(const CANFrame *); + virtual void sendFrameBatch(const QList *); + + virtual void setBusSettings(int, CANBus); + virtual bool getBusSettings(int pBusIdx, CANBus& pBus); + + virtual void suspend(bool); + +protected: + 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; + QMutex sendBulkMutex; + 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 From 6d20a0665d8f9030a0dd8094899ed9232460ef0e Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:25:58 +0200 Subject: [PATCH 16/30] add a factory for the different connection types --- connections/canconfactory.cpp | 15 ++++++++++++++- connections/canconfactory.h | 6 ++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/connections/canconfactory.cpp b/connections/canconfactory.cpp index 54095ab..93b618e 100644 --- a/connections/canconfactory.cpp +++ b/connections/canconfactory.cpp @@ -1,6 +1,19 @@ +#include #include "canconfactory.h" +#include "socketcan.h" +#include "gvretserial.h" -CanConFactory::CanConFactory() +using namespace CANCon; + +CANConnection* CanConFactory::create(type pType, QString pPortName) { + switch(pType) { + case SOCKETCAN: + return new SocketCanConnection(pPortName); + case GVRET_SERIAL: + return new GVRetSerial(pPortName); + default: {} + } + return NULL; } diff --git a/connections/canconfactory.h b/connections/canconfactory.h index a2d8cbc..2b482f5 100644 --- a/connections/canconfactory.h +++ b/connections/canconfactory.h @@ -1,11 +1,13 @@ #ifndef CANCONFACTORY_H #define CANCONFACTORY_H +#include "canconconst.h" +#include "canconnection.h" class CanConFactory { public: - CanConFactory(); + static CANConnection* create(CANCon::type, QString pPortName); }; -#endif // CANCONFACTORY_H \ No newline at end of file +#endif // CANCONFACTORY_H From 45752d137a041a194d36237ace1cebe3a86f7000 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:27:22 +0200 Subject: [PATCH 17/30] changed the way connections are organized and retrieved by connection window --- canconnectionmodel.cpp | 154 ++++++++++++++++++++++++----------------- canconnectionmodel.h | 27 ++++---- 2 files changed, 101 insertions(+), 80 deletions(-) diff --git a/canconnectionmodel.cpp b/canconnectionmodel.cpp index 7ec8ca7..3f96f94 100644 --- a/canconnectionmodel.cpp +++ b/canconnectionmodel.cpp @@ -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,97 +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::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) { - CANBus bus = buses[index.row()]; - CANConnection *conn = bus.getContainer()->getRef(); + 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::addBus(CANBus &bus) +void CANConnectionModel::add(CANConnection* pConn_p) { beginResetModel(); - buses.append(bus); + mConns.append(pConn_p); endResetModel(); } -void CANConnectionModel::removeBus(int busIdx) -{ - if (busIdx>=0 && busIdx < buses.count()) { - beginResetModel(); - buses.removeAt(busIdx); - endResetModel(); - } -} -CANBus* 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(); } -CANBus* CANConnectionModel::findBusByNum(int bus) +QList& CANConnectionModel::getConnections() { - for (int i = 0; i < buses.count(); i++) - { - if (buses[i].busNum == bus) - { - return &buses[i]; + return mConns; +} + + +CANConnection* CANConnectionModel::getAtIdx(int pIdx, int& pBusId) const +{ + if (pIdx < 0) + return NULL; + + int i=0; + QList::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(); +} diff --git a/canconnectionmodel.h b/canconnectionmodel.h index 22dacdc..c91c9e2 100644 --- a/canconnectionmodel.h +++ b/canconnectionmodel.h @@ -1,13 +1,13 @@ #ifndef CANCONNECTIONMODEL_H #define CANCONNECTIONMODEL_H -#include "canconnection.h" -#include "canbus.h" -#include "canconnectioncontainer.h" #include -class CANConnectionContainer; +#include "canbus.h" +#include "connections/canconnection.h" +#include "connectionwindow.h" + class CANConnectionModel : public QAbstractTableModel { @@ -19,24 +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(CANConnectionContainer *conn); - void removeConnection(CANConnection*); - void addBus(CANBus &bus); - void removeBus(int busIdx); - CANBus* 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& getConnections(); + CANConnection* getAtIdx(int, int&) const; void refreshView(); private: - QList connections; - QList buses; - - CANBus *findBusByNum(int bus); + QList mConns; }; #endif // CANCONNECTIONMODEL_H From ec57d30fd1740f4263563b616ef7a2a1eaf234e8 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:29:04 +0200 Subject: [PATCH 18/30] removed canconnectioncontainer --- canconnectioncontainer.cpp | 32 -------------------------------- canconnectioncontainer.h | 22 ---------------------- 2 files changed, 54 deletions(-) delete mode 100644 canconnectioncontainer.cpp delete mode 100644 canconnectioncontainer.h diff --git a/canconnectioncontainer.cpp b/canconnectioncontainer.cpp deleted file mode 100644 index 302a3be..0000000 --- a/canconnectioncontainer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "canconnection.h" -#include "canconnectioncontainer.h" -#include "mainwindow.h" - -CANConnectionContainer::CANConnectionContainer(CANConnection *conn) -{ - thread = new QThread(); - connection = conn; - connection->moveToThread(thread); - - 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 - thread->quit(); - if(!thread->wait()) { - qDebug() << "can't stop thread"; - } - delete thread; - delete connection; -} - -CANConnection* CANConnectionContainer::getRef() -{ - return connection; -} diff --git a/canconnectioncontainer.h b/canconnectioncontainer.h deleted file mode 100644 index 8a4a429..0000000 --- a/canconnectioncontainer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CANCONNECTIONCONTAINER_H -#define CANCONNECTIONCONTAINER_H - -#include -#include -#include "canconnection.h" - -class CANConnectionContainer : public QObject -{ - Q_OBJECT -public: - CANConnectionContainer(CANConnection *conn); - ~CANConnectionContainer(); - - CANConnection* getRef(); - -private: - CANConnection *connection; - QThread *thread; -}; - -#endif // CANCONNECTIONCONTAINER_H From f17b64e9f589291c310be3ab11da26f22ebdcbdc Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:31:44 +0200 Subject: [PATCH 19/30] renamed an signal --- mainwindow.cpp | 9 +++------ mainwindow.h | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 68e27c0..b456467 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -181,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() @@ -713,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) diff --git a/mainwindow.h b/mainwindow.h index cbe0c0d..191008a 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -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 From c3c6ff3acdff5d53bc5f1ab0d6a3536cfa153fc8 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:38:43 +0200 Subject: [PATCH 20/30] removed mutex --- connections/gvretserial.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/connections/gvretserial.h b/connections/gvretserial.h index 94f90e1..b223aee 100644 --- a/connections/gvretserial.h +++ b/connections/gvretserial.h @@ -7,7 +7,6 @@ #include /*************/ -#include #include /*************/ @@ -96,7 +95,6 @@ protected: bool isAutoRestart; bool continuousTimeSync; QSerialPort *serial; - QMutex sendBulkMutex; int framesRapid; STATE rx_state; int rx_step; From 65528fdf121862a5d734076075a5e164511d1621 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:40:36 +0200 Subject: [PATCH 21/30] #if 0 --- serialworker.cpp | 24 ++++++++++++++++-------- serialworker.h | 5 +++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/serialworker.cpp b/serialworker.cpp index 281c050..f3b35d1 100644 --- a/serialworker.cpp +++ b/serialworker.cpp @@ -5,6 +5,7 @@ #include #include +#if 0 SerialWorker::SerialWorker(CANFrameModel *model, int base) : CANConnection(model, base) { qDebug() << "Serial Worker constructor"; @@ -576,15 +577,7 @@ void SerialWorker::updatePortName(QString portName) } } -int SerialWorker::getNumBuses() -{ - return 2; -} -QString SerialWorker::getConnTypeName() -{ - return QString("GVRET"); -} void SerialWorker::updateBusSettings(CANBus bus) { @@ -638,3 +631,18 @@ void SerialWorker::updateBusSettings(CANBus bus) updateBaudRates(can0Baud,can1Baud); } + + +/************************************/ + +int SerialWorker::getNumBuses() +{ + return 2; +} + +QString SerialWorker::getConnTypeName() +{ + return QString("GVRET"); +} + +#endif diff --git a/serialworker.h b/serialworker.h index f9e57ec..dc1a9a9 100644 --- a/serialworker.h +++ b/serialworker.h @@ -8,7 +8,7 @@ #include #include "can_structs.h" #include "canframemodel.h" -#include "canconnection.h" +//#include "canconnection_old.h" namespace SERIALSTATE { @@ -30,6 +30,7 @@ enum STATE //keep this enum synchronized with the Arduino firmware project } +#if 0 using namespace SERIALSTATE; class SerialWorker : public CANConnection { @@ -84,5 +85,5 @@ private: void procRXChar(unsigned char); void sendCommValidation(); }; - +#endif #endif // SERIALTHREAD_H From 87c302c79583b17c3ed91342e495e0c95273e1f6 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:41:39 +0200 Subject: [PATCH 22/30] removed unneeded functions --- canbus.cpp | 34 ++++++++++------------------------ canbus.h | 10 ++-------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/canbus.cpp b/canbus.cpp index 6a8b35b..c01f274 100644 --- a/canbus.cpp +++ b/canbus.cpp @@ -7,17 +7,22 @@ CANBus::CANBus() listenOnly = false; singleWire = false; active = false; - container = Q_NULLPTR; - busNum = 0; } + CANBus::CANBus(const CANBus& pBus) : speed(pBus.speed), listenOnly(pBus.listenOnly), singleWire(pBus.singleWire), - active(pBus.active), - container(pBus.container), /* TODO: check if container is really needed */ - busNum(pBus.busNum) {} + 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) @@ -40,26 +45,11 @@ void CANBus::setEnabled(bool mode) active = mode; } -void CANBus::setContainer(CANConnectionContainer* pContainer) -{ - container = pContainer; -} - -void CANBus::setBusNum(int num) -{ - busNum = num; -} - int CANBus::getSpeed() { return speed; } -int CANBus::getBusNum() -{ - return busNum; -} - bool CANBus::isListenOnly() { return listenOnly; @@ -75,7 +65,3 @@ bool CANBus::isActive() return active; } -CANConnectionContainer* CANBus::getContainer() -{ - return container; -} diff --git a/canbus.h b/canbus.h index a343c92..c8b4e88 100644 --- a/canbus.h +++ b/canbus.h @@ -2,30 +2,24 @@ #define CANBus_H -class CANConnectionContainer; - 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 busNum; int speed; bool listenOnly; bool singleWire; bool active; //is this bus turned on? - CANConnectionContainer* container; + 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 setContainer(CANConnectionContainer *); - CANConnectionContainer* getContainer(); - void setBusNum(int); int getSpeed(); - int getBusNum(); bool isListenOnly(); bool isSingleWire(); bool isActive(); From ae7dbd4a841a0b1b87efcf8dba33299a533b9567 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:42:13 +0200 Subject: [PATCH 23/30] added test for lock free queue --- test/test.pro | 16 +++++--- test/tst_lfqueue.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 10 deletions(-) diff --git a/test/test.pro b/test/test.pro index 58486c6..56c22c3 100644 --- a/test/test.pro +++ b/test/test.pro @@ -1,12 +1,16 @@ -QT += core +QT += widgets testlib QT -= gui CONFIG += c++11 -TARGET = test -CONFIG += console -CONFIG -= app_bundle +INCLUDEPATH += ../utils -TEMPLATE = app +SOURCES += \ + tst_lfqueue.cpp -SOURCES += main.cpp + +#HEADERS += \ +# ../utils/lfqueue.h + +target.path= . +INSTALLS += target diff --git a/test/tst_lfqueue.cpp b/test/tst_lfqueue.cpp index 470a030..1120de5 100644 --- a/test/tst_lfqueue.cpp +++ b/test/tst_lfqueue.cpp @@ -1,8 +1,98 @@ -#include +#include +#include -int main(int argc, char *argv[]) +#include "lfqueue.h" + +class TestLFQueue: public QObject { - QCoreApplication a(argc, argv); + Q_OBJECT +private: + +private slots: + void setSize_data(); + void setSize(); + void exchange_data(); + void exchange(); +}; + + +void TestLFQueue::setSize_data() +{ + QTest::addColumn("size"); + QTest::addColumn("result"); + + QTest::newRow("-1") << -1 << false; + QTest::newRow("0") << 0 << true; + QTest::newRow("10") << 10 << true; + QTest::newRow("2000") << 20000 << true; - return a.exec(); } + + +void TestLFQueue::setSize() +{ + QFETCH(int, size); + QFETCH(bool, result); + + LFQueue queue; + QCOMPARE(queue.setSize(size), result); +} + + +void readerThread(LFQueue* pQueue_p, int pSize, bool pSleep) { + int* val_p; + + for(int i=0; ipeek()) ); + QVERIFY(val_p); + + QCOMPARE(*val_p, i); + pQueue_p->dequeue(); + + if(pSleep) + QThread::msleep(1); + } +} + + +void TestLFQueue::exchange_data() +{ + QTest::addColumn("size"); + QTest::addColumn("writerSleep"); + QTest::addColumn("readerSleep"); + + QTest::newRow("nosleep") << 1000 << false << false; + QTest::newRow("readersleep") << 1000 << false << true; + QTest::newRow("writersleep") << 1000 << true << false; +} + + +void TestLFQueue::exchange() +{ + LFQueue queue; + QFETCH(int, size); + QFETCH(bool, writerSleep); + QFETCH(bool, readerSleep); + + int* val_p; + QCOMPARE(queue.setSize(2), true); + + QFuture thread = QtConcurrent::run(readerThread, &queue, size, readerSleep); + + for(int i=0; i Date: Wed, 15 Jun 2016 18:43:17 +0200 Subject: [PATCH 24/30] change a method signature --- canframemodel.cpp | 3 ++- canframemodel.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index 57d542d..02fc0cf 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -282,8 +282,9 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation, } -void CANFrameModel::addFrame(CANFrame frame, bool autoRefresh = false) +void CANFrameModel::addFrame(CANFrame& frame, bool autoRefresh = false) { + /*TODO: remove mutex */ mutex.lock(); CANFrame tempFrame; tempFrame = frame; diff --git a/canframemodel.h b/canframemodel.h index f53db11..ddea3ce 100644 --- a/canframemodel.h +++ b/canframemodel.h @@ -46,7 +46,7 @@ public: const QMap *getFiltersReference() const; //this neither public slots: - void addFrame(CANFrame, bool); + void addFrame(CANFrame&, bool); signals: void updatedFiltersList(); From ed1b9b082bcc88721fcb6ebc9b13319c4b79251e Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:44:45 +0200 Subject: [PATCH 25/30] severals changes to adapt to new connection model and connection API --- connectionwindow.cpp | 295 +++++++++++++++++++++++++------------------ connectionwindow.h | 35 ++--- 2 files changed, 193 insertions(+), 137 deletions(-) diff --git a/connectionwindow.cpp b/connectionwindow.cpp index 8014093..bab8cf3 100644 --- a/connectionwindow.cpp +++ b/connectionwindow.cpp @@ -2,8 +2,7 @@ #include "connectionwindow.h" #include "ui_connectionwindow.h" -#include "socketcanconnection.h" - +#include "connections/canconfactory.h" ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : @@ -26,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(); @@ -40,7 +40,6 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : ui->ckSingleWire->setChecked(settings->value("Main/SingleWireMode", false).toBool()); ui->cbSpeed->addItem(tr("")); - ui->cbSpeed->addItem(tr("Disabled")); ui->cbSpeed->addItem(tr("125000")); ui->cbSpeed->addItem(tr("250000")); ui->cbSpeed->addItem(tr("500000")); @@ -66,10 +65,19 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : 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())); + mTicker.setInterval(250); //tick 4 times a second (TODO: make this configurable?) */ + mTicker.setSingleShot(false); + mTicker.start(); } ConnectionWindow::~ConnectionWindow() { + mTicker.stop(); delete settings; delete ui; } @@ -81,6 +89,20 @@ void ConnectionWindow::showEvent(QShowEvent* event) handleConnTypeChanged(); } +void ConnectionWindow::refreshCanList() { + QList::iterator conn_p; + QList& 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(); @@ -88,91 +110,101 @@ void ConnectionWindow::handleNewConn() handleConnSelectionChanged(); } +void ConnectionWindow::setSuspendAll(bool pSuspend) +{ + qDebug() << "setSuspendAll"; + + QList::iterator iter; + QList& conns = connModel->getConnections(); + + for (iter = conns.begin(); iter != conns.end(); ++iter) + (*iter)->suspend(pSuspend); +} + +void ConnectionWindow::setActiveAll(bool pActive) +{ + QList::iterator iter; + QList& 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) { -#if 0 - CANBus 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; - } -#endif + 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 CANBus entry and then send it off to the appropriate - //CANConnection object - CANBus *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->getContainer()->getRef(), "updateBusSettings", - Qt::QueuedConnection, - Q_ARG(CANBus, *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*))); @@ -215,55 +247,43 @@ 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()) - { - /* TODO: sanity checks here */ - /* text, port, etc, ... */ - /* factorize code with other probes */ + /* create connection */ + conn_p = CanConFactory::create(getConnectionType(), getPortName()); + if(!conn_p) + return; - /* create connection */ - SocketCanConnection* conn = new SocketCanConnection(canModel, 0); /* what is base? (second param) */ + /* connect signal */ + connect(conn_p, SIGNAL(status(CANCon::status)), + this, SLOT(connectionStatus(CANCon::status))); - /* set port name */ - conn->updatePortName(ui->lePort->text()); - - /* add connection to a container (this creates the thread) */ - CANConnectionContainer* container = new CANConnectionContainer(conn); + /*TODO add return value and checks */ + conn_p->start(); + for (int i=0 ; igetNumBuses() ; i++) { /* set bus configuration */ CANBus bus; bus.active = ui->ckEnabled->isChecked(); - bus.busNum = 0; // not used - bus.container = container; 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; - } + if (ui->cbSpeed->currentIndex() < 1) bus.speed = 0; else bus.speed = ui->cbSpeed->currentText().toInt(); - /* add bus to model */ - connModel->addBus(bus); - - /* set bus settings (send message to thread) */ - QMetaObject::invokeMethod(conn, "updateBusSettings", - Qt::QueuedConnection, - Q_ARG(CANBus, bus)); + /* 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; CANBus *busRef = connModel->getBus(bus); if (status & 40) busRef->setSpeed(speed); @@ -280,6 +300,7 @@ void ConnectionWindow::receiveBusStatus(int bus, int speed, int status) busRef->setListenOnly((status & 4)?true:false); } connModel->refreshView(); +#endif } void ConnectionWindow::handleConnSelectionChanged() @@ -289,10 +310,13 @@ void ConnectionWindow::handleConnSelectionChanged() 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); @@ -300,25 +324,39 @@ 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); - CANBus *bus = connModel->getBus(selIdx); - if (bus->getContainer()->getRef()->getConnTypeName() == "GVRET") ui->rbGVRET->setChecked(true); - if (bus->getContainer()->getRef()->getConnTypeName() == "KVASER") ui->rbKvaser->setChecked(true); - if (bus->getContainer()->getRef()->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); } } -/*TODO: rename the 3 following functions */ -void ConnectionWindow::getSerialPorts() + +void ConnectionWindow::selectSerial() { /* set combobox page visible */ ui->stPort->setCurrentWidget(ui->cbPage); @@ -333,7 +371,7 @@ void ConnectionWindow::getSerialPorts() } } -void ConnectionWindow::getKvaserPorts() +void ConnectionWindow::selectKvaser() { #ifdef Q_OS_WIN /* set combobox page visible */ @@ -341,7 +379,7 @@ void ConnectionWindow::getKvaserPorts() #endif } -void ConnectionWindow::getSocketcanPorts() +void ConnectionWindow::selectSocketCan() { #ifdef Q_OS_LINUX /* set edit text page visible */ @@ -394,16 +432,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); @@ -417,22 +469,21 @@ bool ConnectionWindow::getSWMode() void ConnectionWindow::handleRemoveConn() { -#if 0 int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); - if (selIdx <=0) return; + if (selIdx <0) return; - CANBus* bus = conModel->getBus(selIdx); - if(!bus) return; - - /* remove connection to model (this creates the thread) */ - connModel->removeConnection(bus->connection); - - /* remove connection and reset model */ - conModel->removeBus(selIdx); qDebug() << "remove connection at index: " << selIdx; - selIdx -#endif + 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() @@ -442,21 +493,25 @@ void ConnectionWindow::handleRevert() void ConnectionWindow::sendFrame(const CANFrame *frame) { +#if 0 CANBus *bus = connModel->getBus(frame->bus); if (bus == NULL) return; QMetaObject::invokeMethod(bus->getContainer()->getRef(), "sendFrame", Qt::QueuedConnection, Q_ARG(const CANFrame *, frame)); +#endif } void ConnectionWindow::sendFrameBatch(const QList *frames) { +#if 0 if (frames->count() == 0) return; CANBus *bus = connModel->getBus(frames->at(0).bus); if (bus == NULL) return; QMetaObject::invokeMethod(bus->getContainer()->getRef(), "sendFrameBatch", Qt::QueuedConnection, Q_ARG(const QList *, frames)); +#endif } bool ConnectionWindow::isSocketCanAvailable() diff --git a/connectionwindow.h b/connectionwindow.h index 5b0d9c0..066cad0 100644 --- a/connectionwindow.h +++ b/connectionwindow.h @@ -1,14 +1,18 @@ #ifndef CONNECTIONWINDOW_H #define CONNECTIONWINDOW_H -#include "canconnectionmodel.h" + #include #include #include #include -#include "canconnection.h" -#include "serialworker.h" +#include +//#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,7 +31,7 @@ public: void showEvent(QShowEvent *); int getSpeed(); QString getPortName(); //name of port to connect to - ConnectionType::ConnectionType getConnectionType(); + CANCon::type getConnectionType(); bool getSWMode(); signals: @@ -48,6 +43,8 @@ public slots: void setSWMode(bool mode); void sendFrame(const CANFrame *); void sendFrameBatch(const QList *); + void setSuspendAll(bool); + private slots: void handleOKButton(); @@ -59,7 +56,9 @@ private slots: void handleRevert(); void handleNewConn(); void receiveBusStatus(int bus, int speed, int status); - void connectionSuccess(CANConnection *conn); + void connectionStatus(CANCon::status); + + void refreshCanList(); private: Ui::ConnectionWindow *ui; @@ -67,12 +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 From 71e989ad05795cddd9ed57b2de7dd56a86a460b1 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:45:40 +0200 Subject: [PATCH 26/30] .pro update --- SavvyCAN.pro | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 5dcd015..34879f4 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -50,10 +50,11 @@ SOURCES += main.cpp\ isotp_interpreterwindow.cpp \ isotp_handler.cpp \ canconnectionmodel.cpp \ - canconnection.cpp \ - canconnectioncontainer.cpp \ - socketcanconnection.cpp \ - canbus.cpp + canbus.cpp \ + connections/canconnection.cpp \ + connections/socketcan.cpp \ + connections/canconfactory.cpp \ + connections/gvretserial.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -90,10 +91,13 @@ HEADERS += mainwindow.h \ isotp_interpreterwindow.h \ isotp_handler.h \ canconnectionmodel.h \ - canconnection.h \ - canconnectioncontainer.h \ - socketcanconnection.h \ - canbus.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 \ From d1c56426685109b07b2b8900faae2940ec9a90d1 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 16 Jun 2016 13:25:56 +0200 Subject: [PATCH 27/30] more thread abstraction --- connections/canconnection.cpp | 148 +++++++++++++++++++++++- connections/canconnection.h | 88 +++++++++++---- connections/gvretserial.cpp | 207 ++++++++++++++-------------------- connections/gvretserial.h | 24 ++-- connections/socketcan.cpp | 73 +++--------- connections/socketcan.h | 25 ++-- 6 files changed, 334 insertions(+), 231 deletions(-) diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index b3059b8..7ec3ab7 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -1,35 +1,179 @@ +#include #include "canconnection.h" -CANConnection::CANConnection(QString pPort, CANCon::type pType, int pNumBuses) : +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) + mStatus(CANCon::NOT_CONNECTED), + mThread_p(NULL) { qDebug() << "CANConnection()"; /* register types */ qRegisterMetaType("CANBus"); + qRegisterMetaType("CANFrame"); qRegisterMetaType("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 ; iquit(); + mThread_p->wait(); + delete mThread_p; + mThread_p = NULL; + } + /* delete bus table */ delete[] mBus; mBus = NULL; + /* configured table */ delete[] mConfigured; mConfigured = NULL; + /* delete queue table */ + mQueue.setSize(0); +} + + +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& 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&, pFrames)); + return; + } + + return piSendFrameBatch(pFrames); } diff --git a/connections/canconnection.h b/connections/canconnection.h index 5c9c68f..eb02f60 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -20,8 +20,11 @@ public: * @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); + CANConnection(QString pPort, CANCon::type pType, int pNumBuses, + int pQueueLen, bool pUseThread); /** * @brief CANConnection destructor */ @@ -31,50 +34,33 @@ public: /** * @brief getNumBuses * @return returns the number of buses of the device - * @note multithread safe */ int getNumBuses(); /** * @brief getPort * @return returns the port name of the device - * @note multithread safe */ QString getPort(); /** * @brief getQueue is call by reader to get a reference on the queue to monitor * @return the lock free queue of the device - * @note multithread safe */ LFQueue& getQueue(); /** * @brief getType * @return the @ref CANCon::type of the device - * @note multithread safe */ CANCon::type getType(); /** * @brief getStatus * @return the @ref CANCon::status of the device (either connected or not) - * @note multithread safe */ CANCon::status getStatus(); - /** - * @brief start the device - * @note start a working thread here if needed - */ - virtual void start() = 0; - - /** - * @brief stop the device - * @note stop the working thread here if one has been started - */ - virtual void stop() = 0; - signals: void error(const QString &); @@ -95,30 +81,45 @@ signals: public slots: - virtual void sendFrame(const CANFrame *) = 0; - virtual void sendFrameBatch(const QList *) = 0; + /** + * @brief start the device, this calls piStarted + * @note starts the working thread if required (piStarted 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) */ - virtual void setBusSettings(int pBusIdx, CANBus pBus) = 0; + 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) */ - virtual bool getBusSettings(int pBusIdx, CANBus& pBus) = 0; + 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 will not access the queue when capture is suspended, so it is safe for callee to flush the queue */ - virtual void suspend(bool pSuspend) = 0; + void suspend(bool pSuspend); + + void sendFrame(const CANFrame&); + void sendFrameBatch(const QList&); protected: @@ -177,6 +178,46 @@ protected: */ void setCapSuspended(bool pIsSuspended); +protected: + + /** + * @brief start the device + * @note start a working thread here if needed + */ + virtual void piStarted() = 0; + + /** + * @brief stop the device + * @note stop the working thread here if one has been started + */ + virtual void piStop() = 0; + + /** + * @brief setBusSettings + * @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 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 + */ + 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; + + virtual void piSendFrame(const CANFrame&) = 0; + virtual void piSendFrameBatch(const QList&) = 0; + + private: CANBus* mBus; bool* mConfigured; @@ -186,6 +227,7 @@ private: const CANCon::type mType; bool mIsCapSuspended; QAtomicInt mStatus; + QThread* mThread_p; }; #endif // CANCONNECTION_H diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index 96666d5..1d34f38 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -7,13 +7,9 @@ #include "gvretserial.h" GVRetSerial::GVRetSerial(QString portName) : - CANConnection(portName, CANCon::GVRET_SERIAL, 2), - mThread(NULL) + CANConnection(portName, CANCon::GVRET_SERIAL, 2, 4000, true), + mTimer(this) /*NB: set this as parent of timer to manage it from working thread */ { - getQueue().setSize(2000); /*TODO add check on returned value */ - /* move ourself to the thread */ - moveToThread(&mThread); - qDebug() << "GVRetSerial()"; serial = NULL; @@ -35,13 +31,9 @@ GVRetSerial::~GVRetSerial() } -void GVRetSerial::start() +void GVRetSerial::piStarted() { - qDebug() << "enter thread"; - /* start thread */ - mThread.start(QThread::HighPriority); - /* connect device in thread context */ - connect(&mThread, SIGNAL(started()), this, SLOT(connectDevice())); + connectDevice(); /* start timer */ connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick())); @@ -51,15 +43,8 @@ void GVRetSerial::start() } -void GVRetSerial::suspend(bool pSuspend) { - /* make sure we execute in mThread context */ - if(QThread::currentThread() != &mThread) { - QMetaObject::invokeMethod(this, "suspend", - Qt::BlockingQueuedConnection, - Q_ARG(bool, pSuspend)); - return; - } - +void GVRetSerial::piSuspend(bool pSuspend) +{ /* update capSuspended */ setCapSuspended(pSuspend); @@ -69,36 +54,98 @@ void GVRetSerial::suspend(bool pSuspend) { } -void GVRetSerial::stop() { +void GVRetSerial::piStop() +{ mTimer.stop(); - mThread.quit(); - if(!mThread.wait()) { - qDebug() << "can't stop thread"; - } disconnectDevice(); } -bool GVRetSerial::getBusSettings(int pBusIdx, CANBus& pBus) { - /* make sure we execute in mThread context */ - if(QThread::currentThread() != &mThread) { - bool ret; - QMetaObject::invokeMethod(this, "getBusSettings", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, ret), - Q_ARG(int , pBusIdx), - Q_ARG(CANBus& , pBus)); - return ret; - } - +bool GVRetSerial::piGetBusSettings(int pBusIdx, CANBus& pBus) +{ return getBusConfig(pBusIdx, pBus); } -void GVRetSerial::sendFrame(const CANFrame *) {} -void GVRetSerial::sendFrameBatch(const QList *){} +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&){} + + +/****************************************************************/ void GVRetSerial::readSettings() { @@ -528,84 +575,4 @@ void GVRetSerial::sendCommValidation() } -void GVRetSerial::setBusSettings(int pBusIdx, CANBus bus) -{ - /* make sure we execute in mThread context */ - if(QThread::currentThread() != &mThread) { - QMetaObject::invokeMethod(this, "setBusSettings", - Qt::BlockingQueuedConnection, - Q_ARG(int, pBusIdx), - Q_ARG(CANBus, bus)); - return; - } - /* 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); -} diff --git a/connections/gvretserial.h b/connections/gvretserial.h index b223aee..350277f 100644 --- a/connections/gvretserial.h +++ b/connections/gvretserial.h @@ -44,10 +44,6 @@ public: GVRetSerial(QString portName); virtual ~GVRetSerial(); - virtual void start(); - virtual void stop(); - - signals: void error(const QString &); @@ -60,18 +56,16 @@ signals: //being passed. Just set for things that really are being updated. void busStatus(int, int, int); - -public slots: - - virtual void sendFrame(const CANFrame *); - virtual void sendFrameBatch(const QList *); - - virtual void setBusSettings(int, CANBus); - virtual bool getBusSettings(int pBusIdx, CANBus& pBus); - - virtual void suspend(bool); - 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&); + void disconnectDevice(); private slots: diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 76b6fe3..2b41f2e 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -11,14 +11,10 @@ /***********************************/ SocketCanConnection::SocketCanConnection(QString portName) : - CANConnection(portName, CANCon::SOCKETCAN, 1), + CANConnection(portName, CANCon::SOCKETCAN, 1, 4000, true), mDev_p(NULL), - mThread(NULL) + mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */ { - getQueue().setSize(2000); /*TODO add check on returned value */ - /* move ourself to the thread */ - moveToThread(&mThread); - qDebug() << "SocketCanConnection()"; } @@ -30,11 +26,8 @@ SocketCanConnection::~SocketCanConnection() } -void SocketCanConnection::start() { - - qDebug() << "enter thread"; - mThread.start(QThread::HighPriority); - +void SocketCanConnection::piStarted() +{ connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection())); mTimer.setInterval(1000); mTimer.setSingleShot(false); //keep ticking @@ -42,15 +35,8 @@ void SocketCanConnection::start() { } -void SocketCanConnection::suspend(bool pSuspend) { - /* make sure we execute in mThread context */ - if(QThread::currentThread() != &mThread) { - QMetaObject::invokeMethod(this, "suspend", - Qt::BlockingQueuedConnection, - Q_ARG(bool, pSuspend)); - return; - } - +void SocketCanConnection::piSuspend(bool pSuspend) +{ /* update capSuspended */ setCapSuspended(pSuspend); @@ -60,43 +46,20 @@ void SocketCanConnection::suspend(bool pSuspend) { } -void SocketCanConnection::stop() { +void SocketCanConnection::piStop() { mTimer.stop(); - mThread.quit(); - if(!mThread.wait()) { - qDebug() << "can't stop thread"; - } disconnectDevice(); } -bool SocketCanConnection::getBusSettings(int pBusIdx, CANBus& pBus) { - /* make sure we execute in mThread context */ - if(QThread::currentThread() != &mThread) { - bool ret; - QMetaObject::invokeMethod(this, "getBusSettings", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, ret), - Q_ARG(int , pBusIdx), - Q_ARG(CANBus& , pBus)); - return ret; - } - +bool SocketCanConnection::piGetBusSettings(int pBusIdx, CANBus& pBus) +{ return getBusConfig(pBusIdx, pBus); } -void SocketCanConnection::setBusSettings(int pBusIdx, CANBus bus) +void SocketCanConnection::piSetBusSettings(int pBusIdx, CANBus bus) { - /* make sure we execute in mThread context */ - if(QThread::currentThread() != &mThread) { - QMetaObject::invokeMethod(this, "setBusSettings", - Qt::BlockingQueuedConnection, - Q_ARG(int, pBusIdx), - Q_ARG(CANBus, bus)); - return; - } - /* sanity checks */ if(0 != pBusIdx) return; @@ -139,8 +102,8 @@ void SocketCanConnection::setBusSettings(int pBusIdx, CANBus bus) } -void SocketCanConnection::sendFrame(const CANFrame *) {} -void SocketCanConnection::sendFrameBatch(const QList *){} +void SocketCanConnection::piSendFrame(const CANFrame&) {} +void SocketCanConnection::piSendFrameBatch(const QList&){} /***********************************/ @@ -239,12 +202,12 @@ void SocketCanConnection::testConnection() { break; case CANCon::NOT_CONNECTED: if (dev_p && dev_p->connectDevice()) { - - /* try to reconnect */ - CANBus bus; - if(getBusConfig(0, bus)) - setBusSettings(0, bus); - + if(!mDev_p) { + /* try to reconnect */ + CANBus bus; + if(getBusConfig(0, bus)) + setBusSettings(0, bus); + } /* disconnect test instance */ dev_p->disconnectDevice(); diff --git a/connections/socketcan.h b/connections/socketcan.h index eea37a9..315aad1 100644 --- a/connections/socketcan.h +++ b/connections/socketcan.h @@ -18,10 +18,6 @@ public: SocketCanConnection(QString portName); virtual ~SocketCanConnection(); - virtual void start(); - virtual void stop(); - - signals: void error(const QString &); @@ -34,18 +30,16 @@ signals: //being passed. Just set for things that really are being updated. void busStatus(int, int, int); - -public slots: - - virtual void sendFrame(const CANFrame *); - virtual void sendFrameBatch(const QList *); - - virtual void setBusSettings(int, CANBus); - virtual bool getBusSettings(int pBusIdx, CANBus& pBus); - - virtual void suspend(bool); - 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&); + void disconnectDevice(); private slots: @@ -57,7 +51,6 @@ private slots: protected: QCanBusDevice* mDev_p; QTimer mTimer; - QThread mThread; }; From e2d0033099434f40dbd6b0531cfe1eadd3d5b5f7 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 16 Jun 2016 13:28:29 +0200 Subject: [PATCH 28/30] add connection deletion --- connectionwindow.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/connectionwindow.cpp b/connectionwindow.cpp index bab8cf3..d9237e6 100644 --- a/connectionwindow.cpp +++ b/connectionwindow.cpp @@ -70,13 +70,27 @@ ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : qDebug() << "Serial worker thread starting"; connect(&mTicker, SIGNAL(timeout()), this, SLOT(refreshCanList())); - mTicker.setInterval(250); //tick 4 times a second (TODO: make this configurable?) */ + /* 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& 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; @@ -306,7 +320,6 @@ void ConnectionWindow::receiveBusStatus(int bus, int speed, int status) void ConnectionWindow::handleConnSelectionChanged() { int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); - qDebug() << "Selection: " << selIdx; if (selIdx == -1) { ui->btnOK->setText(tr("Create New Connection")); From 893aab56002b737a376dc7d493eb670d80c86787 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 16 Jun 2016 13:59:06 +0200 Subject: [PATCH 29/30] renamed socketcan class --- connections/canconfactory.cpp | 2 +- connections/canconnection.h | 67 ++++++++++++++++++++++------------- connections/socketcan.cpp | 38 ++++++++++---------- connections/socketcan.h | 12 +++---- 4 files changed, 69 insertions(+), 50 deletions(-) diff --git a/connections/canconfactory.cpp b/connections/canconfactory.cpp index 93b618e..7926001 100644 --- a/connections/canconfactory.cpp +++ b/connections/canconfactory.cpp @@ -9,7 +9,7 @@ CANConnection* CanConFactory::create(type pType, QString pPortName) { switch(pType) { case SOCKETCAN: - return new SocketCanConnection(pPortName); + return new SocketCan(pPortName); case GVRET_SERIAL: return new GVRetSerial(pPortName); default: {} diff --git a/connections/canconnection.h b/connections/canconnection.h index eb02f60..9199c7b 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -23,8 +23,11 @@ public: * @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); + CANConnection(QString pPort, + CANCon::type pType, + int pNumBuses, + int pQueueLen, + bool pUseThread); /** * @brief CANConnection destructor */ @@ -44,7 +47,7 @@ public: QString getPort(); /** - * @brief getQueue is call by reader to get a reference on the queue to monitor + * @brief getQueue * @return the lock free queue of the device */ LFQueue& getQueue(); @@ -63,6 +66,7 @@ public: 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 @@ -73,7 +77,7 @@ signals: void busStatus(int, int, int); /** - * @brief event sent when the CANCon::status of the connection changes (connected->not_connected or the other way round) + * @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); @@ -82,13 +86,13 @@ signals: public slots: /** - * @brief start the device, this calls piStarted - * @note starts the working thread if required (piStarted in the working thread context) + * @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 + * @brief stop the device. This calls piStop * @note if a working thread is used, piStop is called before exiting the working thread */ void stop(); @@ -113,20 +117,30 @@ public slots: /** * @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 will not access the queue when capture is suspended, so it is safe for callee to flush the queue + * @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); - void sendFrame(const CANFrame&); - void sendFrameBatch(const QList&); + /** + * @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& pFrames); protected: /** * @brief setStatus * @param pStatus: the status to set - * @note multithread safe (can be used while another thread calls @ref getStatus) */ void setStatus(CANCon::status pStatus); @@ -134,7 +148,6 @@ protected: * @brief isConfigured * @param pBusId * @return true if bus is configured - * @note NOT multithread safe */ bool isConfigured(int pBusId); @@ -143,7 +156,6 @@ protected: * @param pBusId * @param pConfigured * @note it is not necessary to call this function to set pBusId configured, it is enough to call @ref setBusConfig - * @note NOT multithread safe */ void setConfigured(int pBusId, bool pConfigured); @@ -152,7 +164,6 @@ protected: * @param pBusId * @param pBus * @return true if operation succeeds, false if pBusIdx is invalid or bus has not been configured yet - * @note NOT multithread safe */ bool getBusConfig(int pBusId, CANBus& pBus); @@ -160,47 +171,46 @@ protected: * @brief setBusConfig * @param pBusId: the index of the bus for which settings have to be set * @param pBus: the settings to set - * @note NOT multithread safe */ void setBusConfig(int pBusId, CANBus& pBus); /** * @brief isCapSuspended * @return true if the capture is suspended - * @note NOT multithread safe */ bool isCapSuspended(); /** * @brief setCapSuspended * @param pIsSuspended - * @note NOT multithread safe */ void setCapSuspended(bool pIsSuspended); protected: + /**************************************************************/ + /*********** protected interface to implement *******/ + /**************************************************************/ + /** - * @brief start the device - * @note start a working thread here if needed + * @brief starts the device */ virtual void piStarted() = 0; /** - * @brief stop the device - * @note stop the working thread here if one has been started + * @brief stops the device */ virtual void piStop() = 0; /** - * @brief setBusSettings + * @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 getBusSettings + * @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 @@ -214,7 +224,16 @@ protected: */ 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&) = 0; diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 2b41f2e..16fff23 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -10,23 +10,23 @@ /**** class definition ****/ /***********************************/ -SocketCanConnection::SocketCanConnection(QString portName) : +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() << "SocketCanConnection()"; + qDebug() << "SocketCan()"; } -SocketCanConnection::~SocketCanConnection() +SocketCan::~SocketCan() { stop(); - qDebug() << "~SocketCanConnection()"; + qDebug() << "~SocketCan()"; } -void SocketCanConnection::piStarted() +void SocketCan::piStarted() { connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection())); mTimer.setInterval(1000); @@ -35,7 +35,7 @@ void SocketCanConnection::piStarted() } -void SocketCanConnection::piSuspend(bool pSuspend) +void SocketCan::piSuspend(bool pSuspend) { /* update capSuspended */ setCapSuspended(pSuspend); @@ -46,19 +46,19 @@ void SocketCanConnection::piSuspend(bool pSuspend) } -void SocketCanConnection::piStop() { +void SocketCan::piStop() { mTimer.stop(); disconnectDevice(); } -bool SocketCanConnection::piGetBusSettings(int pBusIdx, CANBus& pBus) +bool SocketCan::piGetBusSettings(int pBusIdx, CANBus& pBus) { return getBusConfig(pBusIdx, pBus); } -void SocketCanConnection::piSetBusSettings(int pBusIdx, CANBus bus) +void SocketCan::piSetBusSettings(int pBusIdx, CANBus bus) { /* sanity checks */ if(0 != pBusIdx) @@ -84,9 +84,9 @@ void SocketCanConnection::piSetBusSettings(int pBusIdx, CANBus bus) } /* connect slots */ - connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SocketCanConnection::errorReceived); - connect(mDev_p, &QCanBusDevice::framesWritten, this, &SocketCanConnection::framesWritten); - connect(mDev_p, &QCanBusDevice::framesReceived, this, &SocketCanConnection::framesReceived); + 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) { @@ -102,8 +102,8 @@ void SocketCanConnection::piSetBusSettings(int pBusIdx, CANBus bus) } -void SocketCanConnection::piSendFrame(const CANFrame&) {} -void SocketCanConnection::piSendFrameBatch(const QList&){} +void SocketCan::piSendFrame(const CANFrame&) {} +void SocketCan::piSendFrameBatch(const QList&){} /***********************************/ @@ -112,7 +112,7 @@ void SocketCanConnection::piSendFrameBatch(const QList&){} /* disconnect device */ -void SocketCanConnection::disconnectDevice() { +void SocketCan::disconnectDevice() { if(mDev_p) { mDev_p->disconnectDevice(); delete mDev_p; @@ -121,7 +121,7 @@ void SocketCanConnection::disconnectDevice() { } -void SocketCanConnection::errorReceived(QCanBusDevice::CanBusError error) const +void SocketCan::errorReceived(QCanBusDevice::CanBusError error) const { switch (error) { case QCanBusDevice::ReadError: @@ -135,12 +135,12 @@ void SocketCanConnection::errorReceived(QCanBusDevice::CanBusError error) const } } -void SocketCanConnection::framesWritten(qint64 count) +void SocketCan::framesWritten(qint64 count) { qDebug() << "Number of frames written:" << count; } -void SocketCanConnection::framesReceived() +void SocketCan::framesReceived() { /* sanity checks */ if(!mDev_p) @@ -186,7 +186,7 @@ void SocketCanConnection::framesReceived() } -void SocketCanConnection::testConnection() { +void SocketCan::testConnection() { QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort()); switch(getStatus()) diff --git a/connections/socketcan.h b/connections/socketcan.h index 315aad1..dd1877b 100644 --- a/connections/socketcan.h +++ b/connections/socketcan.h @@ -1,5 +1,5 @@ -#ifndef SOCKETCANCONNECTION_H -#define SOCKETCANCONNECTION_H +#ifndef SocketCan_H +#define SocketCan_H #include #include @@ -10,13 +10,13 @@ #include "canconnection.h" -class SocketCanConnection : public CANConnection +class SocketCan : public CANConnection { Q_OBJECT public: - SocketCanConnection(QString portName); - virtual ~SocketCanConnection(); + SocketCan(QString portName); + virtual ~SocketCan(); signals: void error(const QString &); @@ -54,4 +54,4 @@ protected: }; -#endif // SOCKETCANCONNECTION_H +#endif // SocketCan_H From 89ad77eab972519d430d7b4b951f63041e1b1966 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 16 Jun 2016 15:52:47 +0200 Subject: [PATCH 30/30] removed uneeded queue resizing --- connections/canconnection.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 7ec3ab7..526d88e 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -55,8 +55,6 @@ CANConnection::~CANConnection() /* configured table */ delete[] mConfigured; mConfigured = NULL; - /* delete queue table */ - mQueue.setSize(0); }