From beea680106a0f1e8c9520fdd95cef7c70c36f420 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 29 Dec 2016 19:13:51 -0500 Subject: [PATCH] Changed the way the filter system works in the CAN connection objects - now used only for sending frames immediately to relevant objects. Tested to work in firmware updater. Currently broken elsewhere. Also switched main frame update interval from 4 times per second to 8 to make things smoother. --- can_structs.h | 1 - connections/canconmanager.cpp | 69 +++++++++++++++++++++++++++- connections/canconmanager.h | 20 ++++++++- connections/canconnection.cpp | 84 ++++++++++++++++++++--------------- connections/canconnection.h | 43 ++++++++---------- connections/gvretserial.cpp | 1 + connections/socketcan.cpp | 12 ++--- firmwareuploaderwindow.cpp | 11 ++++- firmwareuploaderwindow.h | 3 +- mainwindow.cpp | 2 - scriptcontainer.cpp | 13 +++--- 11 files changed, 172 insertions(+), 87 deletions(-) diff --git a/can_structs.h b/can_structs.h index d9fa1c5..3b6f222 100644 --- a/can_structs.h +++ b/can_structs.h @@ -20,7 +20,6 @@ struct CANFlt { quint32 id; quint32 mask; - bool notify; }; struct J1939ID diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index a0a061d..487c750 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -17,7 +17,7 @@ CANConManager* CANConManager::getInstance() CANConManager::CANConManager(QObject *parent): QObject(parent) { connect(&mTimer, SIGNAL(timeout()), this, SLOT(refreshCanList())); - mTimer.setInterval(250); /*tick 4 times a second */ + mTimer.setInterval(125); /*tick 8 times a second */ mTimer.setSingleShot(false); mTimer.start(); @@ -38,7 +38,8 @@ CANConManager::~CANConManager() void CANConManager::add(CANConnection* pConn_p) { - connect(pConn_p, SIGNAL(notify()), this, SLOT(refreshCanList())); + //connect(pConn_p, SIGNAL(notify()), this, SLOT(refreshCanList())); + connect(pConn_p, SIGNAL(targettedFrameReceived(CANFrame)), this, SLOT(gotTargettedFrame(CANFrame))); mConns.append(pConn_p); emit connectionStatusUpdated(getNumBuses()); } @@ -179,3 +180,67 @@ bool CANConManager::sendFrames(const QList& pFrames) return true; } + +//For each device associated with buses go through and see if that device has a bus +//that the filter should apply to. If so forward the data on but fudge +//the bus numbers if bus wasn't -1 so that they're local to the device +bool CANConManager::addTargettedFrame(int pBusId, const CANFlt &target) +{ + int tempBusVal; + int busBase = 0; + + foreach (CANConnection* conn, mConns) + { + if (pBusId == -1) conn->addTargettedFrame(pBusId, target); + else + { + tempBusVal = pBusId >> busBase; + tempBusVal &= ((1 << conn->getNumBuses()) - 1); + if (tempBusVal) { + qDebug() << "Forwarding targetted frame setting to a connection object"; + conn->addTargettedFrame(tempBusVal, target); + } + } + busBase += conn->getNumBuses(); + } +} + +bool CANConManager::removeTargettedFrame(int pBusId, const CANFlt &target) +{ + int tempBusVal; + int busBase = 0; + + foreach (CANConnection* conn, mConns) + { + if (pBusId == -1) conn->removeTargettedFrame(pBusId, target); + else + { + tempBusVal = pBusId >> busBase; + tempBusVal &= ((1 << conn->getNumBuses()) - 1); + if (tempBusVal) conn->removeTargettedFrame(tempBusVal, target); + } + busBase += conn->getNumBuses(); + } +} + +/* + * A connected CANConnection object has passed us a frame that one or more + * other objects are interested in. Fix up the bus number to be a system global bus + * number instead of connection local bus number then send it off again. +*/ +void CANConManager::gotTargettedFrame(CANFrame frame) +{ + int busBase = 0; + + foreach (CANConnection* conn, mConns) + { + if (conn != sender()) busBase += conn->getNumBuses(); + else break; + } + + qDebug() << "Targetted frame, offset was " << busBase << " id was " << frame.ID; + + frame.bus += busBase; + + emit targettedFrameReceived(frame); +} diff --git a/connections/canconmanager.h b/connections/canconmanager.h index 5abfae9..9467f8a 100644 --- a/connections/canconmanager.h +++ b/connections/canconmanager.h @@ -36,12 +36,30 @@ public: //just the multi-frame version of above function. bool sendFrames(const QList& pFrames); + /** + * @brief Add a new filter for the targetted frames. If a frame matches it will immediately be sent via the targettedFrameReceived signal + * @param pBusId - Which bus to bond to. -1 for any, otherwise a bitfield of buses (but 0 = first bus, etc) + * @param target - The filter to use for selected targetted frames + * @return true if filter was able to be added, false otherwise. + */ + bool addTargettedFrame(int pBusId, const CANFlt &target); + + /** + * @brief Try to find a matching filter in the list and remove it, no longer targetting those frames + * @param pBusId - Which bus to bond to. Doesn't have to match the call to addTargettedFrame exactly. You could disconnect just one bus for instance. + * @param target - The filter that was set + * @return true if filter was found and deleted, false otherwise. + */ + bool removeTargettedFrame(int pBusId, const CANFlt &target); + signals: void framesReceived(CANConnection* pConn_p, QVector& pFrames); + void targettedFrameReceived(CANFrame frame); void connectionStatusUpdated(int conns); private slots: - void refreshCanList(); + void refreshCanList(); + void gotTargettedFrame(CANFrame frame); private: explicit CANConManager(QObject *parent = 0); diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 778890f..9f29e39 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -5,8 +5,7 @@ struct BusData { CANBus mBus; bool mConfigured; - QVector mFilters; - bool mFilterOut; + QVector mTargettedFrames; }; @@ -38,7 +37,6 @@ CANConnection::CANConnection(QString pPort, mBusData_p = new BusData[mNumBuses]; for(int i=0 ; i& pFilters, bool pFilterOut) +bool CANConnection::addTargettedFrame(int pBusId, const CANFlt &target) { /* make sure we execute in mThread context */ if( mThread_p && (mThread_p != QThread::currentThread()) ) { bool ret; - QMetaObject::invokeMethod(this, "setFilters", + QMetaObject::invokeMethod(this, "addTargettedFrame", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ret), Q_ARG(int , pBusId), - Q_ARG(const QVector&, pFilters), - Q_ARG(bool , pFilterOut)); + Q_ARG(const CANFlt&, target)); return ret; } /* sanity checks */ - if(pBusId<0 || pBusId>=getNumBuses()) + if(pBusId < -1 || pBusId >= (1 << 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); + for (int i = 0; i < getNumBuses(); i++) + { + if (pBusId == -1 || pBusId && (1 << i)) { + qDebug() << "Connection is registering a new targetted frame filter"; + mBusData_p[i].mTargettedFrames.append(target); + } + } return true; } - -bool CANConnection::discard(int pBusId, quint32 pId, bool& pNotify) +bool CANConnection::removeTargettedFrame(int pBusId, const CANFlt &target) { - 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; - } + /* make sure we execute in mThread context */ + if( mThread_p && (mThread_p != QThread::currentThread()) ) { + bool ret; + QMetaObject::invokeMethod(this, "addTargettedFrame", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, ret), + Q_ARG(int , pBusId), + Q_ARG(const CANFlt&, target)); + return ret; } - return mBusData_p[pBusId].mFilterOut; + + /* sanity checks */ + if(pBusId < -1 || pBusId >= (1 << getNumBuses())) + return false; + + for (int i = 0; i < getNumBuses(); i++) + { + //if (pBusId == -1 || (pBusId && (1 << i))) + //mBusData_p[i].mTargettedFrames.removeOne(target); + } + + return true; } +void CANConnection::checkTargettedFrame(CANFrame &frame) +{ + int maskedID; + foreach (const CANFlt filt, mBusData_p[frame.bus].mTargettedFrames) + { + maskedID = frame.ID & filt.mask; + if (maskedID == filt.id) { + qDebug() << "In connection object I got a targetted frame. Forwarding it."; + emit targettedFrameReceived(frame); + return; //only match once then stop. + } + } +} bool CANConnection::piSendFrames(const QList& pFrames) { @@ -316,11 +334,3 @@ bool CANConnection::piSendFrames(const QList& pFrames) 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 b0c8f51..8633a2a 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -81,9 +81,9 @@ signals: void busStatus(int, int, int); /** - * @brief event sent when a frame matching a filter set with notification hs been received + * @brief event sent when a frame matching a filter is received */ - void notify(); + void targettedFrameReceived(CANFrame frame); /** * @brief event emitted when the CANCon::status of the connection changes (connected->not_connected or the other way round) @@ -149,15 +149,26 @@ public slots: 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 + * @brief Add a new filter for the targetted frames. If a frame matches it will immediately be sent via the targettedFrameReceived signal + * @param pBusId - Which bus to bond to. -1 for any, otherwise a bitfield of buses (but 0 = first bus, etc) + * @param target - The filter to use for selected targetted frames + * @return true if filter was able to be added, false otherwise. */ - bool setFilters(int pBusId, const QVector& pFilters, bool pFilterOut); + bool addTargettedFrame(int pBusId, const CANFlt &target); + + /** + * @brief Try to find a matching filter in the list and remove it, no longer targetting those frames + * @param pBusId - Which bus to bond to. Doesn't have to match the call to addTargettedFrame exactly. You could disconnect just one bus for instance. + * @param target - The filter that was set + * @return true if filter was found and deleted, false otherwise. + */ + bool removeTargettedFrame(int pBusId, const CANFlt &target); protected: + //determine if the passed frame is part of a filter or not. + void checkTargettedFrame(CANFrame &frame); + /** * @brief setStatus * @param pStatus: the status to set @@ -206,16 +217,6 @@ 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: /**************************************************************/ @@ -269,14 +270,6 @@ protected: */ 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: LFQueue mQueue; const int mNumBuses; diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index af60a1e..d669118 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -417,6 +417,7 @@ void GVRetSerial::procRXChar(unsigned char c) //qDebug() << "GVRET got frame on bus " << frame_p->bus; /* copy frame */ *frame_p = buildFrame; + checkTargettedFrame(buildFrame); /* enqueue frame */ getQueue().queue(); } diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index fd6efc3..2250fc0 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -155,9 +155,6 @@ void SocketCan::framesWritten(qint64 count) void SocketCan::framesReceived() { - /* test */ - bool sndNotif = false; - uint64_t timeBasis = CANConManager::getInstance()->getTimeBasis(); /* sanity checks */ @@ -179,8 +176,7 @@ void SocketCan::framesReceived() /* check frame */ if( !recFrame.payload().isEmpty() && - recFrame.payload().length()<=8 && - !discard(0, recFrame.frameId(), sndNotif) ) + recFrame.payload().length()<=8 ) { CANFrame* frame_p = getQueue().get(); if(frame_p) { @@ -192,6 +188,8 @@ void SocketCan::framesReceived() frame_p->isReceived = true; frame_p->timestamp = (recFrame.timeStamp().seconds()*1000000 + recFrame.timeStamp().microSeconds()) - timeBasis; + checkTargettedFrame(*frame_p); + /* enqueue frame */ getQueue().queue(); } @@ -201,10 +199,6 @@ void SocketCan::framesReceived() #endif } } - - if(sndNotif) { - emit notify(); - } } diff --git a/firmwareuploaderwindow.cpp b/firmwareuploaderwindow.cpp index e6cef48..8d12f14 100644 --- a/firmwareuploaderwindow.cpp +++ b/firmwareuploaderwindow.cpp @@ -27,10 +27,17 @@ FirmwareUploaderWindow::FirmwareUploaderWindow(const QVector *frames, timer = new QTimer(); timer->setInterval(100); //100ms without a reply will cause us to attempt a resend + CANFlt firmwareFilter; + firmwareFilter.id = 0x100; + firmwareFilter.mask = 0x7F0; + CANConManager::getInstance()->addTargettedFrame(-1, firmwareFilter); + //MainWindow::getReference()->setTargettedID(baseAddress + 0x10); + connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(handleLoadFile())); connect(ui->btnStartStop, SIGNAL(clicked(bool)), this, SLOT(handleStartStopTransfer())); connect(timer, SIGNAL(timeout()), this, SLOT(timerElapsed())); + connect(CANConManager::getInstance(), SIGNAL(targettedFrameReceived(CANFrame)), this, SLOT(gotTargettedFrame(CANFrame))); } FirmwareUploaderWindow::~FirmwareUploaderWindow() @@ -66,9 +73,9 @@ void FirmwareUploaderWindow::updatedFrames(int numFrames) } } -void FirmwareUploaderWindow::gotTargettedFrame(int frameLoc) +void FirmwareUploaderWindow::gotTargettedFrame(CANFrame frame) { - const CANFrame &frame = modelFrames->at(frameLoc); + qDebug() << "FUW: Got targetted frame with id " << frame.ID; if (frame.ID == (baseAddress + 0x10)) { qDebug() << "Start firmware reply"; if ((frame.data[0] == 0xAD) && (frame.data[1] == 0xDE)) diff --git a/firmwareuploaderwindow.h b/firmwareuploaderwindow.h index 22221b9..ec07906 100644 --- a/firmwareuploaderwindow.h +++ b/firmwareuploaderwindow.h @@ -4,6 +4,7 @@ #include #include #include "can_structs.h" +#include "connections/canconmanager.h" #include "utility.h" namespace Ui { @@ -22,7 +23,7 @@ signals: void sendCANFrame(const CANFrame *); public slots: - void gotTargettedFrame(int frameLoc); + void gotTargettedFrame(CANFrame frame); private slots: void handleLoadFile(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 69af4e3..7d12ef2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -852,8 +852,6 @@ void MainWindow::showFirmwareUploaderWindow() if (!firmwareUploaderWindow) { firmwareUploaderWindow = new FirmwareUploaderWindow(model->getListReference()); - //connect(firmwareUploaderWindow, SIGNAL(sendCANFrame(const CANFrame*)), connectionWindow, SLOT(sendFrame(const CANFrame*))); - //connect(worker, SIGNAL(gotTargettedFrame(int)), firmwareUploaderWindow, SLOT(gotTargettedFrame(int))); } firmwareUploaderWindow->show(); } diff --git a/scriptcontainer.cpp b/scriptcontainer.cpp index 5c4bfa4..c605bb2 100644 --- a/scriptcontainer.cpp +++ b/scriptcontainer.cpp @@ -71,18 +71,17 @@ void ScriptContainer::setFilter(QJSValue id, QJSValue mask, QJSValue bus) CANConnection* conn_p = CANConManager::getInstance()->getByName(mConName); if(conn_p) { + CANFlt canFlt; for(int i=0 ; igetNumBuses() ; i++) { - QVector fltrs; foreach(const CANFilter& flt, filters) { if(flt.bus==i) { - fltrs.append({flt.ID, flt.mask, true}); + canFlt.id = idVal; + canFlt.mask = maskVal; + conn_p->addTargettedFrame(busVal, canFlt); } } - - if(fltrs.size()) - conn_p->setFilters(i, fltrs, false); } } } @@ -108,8 +107,8 @@ void ScriptContainer::clearFilters() CANConnection* conn_p = CANConManager::getInstance()->getByName(mConName); if(conn_p) { - for(int i=0 ; igetNumBuses() ; i++) - conn_p->setFilters(i, QVector(), false); + //for(int i=0 ; igetNumBuses() ; i++) + //conn_p->setFilters(i, QVector(), false); } }