From 80719b253b8ae4490ca796bba7d81dc7021ff6e6 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Wed, 15 Jun 2016 18:18:56 +0200 Subject: [PATCH] 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