Commit 573694ab authored by Thomas BOUTROUE's avatar Thomas BOUTROUE

Attemp to simplify code design and performance of SDO queues

parent 7d9a7549
#ifndef ARRAYBYID_H
#define ARRAYBYID_H
#include <QObject>
template<typename VAL_TYPE, typename ID_TYPE, int MIN_ID, int MAX_ID> struct ArrayById {
private:
static const int SIZE = (MAX_ID - MIN_ID +1);
VAL_TYPE * _entries [SIZE];
public:
explicit ArrayById (QObject * parent) {
for (ID_TYPE id = MIN_ID; id <= MAX_ID; ++id) {
_entries [id - MIN_ID] = new VAL_TYPE (id, parent);
}
}
virtual ~ArrayById (void) { }
inline VAL_TYPE * getById (const ID_TYPE id) {
return (id >= MIN_ID && id <= MAX_ID ? _entries [id - MIN_ID] : Q_NULLPTR);
}
inline const VAL_TYPE * getById (const ID_TYPE id) const {
return (id >= MIN_ID && id <= MAX_ID ? _entries [id - MIN_ID] : Q_NULLPTR);
}
inline VAL_TYPE ** begin (void) { return &_entries [0]; }
inline VAL_TYPE ** end (void) { return &_entries [SIZE]; }
};
#endif // ARRAYBYID_H
......@@ -41,6 +41,7 @@ Project {
Group {
name: "C++ headers";
files: [
"ArrayById.h",
"CanOpenDefs.h",
"CanOpenEntry.h",
"CanOpenSubEntry.h",
......
......@@ -123,58 +123,103 @@ void CanOpenSdoTransfer::markClean (void) {
/*** CAN OPEN SDO TRANSFERS QUEUE ***/
CanOpenSdoTransferQueue::CanOpenSdoTransferQueue (const CanOpenNodeId nodeId, const CanOpenSdoMode mode)
: timeout (1000)
, nodeId (nodeId)
, mode (mode)
, timer (new QTimer)
, currentTransfer (Q_NULLPTR)
CanOpenSdoTransferQueue::CanOpenSdoTransferQueue (const CanOpenNodeId nodeId, QObject * parent)
: QObject (parent)
, _mode (CanOpenSdoModes::SdoNeiter)
, _currentTransfer (Q_NULLPTR)
, NODE_ID (nodeId)
{
timer->setProperty ("nodeId", nodeId);
timer->setTimerType (Qt::PreciseTimer);
timer->setSingleShot (true);
_timerError.setSingleShot (true);
_timerError.setTimerType (Qt::PreciseTimer);
_timerProcess.setSingleShot (false);
_timerProcess.setTimerType (Qt::PreciseTimer);
connect (&_timerError, &QTimer::timeout, this, &CanOpenSdoTransferQueue::onTimeoutError);
connect (&_timerProcess, &QTimer::timeout, this, &CanOpenSdoTransferQueue::processNeeded);
}
void CanOpenSdoTransferQueue::killTimer (void) {
if (timer->isActive ()) {
timer->stop ();
CanOpenSdoMode CanOpenSdoTransferQueue::getMode (void) const {
return _mode;
}
CanOpenNodeId CanOpenSdoTransferQueue::getNodeId (void) const {
return NODE_ID;
}
void CanOpenSdoTransferQueue::reset (void) {
QMutexLocker locker (&_mutex);
killTimeoutWatcher ();
_mode = CanOpenSdoModes::SdoNeiter;
if (_currentTransfer != Q_NULLPTR) {
delete _currentTransfer;
_currentTransfer = Q_NULLPTR;
}
qDeleteAll (_transfersQueue);
_transfersQueue.clear ();
}
void CanOpenSdoTransferQueue::restartTimer (void) {
killTimer ();
timer->start (timeout);
void CanOpenSdoTransferQueue::reconfigure (const CanOpenSdoMode mode, const int timeout) {
_mode = mode;
_timerError.setInterval (timeout);
}
void CanOpenSdoTransferQueue::killTimeoutWatcher (void) {
if (_timerError.isActive ()) {
_timerError.stop ();
}
}
void CanOpenSdoTransferQueue::restartTimeoutWatcher (void) {
killTimeoutWatcher ();
_timerError.start ();
}
void CanOpenSdoTransferQueue::addPendingTransfer (CanOpenSdoTransfer * transfer) {
QMutexLocker locker (&mutex);
if (currentTransfer == Q_NULLPTR && transfersQueue.isEmpty ()) {
currentTransfer = transfer;
QMutexLocker locker (&_mutex);
if (_currentTransfer == Q_NULLPTR && _transfersQueue.isEmpty ()) {
_currentTransfer = transfer;
transfer->markDirty ();
_timerProcess.start (0);
}
else {
transfersQueue.enqueue (transfer);
_transfersQueue.enqueue (transfer);
}
}
CanOpenSdoTransfer * CanOpenSdoTransferQueue::getCurrentTransfer (void) {
QMutexLocker locker (&mutex);
return currentTransfer;
QMutexLocker locker (&_mutex);
return _currentTransfer;
}
bool CanOpenSdoTransferQueue::hasCurrentTransfer (void) {
QMutexLocker locker (&_mutex);
return (_currentTransfer != Q_NULLPTR);
}
void CanOpenSdoTransferQueue::prepareNextTransfer (void) {
QMutexLocker locker (&mutex);
if (currentTransfer == Q_NULLPTR && !transfersQueue.isEmpty ()) {
currentTransfer = transfersQueue.dequeue ();
currentTransfer->markDirty ();
QMutexLocker locker (&_mutex);
if (_currentTransfer == Q_NULLPTR && !_transfersQueue.isEmpty ()) {
_currentTransfer = _transfersQueue.dequeue ();
_currentTransfer->markDirty ();
_timerProcess.start (0);
}
}
void CanOpenSdoTransferQueue::resetCurrentTransfer (void) {
QMutexLocker locker (&mutex);
if (currentTransfer != Q_NULLPTR) {
delete currentTransfer;
currentTransfer = Q_NULLPTR;
QMutexLocker locker (&_mutex);
if (_currentTransfer != Q_NULLPTR) {
delete _currentTransfer;
_currentTransfer = Q_NULLPTR;
_timerProcess.start (0);
}
}
void CanOpenSdoTransferQueue::onTimeoutError (void) {
QMutexLocker locker (&_mutex);
if (_currentTransfer == Q_NULLPTR) {
QMutexLocker sublocker (&_currentTransfer->mutex);
_currentTransfer->errState = CanOpenSdoAbortCodes::ProtocolTimeout;
_currentTransfer->markDirty ();
_timerProcess.start (0);
}
}
......@@ -352,10 +397,72 @@ void CanOpenLssQueue::restartTimer (void) {
timer->start (timeout);
}
CanOpenHeartbeatConsumer::CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId)
: nodeId (nodeId)
, state (CanOpenHeartBeatStates::Initializing)
, watchdog ()
, timeout (0x0000)
, alive (false)
{ }
CanOpenHeartbeatConsumer::CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId, QObject * parent)
: QObject (parent)
, NODE_ID (nodeId)
, m_state (CanOpenHeartBeatStates::Initializing)
, m_timeout (0x0000)
, m_alive (false)
{
connect (&m_watchdog, &QTimer::timeout, this, &CanOpenHeartbeatConsumer::onWatchdogExpired);
}
CanOpenHeartbeatConsumer::~CanOpenHeartbeatConsumer (void) { }
bool CanOpenHeartbeatConsumer::isAlive (void) const {
return m_alive;
}
CanOpenNodeId CanOpenHeartbeatConsumer::getNodeId (void) const {
return NODE_ID;
}
CanOpenHeartBeatState CanOpenHeartbeatConsumer::lastKnownState (void) const {
return m_state;
}
void CanOpenHeartbeatConsumer::reset (void) {
if (m_watchdog.isActive ()) {
m_watchdog.stop ();
}
m_alive = false;
m_state = CanOpenHeartBeatState::Initializing;
m_timeout = 0;
}
void CanOpenHeartbeatConsumer::reconfigure (const quint16 timeout) {
if (m_timeout != timeout) {
m_timeout = timeout;
m_watchdog.stop ();
if (m_timeout > 0) {
m_watchdog.start (m_timeout);
}
}
}
void CanOpenHeartbeatConsumer::handleState (const CanOpenHeartBeatState state) {
if (m_watchdog.isActive ()) {
m_watchdog.stop ();
}
if (m_timeout > 0) {
m_watchdog.start (m_timeout);
if (!m_alive) {
m_alive = true;
emit aliveChanged (NODE_ID, m_alive);
}
if (m_state != state) {
m_state = state;
emit stateChanged (NODE_ID, m_state);
}
}
}
void CanOpenHeartbeatConsumer::onWatchdogExpired (void) {
if (m_watchdog.isActive ()) {
m_watchdog.stop ();
}
if (m_alive) {
m_alive = false;
emit aliveChanged (NODE_ID, m_alive);
}
}
......@@ -567,15 +567,35 @@ public:
};
};
struct QTCAN_CANOPEN_EXPORT CanOpenHeartbeatConsumer {
class QTCAN_CANOPEN_EXPORT CanOpenHeartbeatConsumer : public QObject {
Q_OBJECT
public:
const CanOpenNodeId nodeId;
CanOpenHeartBeatState state;
QBasicTimer watchdog;
quint16 timeout;
bool alive;
explicit CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId, QObject * parent = Q_NULLPTR);
virtual ~CanOpenHeartbeatConsumer (void);
bool isAlive (void) const;
CanOpenNodeId getNodeId (void) const;
CanOpenHeartBeatState lastKnownState (void) const;
public slots:
void reset (void);
void reconfigure (const quint16 timeout);
void handleState (const CanOpenHeartBeatState state);
explicit CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId);
signals:
void stateChanged (const CanOpenNodeId nodeId, const CanOpenHeartBeatState state);
void aliveChanged (const CanOpenNodeId nodeId, const bool alive);
protected slots:
void onWatchdogExpired (void);
private:
const CanOpenNodeId NODE_ID;
QTimer m_watchdog;
CanOpenHeartBeatState m_state;
quint16 m_timeout;
bool m_alive;
};
struct QTCAN_CANOPEN_EXPORT CanOpenSdoFrame {
......@@ -643,25 +663,42 @@ private:
bool dirty;
};
struct QTCAN_CANOPEN_EXPORT CanOpenSdoTransferQueue {
explicit CanOpenSdoTransferQueue (const CanOpenNodeId nodeId = 0x00,
const CanOpenSdoMode mode = CanOpenSdoModes::SdoNeiter);
class QTCAN_CANOPEN_EXPORT CanOpenSdoTransferQueue : public QObject {
Q_OBJECT
QMutex mutex;
int timeout;
CanOpenNodeId nodeId;
CanOpenSdoMode mode;
QTimer * timer;
CanOpenSdoTransfer * currentTransfer;
QQueue<CanOpenSdoTransfer *> transfersQueue;
public:
explicit CanOpenSdoTransferQueue (const CanOpenNodeId nodeId, QObject * parent = Q_NULLPTR);
void killTimer (void);
void restartTimer (void);
CanOpenSdoMode getMode (void) const;
CanOpenNodeId getNodeId (void) const;
CanOpenSdoTransfer * getCurrentTransfer (void);
bool hasCurrentTransfer (void);
void reset (void);
void reconfigure (const CanOpenSdoMode mode, const int timeout);
void killTimeoutWatcher (void);
void restartTimeoutWatcher (void);
void addPendingTransfer (CanOpenSdoTransfer * transfer);
CanOpenSdoTransfer * getCurrentTransfer (void);
void prepareNextTransfer (void);
void resetCurrentTransfer (void);
signals:
void processNeeded (void);
protected slots:
void onTimeoutError (void);
private:
QMutex _mutex;
QTimer _timerError;
QTimer _timerProcess;
CanOpenSdoMode _mode;
CanOpenSdoTransfer * _currentTransfer;
QQueue<CanOpenSdoTransfer *> _transfersQueue;
const CanOpenNodeId NODE_ID;
};
struct QTCAN_CANOPEN_EXPORT CanOpenLssAction {
......
This diff is collapsed.
......@@ -11,6 +11,7 @@
#include "QtCAN.h"
#include "CanOpenDefs.h"
#include "ArrayById.h"
class QTCAN_CANOPEN_EXPORT CanOpenProtocolManager : public QObject {
Q_OBJECT
......@@ -115,14 +116,11 @@ protected slots:
void doMsgSend (CanMessage * msg);
void onMsgRecv (CanMessage * msg);
void onSdoTimeout (void);
void onLssTimeout (void);
void onSyncIntervalChanged (void);
void onHeartBeatIntervalChanged (void);
void onHeartbeatConsumerChanged (void);
void onSdoClockTick (void);
void onSdoQueueProcessNeeded (void);
void onDiag (const int level, const QString & description);
......@@ -143,9 +141,6 @@ protected slots:
void enqueueLssAction (CanOpenLssAction * action);
void processLssAction (void);
protected:
void timerEvent (QTimerEvent * event) Q_DECL_FINAL;
private:
const bool m_autoRemoveMsg;
const bool m_hooksForDebug;
......@@ -155,15 +150,14 @@ private:
CanOpenNodeId m_localNodeId;
CanOpenHeartBeatState m_localNodeState;
CanOpenNetPosition m_localNetworkPos;
QTimer * m_sdoTimer;
QTimer * m_syncTimer;
QTimer * m_heartBeatTimer;
CanDriver * m_driver;
CanOpenObjDict * m_objDict;
CanOpenLssQueue m_lssQueue;
QHash<CanOpenCobId, CanOpenPdoConfigCache *> m_pdoConfigCaches;
QHash<CanOpenNodeId, CanOpenSdoTransferQueue *> m_sdoTransferQueues;
QHash<CanOpenNodeId, CanOpenHeartbeatConsumer *> m_hbConsumersByNodeId;
ArrayById<CanOpenSdoTransferQueue, CanOpenNodeId, 0x01, 0x7F> m_sdoTransferQueues;
ArrayById<CanOpenHeartbeatConsumer, CanOpenNodeId, 0x01, 0x7F> m_hbConsumersByNodeId;
};
#endif // CANOPENPROTOCOLMANAGER_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment