summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarsten Heimrich <karsten.heimrich@qt.io>2019-03-28 14:13:03 +0100
committerKarsten Heimrich <karsten.heimrich@qt.io>2019-04-01 12:14:47 +0000
commit13ddb8a01f107a523047995df8cd673673f89c9e (patch)
treef3abebffe7e6ba731e67fcc82478eeb0976a18cc
parentcbd814d6fa46a488be2edac6a4944d2df6a9382c (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.cpp2
-rw-r--r--src/serialbus/qmodbusreply.cpp3
-rw-r--r--src/serialbus/qmodbusreply.h3
-rw-r--r--src/serialbus/qmodbusrtuserialmaster.cpp27
-rw-r--r--src/serialbus/qmodbusrtuserialmaster.h3
-rw-r--r--src/serialbus/qmodbusrtuserialmaster_p.h26
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