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 { ...@@ -41,6 +41,7 @@ Project {
Group { Group {
name: "C++ headers"; name: "C++ headers";
files: [ files: [
"ArrayById.h",
"CanOpenDefs.h", "CanOpenDefs.h",
"CanOpenEntry.h", "CanOpenEntry.h",
"CanOpenSubEntry.h", "CanOpenSubEntry.h",
......
...@@ -123,58 +123,103 @@ void CanOpenSdoTransfer::markClean (void) { ...@@ -123,58 +123,103 @@ void CanOpenSdoTransfer::markClean (void) {
/*** CAN OPEN SDO TRANSFERS QUEUE ***/ /*** CAN OPEN SDO TRANSFERS QUEUE ***/
CanOpenSdoTransferQueue::CanOpenSdoTransferQueue (const CanOpenNodeId nodeId, const CanOpenSdoMode mode) CanOpenSdoTransferQueue::CanOpenSdoTransferQueue (const CanOpenNodeId nodeId, QObject * parent)
: timeout (1000) : QObject (parent)
, nodeId (nodeId) , _mode (CanOpenSdoModes::SdoNeiter)
, mode (mode) , _currentTransfer (Q_NULLPTR)
, timer (new QTimer) , NODE_ID (nodeId)
, currentTransfer (Q_NULLPTR)
{ {
timer->setProperty ("nodeId", nodeId); _timerError.setSingleShot (true);
timer->setTimerType (Qt::PreciseTimer); _timerError.setTimerType (Qt::PreciseTimer);
timer->setSingleShot (true); _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) { CanOpenSdoMode CanOpenSdoTransferQueue::getMode (void) const {
if (timer->isActive ()) { return _mode;
timer->stop (); }
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) { void CanOpenSdoTransferQueue::reconfigure (const CanOpenSdoMode mode, const int timeout) {
killTimer (); _mode = mode;
timer->start (timeout); _timerError.setInterval (timeout);
}
void CanOpenSdoTransferQueue::killTimeoutWatcher (void) {
if (_timerError.isActive ()) {
_timerError.stop ();
}
}
void CanOpenSdoTransferQueue::restartTimeoutWatcher (void) {
killTimeoutWatcher ();
_timerError.start ();
} }
void CanOpenSdoTransferQueue::addPendingTransfer (CanOpenSdoTransfer * transfer) { void CanOpenSdoTransferQueue::addPendingTransfer (CanOpenSdoTransfer * transfer) {
QMutexLocker locker (&mutex); QMutexLocker locker (&_mutex);
if (currentTransfer == Q_NULLPTR && transfersQueue.isEmpty ()) { if (_currentTransfer == Q_NULLPTR && _transfersQueue.isEmpty ()) {
currentTransfer = transfer; _currentTransfer = transfer;
transfer->markDirty (); transfer->markDirty ();
_timerProcess.start (0);
} }
else { else {
transfersQueue.enqueue (transfer); _transfersQueue.enqueue (transfer);
} }
} }
CanOpenSdoTransfer * CanOpenSdoTransferQueue::getCurrentTransfer (void) { CanOpenSdoTransfer * CanOpenSdoTransferQueue::getCurrentTransfer (void) {
QMutexLocker locker (&mutex); QMutexLocker locker (&_mutex);
return currentTransfer; return _currentTransfer;
}
bool CanOpenSdoTransferQueue::hasCurrentTransfer (void) {
QMutexLocker locker (&_mutex);
return (_currentTransfer != Q_NULLPTR);
} }
void CanOpenSdoTransferQueue::prepareNextTransfer (void) { void CanOpenSdoTransferQueue::prepareNextTransfer (void) {
QMutexLocker locker (&mutex); QMutexLocker locker (&_mutex);
if (currentTransfer == Q_NULLPTR && !transfersQueue.isEmpty ()) { if (_currentTransfer == Q_NULLPTR && !_transfersQueue.isEmpty ()) {
currentTransfer = transfersQueue.dequeue (); _currentTransfer = _transfersQueue.dequeue ();
currentTransfer->markDirty (); _currentTransfer->markDirty ();
_timerProcess.start (0);
} }
} }
void CanOpenSdoTransferQueue::resetCurrentTransfer (void) { void CanOpenSdoTransferQueue::resetCurrentTransfer (void) {
QMutexLocker locker (&mutex); QMutexLocker locker (&_mutex);
if (currentTransfer != Q_NULLPTR) { if (_currentTransfer != Q_NULLPTR) {
delete currentTransfer; delete _currentTransfer;
currentTransfer = Q_NULLPTR; _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) { ...@@ -352,10 +397,72 @@ void CanOpenLssQueue::restartTimer (void) {
timer->start (timeout); timer->start (timeout);
} }
CanOpenHeartbeatConsumer::CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId) CanOpenHeartbeatConsumer::CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId, QObject * parent)
: nodeId (nodeId) : QObject (parent)
, state (CanOpenHeartBeatStates::Initializing) , NODE_ID (nodeId)
, watchdog () , m_state (CanOpenHeartBeatStates::Initializing)
, timeout (0x0000) , m_timeout (0x0000)
, alive (false) , 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: ...@@ -567,15 +567,35 @@ public:
}; };
}; };
struct QTCAN_CANOPEN_EXPORT CanOpenHeartbeatConsumer { class QTCAN_CANOPEN_EXPORT CanOpenHeartbeatConsumer : public QObject {
Q_OBJECT
public: public:
const CanOpenNodeId nodeId; explicit CanOpenHeartbeatConsumer (const CanOpenNodeId nodeId, QObject * parent = Q_NULLPTR);
CanOpenHeartBeatState state; virtual ~CanOpenHeartbeatConsumer (void);
QBasicTimer watchdog;
quint16 timeout; bool isAlive (void) const;
bool alive; 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 { struct QTCAN_CANOPEN_EXPORT CanOpenSdoFrame {
...@@ -643,25 +663,42 @@ private: ...@@ -643,25 +663,42 @@ private:
bool dirty; bool dirty;
}; };
struct QTCAN_CANOPEN_EXPORT CanOpenSdoTransferQueue { class QTCAN_CANOPEN_EXPORT CanOpenSdoTransferQueue : public QObject {
explicit CanOpenSdoTransferQueue (const CanOpenNodeId nodeId = 0x00, Q_OBJECT
const CanOpenSdoMode mode = CanOpenSdoModes::SdoNeiter);
QMutex mutex;
int timeout;
CanOpenNodeId nodeId;
CanOpenSdoMode mode;
QTimer * timer;
CanOpenSdoTransfer * currentTransfer;
QQueue<CanOpenSdoTransfer *> transfersQueue;
void killTimer (void); public:
void restartTimer (void); explicit CanOpenSdoTransferQueue (const CanOpenNodeId nodeId, QObject * parent = Q_NULLPTR);
void addPendingTransfer (CanOpenSdoTransfer * transfer); CanOpenSdoMode getMode (void) const;
CanOpenNodeId getNodeId (void) const;
CanOpenSdoTransfer * getCurrentTransfer (void); CanOpenSdoTransfer * getCurrentTransfer (void);
void prepareNextTransfer (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);
void prepareNextTransfer (void);
void resetCurrentTransfer (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 { struct QTCAN_CANOPEN_EXPORT CanOpenLssAction {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "QtCAN.h" #include "QtCAN.h"
#include "CanOpenDefs.h" #include "CanOpenDefs.h"
#include "ArrayById.h"
class QTCAN_CANOPEN_EXPORT CanOpenProtocolManager : public QObject { class QTCAN_CANOPEN_EXPORT CanOpenProtocolManager : public QObject {
Q_OBJECT Q_OBJECT
...@@ -115,14 +116,11 @@ protected slots: ...@@ -115,14 +116,11 @@ protected slots:
void doMsgSend (CanMessage * msg); void doMsgSend (CanMessage * msg);
void onMsgRecv (CanMessage * msg); void onMsgRecv (CanMessage * msg);
void onSdoTimeout (void); void onLssTimeout (void);
void onLssTimeout (void);
void onSyncIntervalChanged (void); void onSyncIntervalChanged (void);
void onHeartBeatIntervalChanged (void); void onHeartBeatIntervalChanged (void);
void onHeartbeatConsumerChanged (void); void onHeartbeatConsumerChanged (void);
void onSdoQueueProcessNeeded (void);
void onSdoClockTick (void);
void onDiag (const int level, const QString & description); void onDiag (const int level, const QString & description);
...@@ -143,9 +141,6 @@ protected slots: ...@@ -143,9 +141,6 @@ protected slots:
void enqueueLssAction (CanOpenLssAction * action); void enqueueLssAction (CanOpenLssAction * action);
void processLssAction (void); void processLssAction (void);
protected:
void timerEvent (QTimerEvent * event) Q_DECL_FINAL;
private: private:
const bool m_autoRemoveMsg; const bool m_autoRemoveMsg;
const bool m_hooksForDebug; const bool m_hooksForDebug;
...@@ -155,15 +150,14 @@ private: ...@@ -155,15 +150,14 @@ private:
CanOpenNodeId m_localNodeId; CanOpenNodeId m_localNodeId;
CanOpenHeartBeatState m_localNodeState; CanOpenHeartBeatState m_localNodeState;
CanOpenNetPosition m_localNetworkPos; CanOpenNetPosition m_localNetworkPos;
QTimer * m_sdoTimer;
QTimer * m_syncTimer; QTimer * m_syncTimer;
QTimer * m_heartBeatTimer; QTimer * m_heartBeatTimer;
CanDriver * m_driver; CanDriver * m_driver;
CanOpenObjDict * m_objDict; CanOpenObjDict * m_objDict;
CanOpenLssQueue m_lssQueue; CanOpenLssQueue m_lssQueue;
QHash<CanOpenCobId, CanOpenPdoConfigCache *> m_pdoConfigCaches; QHash<CanOpenCobId, CanOpenPdoConfigCache *> m_pdoConfigCaches;
QHash<CanOpenNodeId, CanOpenSdoTransferQueue *> m_sdoTransferQueues; ArrayById<CanOpenSdoTransferQueue, CanOpenNodeId, 0x01, 0x7F> m_sdoTransferQueues;
QHash<CanOpenNodeId, CanOpenHeartbeatConsumer *> m_hbConsumersByNodeId; ArrayById<CanOpenHeartbeatConsumer, CanOpenNodeId, 0x01, 0x7F> m_hbConsumersByNodeId;
}; };
#endif // CANOPENPROTOCOLMANAGER_H #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