Skip to content

Commit

Permalink
more thread abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
canpadawan committed Jun 16, 2016
1 parent 71e989a commit d1c5642
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 229 deletions.
150 changes: 147 additions & 3 deletions connections/canconnection.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,179 @@
#include <QThread>
#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>("CANBus");
qRegisterMetaType<CANFrame>("CANFrame");
qRegisterMetaType<CANCon::status>("CANCon::status");

/* set queue size */
mQueue.setSize(pQueueLen); /*TODO add check on returned value */

/* allocate buses */
mBus = new CANBus[mNumBuses];
mConfigured = new bool[mNumBuses];

for(int i=0 ; i<mNumBuses ; i++)
mConfigured[i] = false;

/* if needed, create a thread and move ourself into it */
if(pUseThread) {
mThread_p = new QThread();
}
}


CANConnection::~CANConnection()
{
qDebug() << "~CANConnection()";

/* stop and delete thread */
if(mThread_p) {
mThread_p->quit();
mThread_p->wait();
delete mThread_p;
mThread_p = NULL;
}

/* delete bus table */
delete[] mBus;
mBus = NULL;
/* configured table */
delete[] mConfigured;
mConfigured = NULL;
/* 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<CANFrame>& pFrames)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "sendFrameBatch",
Qt::BlockingQueuedConnection,
Q_ARG(const QList<CANFrame>&, pFrames));
return;
}

return piSendFrameBatch(pFrames);
}


Expand Down
88 changes: 65 additions & 23 deletions connections/canconnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ class CANConnection : public QObject
* @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
*/
Expand All @@ -31,50 +34,33 @@ class CANConnection : public QObject
/**
* @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<CANFrame>& 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 &);
Expand All @@ -95,30 +81,45 @@ class CANConnection : public QObject

public slots:

virtual void sendFrame(const CANFrame *) = 0;
virtual void sendFrameBatch(const QList<CANFrame> *) = 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<CANFrame>&);

protected:

Expand Down Expand Up @@ -177,6 +178,46 @@ public slots:
*/
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<CANFrame>&) = 0;


private:
CANBus* mBus;
bool* mConfigured;
Expand All @@ -186,6 +227,7 @@ public slots:
const CANCon::type mType;
bool mIsCapSuspended;
QAtomicInt mStatus;
QThread* mThread_p;
};

#endif // CANCONNECTION_H
Loading

0 comments on commit d1c5642

Please sign in to comment.