diff --git a/connections/canconconst.h b/connections/canconconst.h index 707355d..b31301b 100644 --- a/connections/canconconst.h +++ b/connections/canconconst.h @@ -19,6 +19,13 @@ namespace CANCon { SOCKETCAN, NONE }; + + /* test */ + enum cbtype + { + READ, + WRITE + }; } #endif // CANCONCONST_H diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 526d88e..d0d8014 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,6 +21,8 @@ CANConnection::CANConnection(QString pPort, mType(pType), mIsCapSuspended(false), mStatus(CANCon::NOT_CONNECTED), + mStarted(false), + mCallback(NULL), mThread_p(NULL) { qDebug() << "CANConnection()"; @@ -20,16 +31,18 @@ CANConnection::CANConnection(QString pPort, 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 ; i= 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; } @@ -231,6 +245,13 @@ CANCon::status CANConnection::getStatus() { } +bool CANConnection::setCallback(std::function pCallback) { + if(mStarted || !pCallback) return false; + mCallback = pCallback; + return true; +} + + void CANConnection::setStatus(CANCon::status pStatus) { mStatus.store(pStatus); } @@ -243,3 +264,62 @@ void CANConnection::setCapSuspended(bool pIsSuspended) { mIsCapSuspended = pIsSuspended; } +void CANConnection::callback(CANCon::cbtype pCbType) { + if(mCallback) + mCallback(pCbType); +} + +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; +} + + +/* 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..99cd668 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -8,6 +8,7 @@ #include "canbus.h" #include "canconconst.h" +struct BusData; class CANConnection : public QObject { @@ -64,6 +65,13 @@ public: */ CANCon::status getStatus(); + /** + * @brief set the callback function, this call has to be placed before calling start + * @param pCallback + * @return true if callback can be set + */ + bool setCallback(std::function pCallback); + signals: /*not implemented yet */ @@ -76,6 +84,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 @@ -136,6 +149,14 @@ public slots: */ void sendFrameBatch(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 +207,22 @@ protected: */ void setCapSuspended(bool pIsSuspended); + /** + * @brief call callback function + * @param pCbType callback type (read or write) + */ + void callback(CANCon::cbtype pCbType); + + /** + * @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: /**************************************************************/ @@ -236,16 +273,24 @@ protected: */ virtual void piSendFrameBatch(const QList&) = 0; + /** + * @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; + std::function mCallback; + BusData* mBusData_p; QThread* mThread_p; }; diff --git a/connections/gvretserial.h b/connections/gvretserial.h index 350277f..4ef824c 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(); diff --git a/connections/socketcan.cpp b/connections/socketcan.cpp index 16fff23..7da09f0 100644 --- a/connections/socketcan.cpp +++ b/connections/socketcan.cpp @@ -142,6 +142,10 @@ void SocketCan::framesWritten(qint64 count) void SocketCan::framesReceived() { + /* test */ + bool enqueued = false; + bool sndNotif = false; + /* sanity checks */ if(!mDev_p) return; @@ -153,15 +157,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) { @@ -175,13 +180,20 @@ void SocketCan::framesReceived() /* enqueue frame */ getQueue().queue(); + /* set enqueued */ + enqueued = true; } else qDebug() << "can't get a frame, ERROR"; } - else { - qDebug() << "invalid frame"; - } + } + + if(enqueued) { + callback(CANCon::READ); + } + + if(sndNotif) { + emit notify(); } } diff --git a/connections/socketcan.h b/connections/socketcan.h index dd1877b..0d0af5b 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();