diff options
author | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-03-28 14:13:03 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-04-01 12:14:47 +0000 |
commit | 13ddb8a01f107a523047995df8cd673673f89c9e (patch) | |
tree | f3abebffe7e6ba731e67fcc82478eeb0976a18cc | |
parent | cbd814d6fa46a488be2edac6a4944d2df6a9382c (diff) |
Implement handling for sending Modbus RTU broadcast requests
Introduces some methods to set the turnaround delay between a
Modbus broadcast message and a following Modbus message. More
details can be found in the Modbus_over_serial_line_V1.pdf spec
at page 10.
Change-Id: Iddeb7247566663facb79032135c1e4cc2434ca4f
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r-- | src/serialbus/qmodbusclient.cpp | 2 | ||||
-rw-r--r-- | src/serialbus/qmodbusreply.cpp | 3 | ||||
-rw-r--r-- | src/serialbus/qmodbusreply.h | 3 | ||||
-rw-r--r-- | src/serialbus/qmodbusrtuserialmaster.cpp | 27 | ||||
-rw-r--r-- | src/serialbus/qmodbusrtuserialmaster.h | 3 | ||||
-rw-r--r-- | src/serialbus/qmodbusrtuserialmaster_p.h | 26 |
6 files changed, 53 insertions, 11 deletions
diff --git a/src/serialbus/qmodbusclient.cpp b/src/serialbus/qmodbusclient.cpp index cdd9b0b..d273a3a 100644 --- a/src/serialbus/qmodbusclient.cpp +++ b/src/serialbus/qmodbusclient.cpp @@ -361,7 +361,7 @@ void QModbusClientPrivate::processQueueElement(const QModbusResponse &pdu, return; } - if (element.reply->type() == QModbusReply::Raw) { + if (element.reply->type() != QModbusReply::Common) { element.reply->setFinished(true); return; } diff --git a/src/serialbus/qmodbusreply.cpp b/src/serialbus/qmodbusreply.cpp index c8b328f..a01a606 100644 --- a/src/serialbus/qmodbusreply.cpp +++ b/src/serialbus/qmodbusreply.cpp @@ -74,6 +74,9 @@ public: \value Common The reply originates from a common read, write or read/write request. See \l QModbusClient::sendReadRequest, \l QModbusClient::sendWriteRequest and \l QModbusClient::sendReadWriteRequest + \value Broadcast The replay originates from a Modbus broadcast request. The + \l serverAddress() will return \c 0 and the \l finished() + signal will be emitted immediately. */ /*! diff --git a/src/serialbus/qmodbusreply.h b/src/serialbus/qmodbusreply.h index 9b54687..ffefc89 100644 --- a/src/serialbus/qmodbusreply.h +++ b/src/serialbus/qmodbusreply.h @@ -53,7 +53,8 @@ class Q_SERIALBUS_EXPORT QModbusReply : public QObject public: enum ReplyType { Raw, - Common + Common, + Broadcast }; Q_ENUM(ReplyType) diff --git a/src/serialbus/qmodbusrtuserialmaster.cpp b/src/serialbus/qmodbusrtuserialmaster.cpp index d11e7cc..a54b253 100644 --- a/src/serialbus/qmodbusrtuserialmaster.cpp +++ b/src/serialbus/qmodbusrtuserialmaster.cpp @@ -104,6 +104,33 @@ void QModbusRtuSerialMaster::setInterFrameDelay(int microseconds) } /*! + \since 5.13 + + Returns the amount of milliseconds for the silent interval between a Modbus + broadcast and a consecutive Modbus messages. The default value is set to + \c 100 milliseconds. +*/ +int QModbusRtuSerialMaster::turnaroundDelay() const +{ + Q_D(const QModbusRtuSerialMaster); + return d->m_turnaroundDelay; +} + +/*! + \since 5.13 + + Sets the amount of milliseconds for the silent interval between a Modbus + broadcast and a consecutive Modbus messages to \a turnaroundDelay. + Typically the turnaround delay is in the range of \c 100 to \c 200 + milliseconds. +*/ +void QModbusRtuSerialMaster::setTurnaroundDelay(int turnaroundDelay) +{ + Q_D(QModbusRtuSerialMaster); + d->m_turnaroundDelay = turnaroundDelay; +} + +/*! \internal */ QModbusRtuSerialMaster::QModbusRtuSerialMaster(QModbusRtuSerialMasterPrivate &dd, QObject *parent) diff --git a/src/serialbus/qmodbusrtuserialmaster.h b/src/serialbus/qmodbusrtuserialmaster.h index 5c607e2..87f58df 100644 --- a/src/serialbus/qmodbusrtuserialmaster.h +++ b/src/serialbus/qmodbusrtuserialmaster.h @@ -55,6 +55,9 @@ public: int interFrameDelay() const; void setInterFrameDelay(int microseconds); + int turnaroundDelay() const; + void setTurnaroundDelay(int turnaroundDelay); + protected: QModbusRtuSerialMaster(QModbusRtuSerialMasterPrivate &dd, QObject *parent = nullptr); diff --git a/src/serialbus/qmodbusrtuserialmaster_p.h b/src/serialbus/qmodbusrtuserialmaster_p.h index a7bbb4b..9672684 100644 --- a/src/serialbus/qmodbusrtuserialmaster_p.h +++ b/src/serialbus/qmodbusrtuserialmaster_p.h @@ -182,7 +182,7 @@ public: processQueueElement(response, m_queue.dequeue()); m_state = Idle; - scheduleNextRequest(); + scheduleNextRequest(m_interFrameDelayMilliseconds); } void onAboutToClose() @@ -215,7 +215,7 @@ public: } m_state = Idle; - scheduleNextRequest(); + scheduleNextRequest(m_interFrameDelayMilliseconds); } void onBytesWritten(qint64 bytes) @@ -230,8 +230,14 @@ public: qCDebug(QT_MODBUS) << "(RTU client) Send successful:" << current.requestPdu; - // TODO: Implement broadcast here. - current.m_timerId = m_responseTimer.start(m_responseTimeoutDuration); + if (!current.reply.isNull() && current.reply->type() == QModbusReply::Broadcast) { + m_state = ProcessReply; + processQueueElement({}, m_queue.dequeue()); + m_state = Idle; + scheduleNextRequest(m_turnaroundDelay); + } else { + current.m_timerId = m_responseTimer.start(m_responseTimeoutDuration); + } } void onError(QSerialPort::SerialPortError error) @@ -354,23 +360,24 @@ public: { Q_Q(QModbusRtuSerialMaster); - auto reply = new QModbusReply(type, serverAddress, q); + auto reply = new QModbusReply(serverAddress == 0 ? QModbusReply::Broadcast : type, + serverAddress, q); QueueElement element(reply, request, unit, m_numberOfRetries + 1); element.adu = QModbusSerialAdu::create(QModbusSerialAdu::Rtu, serverAddress, request); m_queue.enqueue(element); - scheduleNextRequest(); + scheduleNextRequest(m_interFrameDelayMilliseconds); return reply; } - void scheduleNextRequest() + void scheduleNextRequest(int delay) { Q_Q(QModbusRtuSerialMaster); if (m_state == Idle && !m_queue.isEmpty()) { m_state = WaitingForReplay; - QTimer::singleShot(m_interFrameDelayMilliseconds, q, [this]() { processQueue(); }); + QTimer::singleShot(delay, q, [this]() { processQueue(); }); } } @@ -386,7 +393,7 @@ public: if (current.reply.isNull()) { m_queue.dequeue(); m_state = Idle; - scheduleNextRequest(); + scheduleNextRequest(m_interFrameDelayMilliseconds); } else { current.bytesWritten = 0; current.numberOfRetries--; @@ -427,6 +434,7 @@ public: QSerialPort *m_serialPort = nullptr; int m_interFrameDelayMilliseconds = 2; // A approximated value of 1.750 msec. + int m_turnaroundDelay = 100; // Recommended value is between 100 and 200 msec. }; QT_END_NAMESPACE |