diff --git a/can_structs.h b/can_structs.h index d118dc8..d9fa1c5 100644 --- a/can_structs.h +++ b/can_structs.h @@ -11,11 +11,18 @@ public: int bus; bool extended; bool isReceived; //did we receive this or send it? - int len; + uint32_t len; unsigned char data[8]; uint64_t timestamp; }; +struct CANFlt +{ + quint32 id; + quint32 mask; + bool notify; +}; + struct J1939ID { public: diff --git a/canbus.cpp b/canbus.cpp index c01f274..91e83ad 100644 --- a/canbus.cpp +++ b/canbus.cpp @@ -17,7 +17,7 @@ CANBus::CANBus(const CANBus& pBus) : active(pBus.active) {} -bool CANBus::operator==(CANBus& bus) { +bool CANBus::operator==(const CANBus& bus) const{ return speed == bus.speed && listenOnly == bus.listenOnly && singleWire == bus.singleWire && diff --git a/canbus.h b/canbus.h index c8b4e88..8dd8044 100644 --- a/canbus.h +++ b/canbus.h @@ -7,7 +7,7 @@ class CANBus public: CANBus(); CANBus(const CANBus&); - bool operator==(CANBus&); + bool operator==(const CANBus&) const; virtual ~CANBus(){}; /*TODO: remove connection from CANBus and add CANBus as an element of CANConnection */ int speed; bool listenOnly; diff --git a/canframemodel.cpp b/canframemodel.cpp index 02fc0cf..f1a3b64 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -207,7 +207,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const return QString::number(thisFrame.len); break; case 6: //data - for (int i = 0; i < thisFrame.len; i++) + for (unsigned int i = 0; i < thisFrame.len; i++) { tempString.append(Utility::formatNumber(thisFrame.data[i])); tempString.append(" "); diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 526d88e..cb88194 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -1,6 +1,15 @@ #include #include "canconnection.h" + +struct BusData { + CANBus mBus; + bool mConfigured; + QVector mFilters; + bool mFilterOut; +}; + + CANConnection::CANConnection(QString pPort, CANCon::type pType, int pNumBuses, @@ -12,24 +21,25 @@ CANConnection::CANConnection(QString pPort, mType(pType), mIsCapSuspended(false), mStatus(CANCon::NOT_CONNECTED), + mStarted(false), mThread_p(NULL) { - qDebug() << "CANConnection()"; - /* register types */ qRegisterMetaType("CANBus"); qRegisterMetaType("CANFrame"); qRegisterMetaType("CANCon::status"); + qRegisterMetaType("CANFlt"); /* set queue size */ mQueue.setSize(pQueueLen); /*TODO add check on returned value */ /* allocate buses */ - mBus = new CANBus[mNumBuses]; - mConfigured = new bool[mNumBuses]; - - for(int i=0 ; iquit(); @@ -49,12 +58,10 @@ CANConnection::~CANConnection() mThread_p = NULL; } - /* delete bus table */ - delete[] mBus; - mBus = NULL; - /* configured table */ - delete[] mConfigured; - mConfigured = NULL; + if(mBusData_p) { + delete[] mBusData_p; + mBusData_p = NULL; + } } @@ -71,6 +78,9 @@ void CANConnection::start() return; } + /* set started flag */ + mStarted = true; + /* in multithread case, this will be called before entering thread event loop */ return piStarted(); } @@ -93,7 +103,7 @@ void CANConnection::suspend(bool pSuspend) void CANConnection::stop() { /* 1) execute in mThread_p context */ - if( mThread_p && (mThread_p != QThread::currentThread()) ) + if( mThread_p && mStarted && (mThread_p != QThread::currentThread()) ) { /* if thread is finished, it means we call this function for the second time so we can leave */ if( !mThread_p->isFinished() ) @@ -147,31 +157,37 @@ void CANConnection::setBusSettings(int pBusIdx, CANBus pBus) } -void CANConnection::sendFrame(const CANFrame& pFrame) +bool CANConnection::sendFrame(const CANFrame& pFrame) { /* make sure we execute in mThread context */ - if( mThread_p && (mThread_p != QThread::currentThread()) ) { + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + bool ret; QMetaObject::invokeMethod(this, "sendFrame", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), Q_ARG(const CANFrame&, pFrame)); - return; + return ret; } return piSendFrame(pFrame); } -void CANConnection::sendFrameBatch(const QList& pFrames) +bool CANConnection::sendFrames(const QList& pFrames) { /* make sure we execute in mThread context */ - if( mThread_p && (mThread_p != QThread::currentThread()) ) { - QMetaObject::invokeMethod(this, "sendFrameBatch", + if( mThread_p && (mThread_p != QThread::currentThread()) ) + { + bool ret; + QMetaObject::invokeMethod(this, "sendFrames", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), Q_ARG(const QList&, pFrames)); - return; + return ret; } - return piSendFrameBatch(pFrames); + return piSendFrames(pFrames); } @@ -181,33 +197,33 @@ int CANConnection::getNumBuses() { bool CANConnection::isConfigured(int pBusId) { - if( pBusId < 0 || pBusId >= mNumBuses) + if( pBusId < 0 || pBusId >= getNumBuses()) return false; - return mConfigured[pBusId]; + return mBusData_p[pBusId].mConfigured; } void CANConnection::setConfigured(int pBusId, bool pConfigured) { - if( pBusId < 0 || pBusId >= mNumBuses) + if( pBusId < 0 || pBusId >= getNumBuses()) return; - mConfigured[pBusId] = pConfigured; + mBusData_p[pBusId].mConfigured = pConfigured; } bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) { - if( pBusId < 0 || pBusId >= mNumBuses || !isConfigured(pBusId)) + if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId)) return false; - pBus = mBus[pBusId]; + pBus = mBusData_p[pBusId].mBus; return true; } void CANConnection::setBusConfig(int pBusId, CANBus& pBus) { - if( pBusId < 0 || pBusId >= mNumBuses) + if( pBusId < 0 || pBusId >= getNumBuses()) return; - mConfigured[pBusId] = true; - mBus[pBusId] = pBus; + mBusData_p[pBusId].mConfigured = true; + mBusData_p[pBusId].mBus = pBus; } @@ -230,7 +246,6 @@ CANCon::status CANConnection::getStatus() { return (CANCon::status) mStatus.load(); } - void CANConnection::setStatus(CANCon::status pStatus) { mStatus.store(pStatus); } @@ -243,3 +258,69 @@ void CANConnection::setCapSuspended(bool pIsSuspended) { mIsCapSuspended = pIsSuspended; } +bool CANConnection::setFilters(int pBusId, const QVector& pFilters, bool pFilterOut) +{ + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + bool ret; + QMetaObject::invokeMethod(this, "setFilters", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int , pBusId), + Q_ARG(const QVector&, pFilters), + Q_ARG(bool , pFilterOut)); + return ret; + } + + /* sanity checks */ + if(pBusId<0 || pBusId>=getNumBuses()) + return false; + + /* copy filters */ + mBusData_p[pBusId].mFilters = pFilters; + mBusData_p[pBusId].mFilterOut = pFilterOut; + + /* set hardware filtering if available */ + if(pFilterOut) + piSetFilters(pBusId, pFilters); + + return true; +} + + +bool CANConnection::discard(int pBusId, quint32 pId, bool& pNotify) +{ + if(pBusId<0 || pBusId>=getNumBuses()) + return true; + + foreach (const CANFlt& filter, mBusData_p[pBusId].mFilters) + { + if( (filter.id & filter.mask) == (pId & filter.mask) ) + { + if(filter.notify) + pNotify = true; + return false; + } + } + return mBusData_p[pBusId].mFilterOut; +} + + +bool CANConnection::piSendFrames(const QList& pFrames) +{ + foreach(const CANFrame& frame, pFrames) + { + if(!piSendFrame(frame)) + return false; + } + + return true; +} + + +/* default implementation of piSetFilters */ +void CANConnection::piSetFilters(int pBusId, const QVector& pFilters) +{ + Q_UNUSED(pBusId); + Q_UNUSED(pFilters); +} diff --git a/connections/canconnection.h b/connections/canconnection.h index 9199c7b..117b0c7 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -8,12 +8,13 @@ #include "canbus.h" #include "canconconst.h" +struct BusData; class CANConnection : public QObject { Q_OBJECT -public: +protected: /** * @brief CANConnection constructor @@ -28,6 +29,9 @@ public: int pNumBuses, int pQueueLen, bool pUseThread); + +public: + /** * @brief CANConnection destructor */ @@ -76,6 +80,11 @@ signals: //being passed. Just set for things that really are being updated. void busStatus(int, int, int); + /** + * @brief event sent when a frame matching a filter set with notification hs been received + */ + void notify(); + /** * @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 @@ -118,23 +127,34 @@ 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 shall not access the queue when capture is suspended, it is then safe for callee to flush the queue + * @note the caller shall not access the queue when capture is suspended, + * @note the callee is expected to flush the queue */ void suspend(bool pSuspend); /** * @brief provides device with the frame to send * @param pFrame: the frame to send + * @return false if parameter is invalid (bus id for instance) * @note this calls piSendFrame (in the working thread context if one has been started) */ - void sendFrame(const CANFrame& pFrame); + bool sendFrame(const CANFrame& pFrame); /** * @brief provides device with a list of frames to send * @param pFrame: the list of frames to send + * @return false if parameter is invalid (bus id for instance) * @note this calls piSendFrameBatch (in the working thread context if one has been started) */ - void sendFrameBatch(const QList& pFrames); + bool sendFrames(const QList& pFrames); + + /** + * @brief sets a filter list. Filters can be used to send a signal or filter out messages + * @param pFilters: a vector of can filters + * @param pFilterOut: if set to true, can frames not matching a filter are discarded + * @return true if filters have been set, false if busid is invalid + */ + bool setFilters(int pBusId, const QVector& pFilters, bool pFilterOut); protected: @@ -186,6 +206,16 @@ protected: */ void setCapSuspended(bool pIsSuspended); + /** + * @brief used to check if a message shall be discarded. The function also update pNotify if a notification is expected for that message + * @param pBusId: the bus id on which the frame has been received + * @param pId: the id of the message to filter + * @param pNotify: set to true if a notification is expected, else pNotify is not set + * @return true if message shall be discarded + */ + bool discard(int pBusId, quint32 pId, bool& pNotify); + + protected: /**************************************************************/ @@ -227,25 +257,35 @@ protected: /** * @brief provides device with the frame to send * @param pFrame: the frame to send + * @return false if parameter is invalid (bus id for instance) */ - virtual void piSendFrame(const CANFrame&) = 0; + virtual bool piSendFrame(const CANFrame&) = 0; /** * @brief provides device with a list of frames to send * @param pFrame: the list of frames to send + * @return false if parameter is invalid (bus id for instance) + * @note implementing this function is optional */ - virtual void piSendFrameBatch(const QList&) = 0; + virtual bool piSendFrames(const QList&); + /** + * @brief sets a hardware filter list + * @param pBusId: the bus id on which filters have to be set + * @param pFilters: a vector of can filters, the notification flag of CANFilter is ignored + * @note implementing this function is optional + */ + virtual void piSetFilters(int pBusId, const QVector& pFilters); private: - CANBus* mBus; - bool* mConfigured; LFQueue mQueue; const int mNumBuses; const QString mPort; const CANCon::type mType; bool mIsCapSuspended; QAtomicInt mStatus; + bool mStarted; + BusData* mBusData_p; QThread* mThread_p; }; diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index 1d34f38..d9408b3 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -141,8 +141,8 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus) } -void GVRetSerial::piSendFrame(const CANFrame&) {} -void GVRetSerial::piSendFrameBatch(const QList&){} +bool GVRetSerial::piSendFrame(const CANFrame&) {return false;} + /****************************************************************/ diff --git a/connections/gvretserial.h b/connections/gvretserial.h index 350277f..4038a01 100644 --- a/connections/gvretserial.h +++ b/connections/gvretserial.h @@ -44,18 +44,6 @@ public: GVRetSerial(QString portName); virtual ~GVRetSerial(); -signals: - void error(const QString &); - - void status(CANCon::status); - void deviceInfo(int, int); //First param = driver version (or version of whatever you want), second param a status byte - - //bus number, bus speed, status (bit 0 = enabled, 1 = single wire, 2 = listen only) - //3 = Use value stored for enabled, 4 = use value passed for single wire, 5 = use value passed for listen only - //6 = use value passed for speed. This allows bus status to be updated but set that some things aren't really - //being passed. Just set for things that really are being updated. - void busStatus(int, int, int); - protected: virtual void piStarted(); @@ -63,8 +51,7 @@ protected: 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&); + virtual bool piSendFrame(const CANFrame&) ; void disconnectDevice(); diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 16fff23..64eaa0f 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -15,14 +15,12 @@ SocketCan::SocketCan(QString portName) : mDev_p(NULL), mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */ { - qDebug() << "SocketCan()"; } SocketCan::~SocketCan() { stop(); - qDebug() << "~SocketCan()"; } @@ -102,8 +100,20 @@ void SocketCan::piSetBusSettings(int pBusIdx, CANBus bus) } -void SocketCan::piSendFrame(const CANFrame&) {} -void SocketCan::piSendFrameBatch(const QList&){} +bool SocketCan::piSendFrame(const CANFrame& pFrame) +{ + /* sanity checks */ + if(0 != pFrame.bus || pFrame.len>8) + return false; + + /* fill frame */ + QCanBusFrame frame; + frame.setFrameId(pFrame.ID); + frame.setExtendedFrameFormat(false); + frame.setPayload(QByteArray((const char*)pFrame.data, pFrame.len)); + + return mDev_p->writeFrame(frame); +} /***********************************/ @@ -142,6 +152,9 @@ void SocketCan::framesWritten(qint64 count) void SocketCan::framesReceived() { + /* test */ + bool sndNotif = false; + /* sanity checks */ if(!mDev_p) return; @@ -153,15 +166,16 @@ void SocketCan::framesReceived() /* exit case */ if(!recFrame.isValid()) - return; + break; /* drop frame if capture is suspended */ if(isCapSuspended()) continue; /* check frame */ - if(!recFrame.payload().isEmpty() && - recFrame.payload().length()<=8) + if( !recFrame.payload().isEmpty() && + recFrame.payload().length()<=8 && + !discard(0, recFrame.frameId(), sndNotif) ) { CANFrame* frame_p = getQueue().get(); if(frame_p) { @@ -176,12 +190,15 @@ void SocketCan::framesReceived() /* enqueue frame */ getQueue().queue(); } +#if 0 else qDebug() << "can't get a frame, ERROR"; +#endif } - else { - qDebug() << "invalid frame"; - } + } + + if(sndNotif) { + emit notify(); } } diff --git a/connections/socketcan.h b/connections/socketcan.h index dd1877b..c303236 100644 --- a/connections/socketcan.h +++ b/connections/socketcan.h @@ -18,18 +18,6 @@ public: SocketCan(QString portName); virtual ~SocketCan(); -signals: - void error(const QString &); - - void status(CANCon::status); - void deviceInfo(int, int); //First param = driver version (or version of whatever you want), second param a status byte - - //bus number, bus speed, status (bit 0 = enabled, 1 = single wire, 2 = listen only) - //3 = Use value stored for enabled, 4 = use value passed for single wire, 5 = use value passed for listen only - //6 = use value passed for speed. This allows bus status to be updated but set that some things aren't really - //being passed. Just set for things that really are being updated. - void busStatus(int, int, int); - protected: virtual void piStarted(); @@ -37,8 +25,7 @@ protected: 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&); + virtual bool piSendFrame(const CANFrame&); void disconnectDevice(); diff --git a/connectionwindow.cpp b/connectionwindow.cpp index d9237e6..9ef7f3b 100644 --- a/connectionwindow.cpp +++ b/connectionwindow.cpp @@ -1,13 +1,18 @@ #include +#include #include "connectionwindow.h" #include "ui_connectionwindow.h" #include "connections/canconfactory.h" +#define FALSE 0 +#define TRUE 1 + ConnectionWindow::ConnectionWindow(CANFrameModel *cModel, QWidget *parent) : QDialog(parent), - ui(new Ui::ConnectionWindow) + ui(new Ui::ConnectionWindow), + mRefreshReqOngoing(FALSE) { ui->setupUi(this); @@ -104,17 +109,20 @@ void ConnectionWindow::showEvent(QShowEvent* event) } void ConnectionWindow::refreshCanList() { - QList::iterator conn_p; - QList& conns = connModel->getConnections(); + 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() ) ) { + foreach (CANConnection* conn_p, conns) + { + while( (frame_p = conn_p->getQueue().peek() ) ) { canModel->addFrame(*frame_p, true); - (*conn_p)->getQueue().dequeue(); + conn_p->getQueue().dequeue(); } } + + /* erase flag (this should be done before we start dequeuing...) */ + mRefreshReqOngoing.store(FALSE); } void ConnectionWindow::handleNewConn() @@ -272,8 +280,16 @@ void ConnectionWindow::handleOKButton() connect(conn_p, SIGNAL(status(CANCon::status)), this, SLOT(connectionStatus(CANCon::status))); + //conn_p->setCallback(std::bind(&ConnectionWindow::callback, this, std::placeholders::_1)); + /*TODO add return value and checks */ conn_p->start(); + /*{ + QVector flters; + flters.append({0x305, 0xFFFF, true}); + conn_p->setFilters(0, flters, false); + connect(conn_p, SIGNAL(notify()), this, SLOT(refreshCanList())); + }*/ for (int i=0 ; igetNumBuses() ; i++) { /* set bus configuration */ diff --git a/connectionwindow.h b/connectionwindow.h index 066cad0..5cc9b4c 100644 --- a/connectionwindow.h +++ b/connectionwindow.h @@ -8,8 +8,6 @@ #include #include #include -//#include "canconnection_old.h" -//#include "serialworker.h" #include "canconnectionmodel.h" #include "canframemodel.h" @@ -68,6 +66,7 @@ private: CANFrameModel *canModel; QTimer mTicker; + QAtomicInt mRefreshReqOngoing; void selectSerial(); void selectKvaser(); diff --git a/filecomparatorwindow.cpp b/filecomparatorwindow.cpp index 83f120e..c7aeea2 100644 --- a/filecomparatorwindow.cpp +++ b/filecomparatorwindow.cpp @@ -112,7 +112,7 @@ void FileComparatorWindow::calculateDetails() CANFrame frame = interestedFrames.at(x); if (interestedIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there { - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { interestedIDs[frame.ID].values[y][frame.data[y]]++; tmp = frame.data[y]; @@ -137,7 +137,7 @@ void FileComparatorWindow::calculateDetails() } } //memset(newData->values, 0, 256 * 8); - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { newData->values[y][frame.data[y]] = 1; tmp = frame.data[y]; @@ -177,7 +177,7 @@ void FileComparatorWindow::calculateDetails() } } //memset(newData->values, 0, 256 * 8); - for (int y = 0; y < frame.len; y++) + for (unsigned int y = 0; y < frame.len; y++) { newData->values[y][frame.data[y]] = 1; tmp = frame.data[y]; diff --git a/framefileio.cpp b/framefileio.cpp index 2e96149..94c612d 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -322,7 +322,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector* frames) else thisFrame.isReceived = true; thisFrame.bus = 0; thisFrame.len = tokens.length() - 3; - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) { if (tokens[d + 3] != "") { @@ -379,7 +379,7 @@ bool FrameFileIO::saveCRTDFile(QString filename, const QVector* frames outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); outFile->putChar(' '); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -446,9 +446,9 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) { thisFrame.isReceived = true; thisFrame.bus = tokens[3].toInt(); - thisFrame.len = tokens[4].toInt(); + thisFrame.len = tokens[4].toUInt(); for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16); } else if (fileVersion == 2) @@ -456,10 +456,10 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) if (tokens[3].at(0) == 'R') thisFrame.isReceived = true; else thisFrame.isReceived = false; thisFrame.bus = tokens[4].toInt(); - thisFrame.len = tokens[5].toInt(); - if (thisFrame.len + 6 > tokens.length()) thisFrame.len = tokens.length() - 6; + thisFrame.len = tokens[5].toUInt(); + if (thisFrame.len + 6 > (unsigned int) tokens.length()) thisFrame.len = tokens.length() - 6; for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; - for (int d = 0; d < thisFrame.len; d++) + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16); } @@ -570,7 +570,7 @@ bool FrameFileIO::loadGenericCSVFile(QString filename, QVector* frames QList dataTok = tokens[1].split(' '); thisFrame.len = dataTok.length(); if (thisFrame.len > 8) thisFrame.len = 8; - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataTok[d].toInt(NULL, 16); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataTok[d].toInt(NULL, 16); frames->append(thisFrame); } @@ -608,7 +608,7 @@ bool FrameFileIO::saveGenericCSVFile(QString filename, const QVector* outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); outFile->putChar(44); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -696,10 +696,9 @@ bool FrameFileIO::loadLogFile(QString filename, QVector* frames) if (tokens[4] == "s") thisFrame.extended = false; else thisFrame.extended = true; thisFrame.bus = tokens[2].toInt() - 1; - thisFrame.len = tokens[5].toInt(); + thisFrame.len = tokens[5].toUInt(); if (thisFrame.len > 8) thisFrame.len = 8; - if (thisFrame.len < 0) thisFrame.len = 0; - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16); frames->append(thisFrame); } else foundErrors = true; @@ -759,7 +758,7 @@ bool FrameFileIO::saveLogFile(QString filename, const QVector* frames) else outFile->write(" s "); outFile->write(QString::number(frames->at(c).len).toUtf8() + " "); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -836,7 +835,7 @@ bool FrameFileIO::loadIXXATFile(QString filename, QVector* frames) QStringList dataToks = unQuote(tokens[4]).simplified().split(' '); thisFrame.len = dataToks.length(); - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16); frames->append(thisFrame); } else foundErrors = true; @@ -889,7 +888,7 @@ bool FrameFileIO::saveIXXATFile(QString filename, const QVector* frame else outFile->write(",\"Std\""); outFile->write(",\"\",\""); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); @@ -952,7 +951,7 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector* frames) if (thisFrame.len <= 8 && thisFrame.ID <= 0x7FF) { - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d]; + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d]; frames->append(thisFrame); } else foundErrors = true; @@ -1008,7 +1007,7 @@ bool FrameFileIO::saveCANDOFile(QString filename, const QVector* frame data[1] = (char)(ms & 0xFF); data[2] = (char)(id & 0xFF); data[3] = (char)((id >> 8) + (thisFrame.len << 4)); - for (int d = 0; d < thisFrame.len; d++) data[4 + d] = (char)thisFrame.data[d]; + for (unsigned int d = 0; d < thisFrame.len; d++) data[4 + d] = (char)thisFrame.data[d]; outFile->write(data); } } @@ -1074,11 +1073,10 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector* frames) if (thisFrame.ID <= 0x7FF) thisFrame.extended = false; else thisFrame.extended = true; thisFrame.bus = 0; - thisFrame.len = tokens[3].toInt(); + thisFrame.len = tokens[3].toUInt(); if (thisFrame.len > 8) thisFrame.len = 8; - if (thisFrame.len < 0) thisFrame.len = 0; - if (thisFrame.len + 4 > tokens.length()) thisFrame.len = tokens.length() - 4; - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]); + if (thisFrame.len + 4 > (unsigned int) tokens.length()) thisFrame.len = tokens.length() - 4; + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]); frames->append(thisFrame); } else foundErrors = true; @@ -1140,7 +1138,7 @@ bool FrameFileIO::saveMicrochipFile(QString filename, const QVector* f outFile->write("0x" + QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8() + ";"); outFile->write(QString::number(frames->at(c).len).toUtf8() + ";"); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write("0x" + QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(';'); @@ -1233,12 +1231,11 @@ bool FrameFileIO::loadTraceFile(QString filename, QVector* frames) if (thisFrame.ID <= 0x7FF) thisFrame.extended = false; else thisFrame.extended = true; thisFrame.bus = 0; - thisFrame.len = tokens[3].toInt(); - if (thisFrame.len < 0) thisFrame.len = 0; + thisFrame.len = tokens[3].toUInt(); if (thisFrame.len > 8) thisFrame.len = 8; QList dataToks = tokens[4].split(' '); - if (thisFrame.len > dataToks.length()) thisFrame.len = dataToks.length(); - for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16); + if (thisFrame.len > (unsigned int) dataToks.length()) thisFrame.len = (unsigned int) dataToks.length(); + for (unsigned int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16); frames->append(thisFrame); } else foundErrors = true; @@ -1325,7 +1322,7 @@ bool FrameFileIO::saveTraceFile(QString filename, const QVector * fram outFile->write(QString::number(frames->at(c).len).toUtf8() + "\t"); - for (int temp = 0; temp < frames->at(c).len; temp++) + for (unsigned int temp = 0; temp < frames->at(c).len; temp++) { outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); outFile->putChar(' '); diff --git a/mainwindow.cpp b/mainwindow.cpp index b456467..f19f682 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -157,7 +157,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->lbNumFrames->setText("0"); connect(&updateTimer, &QTimer::timeout, this, &MainWindow::tickGUIUpdate); - updateTimer.setInterval(250); + updateTimer.setInterval(500); //test 250); updateTimer.start(); elapsedTime = new QTime; @@ -679,7 +679,7 @@ Data Bytes: 88 10 00 13 BB 00 06 00 outFile->write(builderString.toUtf8()); builderString = tr("Data Bytes: "); - for (int temp = 0; temp < thisFrame.len; temp++) + for (unsigned int temp = 0; temp < thisFrame.len; temp++) { builderString += Utility::formatNumber(thisFrame.data[temp]) + " "; } diff --git a/scriptcontainer.cpp b/scriptcontainer.cpp index 9e14e2d..84b7280 100644 --- a/scriptcontainer.cpp +++ b/scriptcontainer.cpp @@ -93,13 +93,12 @@ void ScriptContainer::sendFrame(QJSValue bus, QJSValue id, QJSValue length, QJSV CANFrame frame; frame.extended = false; frame.ID = id.toInt(); - frame.len = length.toInt(); - if (frame.len < 0) frame.len = 0; + frame.len = length.toUInt(); if (frame.len > 8) frame.len = 8; if (!data.isArray()) qDebug() << "data isn't an array"; - for (int i = 0; i < frame.len; i++) + for (unsigned int i = 0; i < frame.len; i++) { frame.data[i] = (uint8_t)data.property(i).toInt(); } @@ -125,7 +124,7 @@ void ScriptContainer::gotFrame(const CANFrame &frame) QJSValueList args; args << frame.bus << frame.ID << frame.len; QJSValue dataBytes = scriptEngine.newArray(frame.len); - for (int j = 0; j < frame.len; j++) dataBytes.setProperty(j, QJSValue(frame.data[j])); + for (unsigned int j = 0; j < frame.len; j++) dataBytes.setProperty(j, QJSValue(frame.data[j])); args.append(dataBytes); gotFrameFunction.call(args); return; //as soon as one filter matches we jump out diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..26abd34 --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,21 @@ +#include + +#include "tst_lfqueue.h" +#include "tst_cancon.h" + + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + int status = 0; + auto ASSERT_TEST = [&status, argc, argv](QObject* obj) { + status |= QTest::qExec(obj, argc, argv); + delete obj; + }; + + ASSERT_TEST(new TestLFQueue()); + ASSERT_TEST(new TestCanCon(CANCon::SOCKETCAN, "vcan0", 1)); + + return status; +} diff --git a/test/test.pro b/test/test.pro index 56c22c3..40c53f2 100644 --- a/test/test.pro +++ b/test/test.pro @@ -1,12 +1,19 @@ -QT += widgets testlib -QT -= gui +QT += core gui serialbus widgets testlib serialbus + CONFIG += c++11 -INCLUDEPATH += ../utils +INCLUDEPATH += ../ ../connections SOURCES += \ - tst_lfqueue.cpp + tst_lfqueue.cpp \ + main.cpp \ + tst_cancon.cpp \ + ../connections/canconfactory.cpp \ + ../connections/canconnection.cpp \ + ../connections/gvretserial.cpp \ + ../connections/socketcan.cpp \ + ../canbus.cpp #HEADERS += \ @@ -14,3 +21,13 @@ SOURCES += \ target.path= . INSTALLS += target + +HEADERS += \ + tst_lfqueue.h \ + tst_cancon.h \ + ../connections/canconconst.h \ + ../connections/canconfactory.h \ + ../connections/canconnection.h \ + ../connections/gvretserial.h \ + ../connections/socketcan.h \ + ../canbus.h diff --git a/test/tst_cancon.cpp b/test/tst_cancon.cpp new file mode 100644 index 0000000..eaf1eac --- /dev/null +++ b/test/tst_cancon.cpp @@ -0,0 +1,366 @@ +#include +#include + +#include "tst_cancon.h" +#include "canconnection.h" +#include "canconfactory.h" + + +#define QVERIFYB(statement) \ +do {\ + if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\ + return false;\ +} while (0) + +#define QCOMPAREB(actual, expected) \ +do {\ + if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ + return false;\ +} while (0) + +Q_DECLARE_METATYPE(QVector); + + + +TestCanCon::TestCanCon(CANCon::type pType, QString pPortName, int pNbBus): + mType(pType), + mPortName(pPortName), + mNbBus(pNbBus){} + +void TestCanCon::create() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + /* try to get an element from the queue */ + QVERIFY(conn_p->getQueue().get()); + + if(conn_p) + delete conn_p; +} + +void TestCanCon::connectToDevice() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + QSignalSpy spy(conn_p, SIGNAL(status(CANCon::status))); + + /* start connection */ + conn_p->start(); + + /* wait for a signal */ + for(int i=0 ; (spy.count() != 1) && (i < 10) ; i++) + QTest::qWait(500); + + + QCOMPARE(spy.count(), 1); // make sure the signal was emitted exactly one time + QList arguments = spy.takeFirst(); // take the first signal + + QVERIFY(arguments.at(0).toInt() == CANCon::CONNECTED); // verify the first argument + + /* stop connection */ + conn_p->stop(); + delete conn_p; +} + +void TestCanCon::recvFrames() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + int i; + for(i=0 ; queue.peek() && i<1000 ; i++) + { + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + queue.dequeue(); + } + + QVERIFY(i>0); + + /* stop connection */ + conn_p->stop(); + delete conn_p; +} + + +void TestCanCon::suspend() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + conn_p->suspend(true); + + /* the queue should be flushed */ + canf_p = queue.peek(); + QVERIFY(!canf_p); + + /* restart capture */ + conn_p->suspend(false); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + /* get a frame */ + canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + /* stop connection */ + conn_p->stop(); + delete conn_p; +} + + +void TestCanCon::filter_data() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + /* find 3 different ids */ + QVector ids; + + while( queue.peek() && ids.count()!=3 ) + { + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + if(!ids.contains(canf_p->ID)) + ids.append(canf_p->ID); + + queue.dequeue(); + } + + QCOMPARE(ids.count(), 3); + + /* stop connection */ + conn_p->stop(); + delete conn_p; + + /* prepare test vector */ + + QTest::addColumn>("filters"); + QTest::addColumn("filterOut"); + QTest::addColumn("signalReceived"); + QTest::addColumn>("filtered"); + + QVector filters; + QVector filteredIds; + + /* one filter no signal*/ + filters.clear(); + filteredIds.clear(); + filters.append({ids[0], 0xFFFF, false}); + filteredIds.append(ids[0]); + QTest::newRow("1filternosignal") << filters << false << false << filteredIds; + + /* one filter & signal*/ + filters.clear(); + filteredIds.clear(); + filters.append({ids[0], 0xFFFF, true}); + filteredIds.append(ids[0]); + QTest::newRow("1filtersignal") << filters << false << true << filteredIds; + + /* 3 filters */ + filters.clear(); + filteredIds.clear(); + foreach(quint32 id, ids) { + filters.append({id, 0xFFFF, false}); + filteredIds.append(id); + } + QTest::newRow("3filters") << filters << false << false << filteredIds; +} + + +void TestCanCon::filter() +{ + QFETCH(QVector, filters); + QFETCH(bool, filterOut); + QFETCH(bool, signalReceived); + QFETCH(QVector, filtered); + + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* set filters */ + for(int i=0 ; igetNumBuses() ; i++) + QVERIFY(conn_p->setFilters(i, filters, filterOut)); + + /* spy signal */ + QSignalSpy spy(conn_p, SIGNAL(notify())); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + LFQueue& queue = conn_p->getQueue(); + + /* wait for frames to arrive */ + QTest::qWait(1000); + + if(signalReceived) + QVERIFY(spy.count()>0); + + int i; + for(i=0 ; queue.peek() && i<1000 ; i++) + { + CANFrame* canf_p = queue.peek(); + QVERIFY(pValidateFrame(conn_p, canf_p)); + + if(filterOut) + QVERIFY(filtered.contains(canf_p->ID)); + + queue.dequeue(); + } + + QVERIFY(i>0); + + conn_p->stop(); + delete conn_p; +} + + +void TestCanCon::write() +{ + CANConnection* conn_p; + QVERIFY(pCreate(conn_p)); + + /* start connection */ + conn_p->start(); + + /* configure */ + QVERIFY(pConfig(conn_p)); + + QList frames; + /* build frames */ + CANFrame frame; + frame.bus = 0; + frame.ID = 0x1DE; + frame.data[0] = 0xDE; + frame.data[1] = 0xAD; + frame.data[2] = 0xC0; + frame.data[3] = 0xDE; + frame.len = 4; + + frames.append(frame); + + frame.data[2] = 0xBE; + frame.data[3] = 0xEF; + frames.append(frame); + + frame.data[2] = 0xDE; + frame.data[3] = 0xAD; + + + /* bad frame length */ + unsigned int oldVal = frame.len; + frame.len = 9; + QCOMPARE(conn_p->sendFrame(frame), false); + frame.len = oldVal; + + /* bad bus id */ + oldVal = frame.bus; + frame.bus = 48; + QCOMPARE(conn_p->sendFrame(frame), false); + frame.bus = oldVal; + + qDebug() << "Sending DE AD DE AD"; + /* send */ + QVERIFY(conn_p->sendFrame(frame)); + + /* leave some time for the frame to be sent */ + QTest::qWait(1000); + + qDebug() << "Sending DE AD C0 DE"; + qDebug() << "Sending DE AD BE EF"; + /* send */ + QVERIFY(conn_p->sendFrames(frames)); + + /* leave some time for the frame to be sent */ + QTest::qWait(1000); + + conn_p->stop(); + delete conn_p; +} + + +/*********************************************************/ + +bool TestCanCon::pCreate(CANConnection*& pConn_p) +{ + pConn_p = CanConFactory::create(mType, mPortName); + QVERIFYB(pConn_p); + + QCOMPAREB(pConn_p->getPort(), mPortName); + QCOMPAREB(pConn_p->getNumBuses(), mNbBus); + QCOMPAREB(pConn_p->getType(), mType); + QCOMPAREB(pConn_p->getStatus(), CANCon::NOT_CONNECTED); + + return true; +} + +bool TestCanCon::pConfig(CANConnection* pConn_p) +{ + /*configure buses */ + CANBus bus; + CANBus retBus; + for(int i=0 ; igetNumBuses() ; i++) + { + /* TODO: fix configuration */ + bus.active = true; + pConn_p->setBusSettings(i, bus); + QVERIFYB(pConn_p->getBusSettings(i, retBus)); + QCOMPAREB(bus, retBus); + } + + return true; +} + +bool TestCanCon::pValidateFrame(CANConnection* pConn_p, CANFrame* pCan_p) +{ + QVERIFYB( pCan_p ); + QVERIFYB( (0<=pCan_p->bus) && (pCan_p->bus <= pConn_p->getNumBuses()) ); + QVERIFYB( pCan_p->isReceived); + QVERIFYB( pCan_p->len<=8 ); + QVERIFYB( (0<=pCan_p->ID) && (pCan_p->ID<2048) ); + + return true; +} diff --git a/test/tst_cancon.h b/test/tst_cancon.h new file mode 100644 index 0000000..2d79bd4 --- /dev/null +++ b/test/tst_cancon.h @@ -0,0 +1,33 @@ +#ifndef TESTCANCON_H +#define TESTCANCON_H + +#include +#include "canconconst.h" +#include "canconnection.h" + +class TestCanCon: public QObject +{ + Q_OBJECT +public: + TestCanCon(CANCon::type, QString pPortName, int pNbBus); +private: + CANCon::type mType; + QString mPortName; + int mNbBus; + +private slots: + void create(); + void connectToDevice(); + void recvFrames(); + void suspend(); + void filter(); + void filter_data(); + void write(); + +private: + bool pCreate(CANConnection*& pConn_p); + bool pConfig(CANConnection* pConn_p); + bool pValidateFrame(CANConnection* pConn_p, CANFrame* pCan_p); +}; + +#endif // TESTCANCON_H diff --git a/test/tst_lfqueue.cpp b/test/tst_lfqueue.cpp index 1120de5..4343f47 100644 --- a/test/tst_lfqueue.cpp +++ b/test/tst_lfqueue.cpp @@ -1,19 +1,10 @@ -#include +#include + #include -#include "lfqueue.h" +#include "utils/lfqueue.h" +#include "tst_lfqueue.h" -class TestLFQueue: public QObject -{ - Q_OBJECT -private: - -private slots: - void setSize_data(); - void setSize(); - void exchange_data(); - void exchange(); -}; void TestLFQueue::setSize_data() @@ -92,7 +83,3 @@ void TestLFQueue::exchange() thread.waitForFinished(); } - - -QTEST_MAIN(TestLFQueue) -#include "tst_lfqueue.moc" diff --git a/test/tst_lfqueue.h b/test/tst_lfqueue.h new file mode 100644 index 0000000..315bf75 --- /dev/null +++ b/test/tst_lfqueue.h @@ -0,0 +1,18 @@ +#ifndef TST_LFQUEUE_H +#define TST_LFQUEUE_H + +#include + +class TestLFQueue: public QObject +{ + Q_OBJECT +private: + +private slots: + void setSize_data(); + void setSize(); + void exchange_data(); + void exchange(); +}; + +#endif // TST_LFQUEUE_H