summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/canbus/canbus.pro5
-rw-r--r--src/serialbus/configure.json9
-rw-r--r--src/serialbus/qcanbus.h2
-rw-r--r--src/serialbus/qcanbusdeviceinfo.h2
-rw-r--r--src/serialbus/qcanbusfactory.h2
-rw-r--r--src/serialbus/qcanbusframe.h2
-rw-r--r--src/serialbus/qmodbusclient.cpp5
-rw-r--r--src/serialbus/qmodbusclient_p.h1
-rw-r--r--src/serialbus/qmodbuscommevent_p.h2
-rw-r--r--src/serialbus/qmodbusdevice.cpp4
-rw-r--r--src/serialbus/qmodbusdevice.h2
-rw-r--r--src/serialbus/qmodbusdevice_p.h4
-rw-r--r--src/serialbus/qmodbusdeviceidentification.h2
-rw-r--r--src/serialbus/qmodbuspdu.h2
-rw-r--r--src/serialbus/qmodbusreply.cpp7
-rw-r--r--src/serialbus/qmodbusreply.h3
-rw-r--r--src/serialbus/qmodbusrtuserialmaster.cpp31
-rw-r--r--src/serialbus/qmodbusrtuserialmaster.h3
-rw-r--r--src/serialbus/qmodbusrtuserialmaster_p.h500
-rw-r--r--src/serialbus/qmodbusrtuserialslave.cpp4
-rw-r--r--src/serialbus/qmodbusrtuserialslave_p.h10
-rw-r--r--src/serialbus/qmodbustcpclient_p.h10
-rw-r--r--src/serialbus/qmodbustcpserver.cpp64
-rw-r--r--src/serialbus/qmodbustcpserver.h14
-rw-r--r--src/serialbus/qmodbustcpserver_p.h31
-rw-r--r--src/serialbus/qtserialbusglobal.h (renamed from src/serialbus/qserialbusglobal.h)7
-rw-r--r--src/serialbus/serialbus.pro26
27 files changed, 469 insertions, 285 deletions
diff --git a/src/plugins/canbus/canbus.pro b/src/plugins/canbus/canbus.pro
index 4366027..ab9755c 100644
--- a/src/plugins/canbus/canbus.pro
+++ b/src/plugins/canbus/canbus.pro
@@ -11,5 +11,8 @@ qtConfig(socketcan) {
qtConfig(library) {
SUBDIRS += passthrucan peakcan tinycan
- win32:SUBDIRS += systeccan vectorcan
+ win32 {
+ SUBDIRS += systeccan
+ !winrt:SUBDIRS += vectorcan
+ }
}
diff --git a/src/serialbus/configure.json b/src/serialbus/configure.json
index d640f57..15d4863 100644
--- a/src/serialbus/configure.json
+++ b/src/serialbus/configure.json
@@ -25,6 +25,12 @@
"label": "Socket CAN FD",
"condition": "config.linux && features.socketcan && tests.socketcan_fd",
"output": [ "privateFeature"]
+ },
+ "modbus-serialport" : {
+ "label": "SerialPort Support",
+ "condition": "module.serialport",
+ "purpose": "Enables Serial-based Modbus Support",
+ "output": [ "publicFeature"]
}
},
@@ -46,7 +52,8 @@
"section": "Qt SerialBus",
"entries": [
"socketcan",
- "socketcan_fd"
+ "socketcan_fd",
+ "modbus-serialport"
]
}
]
diff --git a/src/serialbus/qcanbus.h b/src/serialbus/qcanbus.h
index 695d312..6170fcc 100644
--- a/src/serialbus/qcanbus.h
+++ b/src/serialbus/qcanbus.h
@@ -38,7 +38,7 @@
#define QCANBUS_H
#include <QtCore/qobject.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusdeviceinfo.h>
diff --git a/src/serialbus/qcanbusdeviceinfo.h b/src/serialbus/qcanbusdeviceinfo.h
index fbe2c71..c46302d 100644
--- a/src/serialbus/qcanbusdeviceinfo.h
+++ b/src/serialbus/qcanbusdeviceinfo.h
@@ -39,7 +39,7 @@
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
QT_BEGIN_NAMESPACE
diff --git a/src/serialbus/qcanbusfactory.h b/src/serialbus/qcanbusfactory.h
index d74903c..cd7322b 100644
--- a/src/serialbus/qcanbusfactory.h
+++ b/src/serialbus/qcanbusfactory.h
@@ -38,7 +38,7 @@
#define QCANBUSFACTORY_H
#include <QtCore/qstringlist.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusdeviceinfo.h>
diff --git a/src/serialbus/qcanbusframe.h b/src/serialbus/qcanbusframe.h
index d1f8857..69bde41 100644
--- a/src/serialbus/qcanbusframe.h
+++ b/src/serialbus/qcanbusframe.h
@@ -39,7 +39,7 @@
#include <QtCore/qmetatype.h>
#include <QtCore/qobject.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
QT_BEGIN_NAMESPACE
diff --git a/src/serialbus/qmodbusclient.cpp b/src/serialbus/qmodbusclient.cpp
index 32be316..d273a3a 100644
--- a/src/serialbus/qmodbusclient.cpp
+++ b/src/serialbus/qmodbusclient.cpp
@@ -351,6 +351,9 @@ QModbusRequest QModbusClientPrivate::createRWRequest(const QModbusDataUnit &read
void QModbusClientPrivate::processQueueElement(const QModbusResponse &pdu,
const QueueElement &element)
{
+ if (element.reply.isNull())
+ return;
+
element.reply->setRawResult(pdu);
if (pdu.isException()) {
element.reply->setError(QModbusDevice::ProtocolError,
@@ -358,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/qmodbusclient_p.h b/src/serialbus/qmodbusclient_p.h
index 2286fc8..f9a0dfb 100644
--- a/src/serialbus/qmodbusclient_p.h
+++ b/src/serialbus/qmodbusclient_p.h
@@ -126,6 +126,7 @@ public:
QSharedPointer<QTimer> timer;
QByteArray adu;
qint64 bytesWritten = 0;
+ qint32 m_timerId = INT_MIN;
};
void processQueueElement(const QModbusResponse &pdu, const QueueElement &element);
};
diff --git a/src/serialbus/qmodbuscommevent_p.h b/src/serialbus/qmodbuscommevent_p.h
index 47967e7..087c060 100644
--- a/src/serialbus/qmodbuscommevent_p.h
+++ b/src/serialbus/qmodbuscommevent_p.h
@@ -37,7 +37,7 @@
#ifndef QMODBUSCOMMEVENT_P_H
#define QMODBUSCOMMEVENT_P_H
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
//
// W A R N I N G
diff --git a/src/serialbus/qmodbusdevice.cpp b/src/serialbus/qmodbusdevice.cpp
index aa1bddc..9891d16 100644
--- a/src/serialbus/qmodbusdevice.cpp
+++ b/src/serialbus/qmodbusdevice.cpp
@@ -124,6 +124,7 @@ QVariant QModbusDevice::connectionParameter(int parameter) const
{
Q_D(const QModbusDevice);
switch (parameter) {
+#if QT_CONFIG(modbus_serialport)
case SerialPortNameParameter:
return d->m_comPort;
case SerialDataBitsParameter:
@@ -134,6 +135,7 @@ QVariant QModbusDevice::connectionParameter(int parameter) const
return d->m_stopBits;
case SerialBaudRateParameter:
return d->m_baudRate;
+#endif
case NetworkPortParameter:
return d->m_networkPort;
case NetworkAddressParameter:
@@ -156,6 +158,7 @@ void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value)
{
Q_D(QModbusDevice);
switch (parameter) {
+#if QT_CONFIG(modbus_serialport)
case SerialPortNameParameter:
d->m_comPort = value.toString();
break;
@@ -171,6 +174,7 @@ void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value)
case SerialBaudRateParameter:
d->m_baudRate = QSerialPort::BaudRate(value.toInt());
break;
+#endif
case NetworkPortParameter:
d->m_networkPort = value.toInt();
break;
diff --git a/src/serialbus/qmodbusdevice.h b/src/serialbus/qmodbusdevice.h
index 20fa1b3..468fdf4 100644
--- a/src/serialbus/qmodbusdevice.h
+++ b/src/serialbus/qmodbusdevice.h
@@ -38,7 +38,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qiodevice.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
QT_BEGIN_NAMESPACE
diff --git a/src/serialbus/qmodbusdevice_p.h b/src/serialbus/qmodbusdevice_p.h
index 52ace00..a845a89 100644
--- a/src/serialbus/qmodbusdevice_p.h
+++ b/src/serialbus/qmodbusdevice_p.h
@@ -39,7 +39,9 @@
#include <QtCore/qvariant.h>
#include <QtSerialBus/qmodbusdevice.h>
+#if QT_CONFIG(modbus_serialport)
#include <QtSerialPort/qserialport.h>
+#endif
#include <private/qobject_p.h>
@@ -65,11 +67,13 @@ public:
QModbusDevice::Error error = QModbusDevice::NoError;
QString errorString;
+#if QT_CONFIG(modbus_serialport)
QString m_comPort;
QSerialPort::DataBits m_dataBits = QSerialPort::Data8;
QSerialPort::Parity m_parity = QSerialPort::EvenParity;
QSerialPort::StopBits m_stopBits = QSerialPort::OneStop;
QSerialPort::BaudRate m_baudRate = QSerialPort::Baud19200;
+#endif
int m_networkPort = 502;
QString m_networkAddress = QStringLiteral("127.0.0.1");
diff --git a/src/serialbus/qmodbusdeviceidentification.h b/src/serialbus/qmodbusdeviceidentification.h
index 63d7ee3..9f08f55 100644
--- a/src/serialbus/qmodbusdeviceidentification.h
+++ b/src/serialbus/qmodbusdeviceidentification.h
@@ -39,7 +39,7 @@
#include <QtCore/qmap.h>
#include <QtCore/qmetatype.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
QT_BEGIN_NAMESPACE
diff --git a/src/serialbus/qmodbuspdu.h b/src/serialbus/qmodbuspdu.h
index 28b1f8a..14cef59 100644
--- a/src/serialbus/qmodbuspdu.h
+++ b/src/serialbus/qmodbuspdu.h
@@ -39,7 +39,7 @@
#include <QtCore/qdatastream.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qvector.h>
-#include <QtSerialBus/qserialbusglobal.h>
+#include <QtSerialBus/qtserialbusglobal.h>
QT_BEGIN_NAMESPACE
diff --git a/src/serialbus/qmodbusreply.cpp b/src/serialbus/qmodbusreply.cpp
index 74cb3e6..7201a33 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.
*/
/*!
@@ -275,6 +278,6 @@ void QModbusReply::setRawResult(const QModbusResponse &response)
d->m_response = response;
}
-#include "moc_qmodbusreply.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qmodbusreply.cpp"
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 99006f4..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)
@@ -150,10 +177,6 @@ void QModbusRtuSerialMaster::close()
if (d->m_serialPort->isOpen())
d->m_serialPort->close();
- // enqueue current active request back for abortion
- d->m_queue.enqueue(d->m_current);
- d->m_current = QModbusClientPrivate::QueueElement();
-
int numberOfAborts = 0;
while (!d->m_queue.isEmpty()) {
// Finish each open reply and forget them
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 5e440b2..9672684 100644
--- a/src/serialbus/qmodbusrtuserialmaster_p.h
+++ b/src/serialbus/qmodbusrtuserialmaster_p.h
@@ -65,174 +65,254 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_MODBUS)
Q_DECLARE_LOGGING_CATEGORY(QT_MODBUS_LOW)
+class Timer : public QObject
+{
+ Q_OBJECT
+
+public:
+ Timer() = default;
+ int start(int msec)
+ {
+ m_timer = QBasicTimer();
+ m_timer.start(msec, Qt::PreciseTimer, this);
+ return m_timer.timerId();
+ }
+ void stop() { m_timer.stop(); }
+ bool isActive() const { return m_timer.isActive(); }
+
+signals:
+ void timeout(int timerId);
+
+private:
+ void timerEvent(QTimerEvent *event) override
+ {
+ const auto id = m_timer.timerId();
+ if (event->timerId() == id)
+ emit timeout(id);
+ }
+
+private:
+ QBasicTimer m_timer;
+};
+
class QModbusRtuSerialMasterPrivate : public QModbusClientPrivate
{
Q_DECLARE_PUBLIC(QModbusRtuSerialMaster)
- enum State {
+ enum State
+ {
Idle,
- Schedule,
- Send,
- Receive,
+ WaitingForReplay,
+ ProcessReply
} m_state = Idle;
public:
- void setupSerialPort()
+ void onReadyRead()
{
- Q_Q(QModbusRtuSerialMaster);
+ m_responseBuffer += m_serialPort->read(m_serialPort->bytesAvailable());
+ qCDebug(QT_MODBUS_LOW) << "(RTU client) Response buffer:" << m_responseBuffer.toHex();
- m_sendTimer.setSingleShot(true);
- QObject::connect(&m_sendTimer, &QTimer::timeout, q, [this]() { processQueue(); });
+ if (m_responseBuffer.size() < 2) {
+ qCDebug(QT_MODBUS) << "(RTU client) Modbus ADU not complete";
+ return;
+ }
- m_responseTimer.setSingleShot(true);
- QObject::connect(&m_responseTimer, &QTimer::timeout, q, [this]() { processQueue(); });
+ const QModbusSerialAdu tmpAdu(QModbusSerialAdu::Rtu, m_responseBuffer);
+ int pduSizeWithoutFcode = QModbusResponse::calculateDataSize(tmpAdu.pdu());
+ if (pduSizeWithoutFcode < 0) {
+ // wait for more data
+ qCDebug(QT_MODBUS) << "(RTU client) Cannot calculate PDU size for function code:"
+ << tmpAdu.pdu().functionCode() << ", delaying pending frame";
+ return;
+ }
- m_serialPort = new QSerialPort(q);
- QObject::connect(m_serialPort, &QSerialPort::readyRead, q, [this]() {
- responseBuffer += m_serialPort->read(m_serialPort->bytesAvailable());
- qCDebug(QT_MODBUS_LOW) << "(RTU client) Response buffer:" << responseBuffer.toHex();
+ // server address byte + function code byte + PDU size + 2 bytes CRC
+ int aduSize = 2 + pduSizeWithoutFcode + 2;
+ if (tmpAdu.rawSize() < aduSize) {
+ qCDebug(QT_MODBUS) << "(RTU client) Incomplete ADU received, ignoring";
+ return;
+ }
- if (responseBuffer.size() < 2) {
- qCDebug(QT_MODBUS) << "(RTU client) Modbus ADU not complete";
- return;
+ if (m_queue.isEmpty())
+ return;
+ auto &current = m_queue.first();
+
+ // Special case for Diagnostics:ReturnQueryData. The response has no
+ // length indicator and is just a simple echo of what we have send.
+ if (tmpAdu.pdu().functionCode() == QModbusPdu::Diagnostics) {
+ const QModbusResponse response = tmpAdu.pdu();
+ if (canMatchRequestAndResponse(response, tmpAdu.serverAddress())) {
+ quint16 subCode = 0xffff;
+ response.decodeData(&subCode);
+ if (subCode == Diagnostics::ReturnQueryData) {
+ if (response.data() != current.requestPdu.data())
+ return; // echo does not match request yet
+ aduSize = 2 + response.dataSize() + 2;
+ if (tmpAdu.rawSize() < aduSize)
+ return; // echo matches, probably checksum missing
+ }
}
+ }
- const QModbusSerialAdu tmpAdu(QModbusSerialAdu::Rtu, responseBuffer);
- int pduSizeWithoutFcode = QModbusResponse::calculateDataSize(tmpAdu.pdu());
- if (pduSizeWithoutFcode < 0) {
- // wait for more data
- qCDebug(QT_MODBUS) << "(RTU client) Cannot calculate PDU size for function code:"
- << tmpAdu.pdu().functionCode() << ", delaying pending frame";
- return;
- }
+ const QModbusSerialAdu adu(QModbusSerialAdu::Rtu, m_responseBuffer.left(aduSize));
+ m_responseBuffer.remove(0, aduSize);
- // server address byte + function code byte + PDU size + 2 bytes CRC
- int aduSize = 2 + pduSizeWithoutFcode + 2;
- if (tmpAdu.rawSize() < aduSize) {
- qCDebug(QT_MODBUS) << "(RTU client) Incomplete ADU received, ignoring";
- return;
- }
+ qCDebug(QT_MODBUS) << "(RTU client) Received ADU:" << adu.rawData().toHex();
+ if (QT_MODBUS().isDebugEnabled() && !m_responseBuffer.isEmpty())
+ qCDebug(QT_MODBUS_LOW) << "(RTU client) Pending buffer:" << m_responseBuffer.toHex();
- // Special case for Diagnostics:ReturnQueryData. The response has no
- // length indicator and is just a simple echo of what we have send.
- if (tmpAdu.pdu().functionCode() == QModbusPdu::Diagnostics) {
- const QModbusResponse response = tmpAdu.pdu();
- if (canMatchRequestAndResponse(response, tmpAdu.serverAddress())) {
- quint16 subCode = 0xffff;
- response.decodeData(&subCode);
- if (subCode == Diagnostics::ReturnQueryData) {
- if (response.data() != m_current.requestPdu.data())
- return; // echo does not match request yet
- aduSize = 2 + response.dataSize() + 2;
- if (tmpAdu.rawSize() < aduSize)
- return; // echo matches, probably checksum missing
- }
- }
- }
+ // check CRC
+ if (!adu.matchingChecksum()) {
+ qCWarning(QT_MODBUS) << "(RTU client) Discarding response with wrong CRC, received:"
+ << adu.checksum<quint16>() << ", calculated CRC:"
+ << QModbusSerialAdu::calculateCRC(adu.data(), adu.size());
+ return;
+ }
- const QModbusSerialAdu adu(QModbusSerialAdu::Rtu, responseBuffer.left(aduSize));
- responseBuffer.remove(0, aduSize);
+ const QModbusResponse response = adu.pdu();
+ if (!canMatchRequestAndResponse(response, adu.serverAddress())) {
+ qCWarning(QT_MODBUS) << "(RTU client) Cannot match response with open request, "
+ "ignoring";
+ return;
+ }
- qCDebug(QT_MODBUS)<< "(RTU client) Received ADU:" << adu.rawData().toHex();
- if (QT_MODBUS().isDebugEnabled() && !responseBuffer.isEmpty())
- qCDebug(QT_MODBUS_LOW) << "(RTU client) Pending buffer:" << responseBuffer.toHex();
+ m_state = ProcessReply;
+ m_responseTimer.stop();
+ current.m_timerId = INT_MIN;
- // check CRC
- if (!adu.matchingChecksum()) {
- qCWarning(QT_MODBUS) << "(RTU client) Discarding response with wrong CRC, received:"
- << adu.checksum<quint16>() << ", calculated CRC:"
- << QModbusSerialAdu::calculateCRC(adu.data(), adu.size());
- return;
- }
+ processQueueElement(response, m_queue.dequeue());
- const QModbusResponse response = adu.pdu();
- if (!canMatchRequestAndResponse(response, adu.serverAddress())) {
- qCWarning(QT_MODBUS) << "(RTU client) Cannot match response with open request, "
- "ignoring";
- return;
- }
+ m_state = Idle;
+ scheduleNextRequest(m_interFrameDelayMilliseconds);
+ }
- if (m_state != State::Receive) {
- qCDebug(QT_MODBUS) << "(RTU server) Ignoring response due to non receive state";
- return;
- }
+ void onAboutToClose()
+ {
+ Q_Q(QModbusRtuSerialMaster);
+ Q_UNUSED(q) // avoid warning in release mode
+ Q_ASSERT(q->state() == QModbusDevice::ClosingState);
+
+ m_responseTimer.stop();
+ }
+
+ void onResponseTimeout(int timerId)
+ {
+ m_responseTimer.stop();
+ if (m_state != State::WaitingForReplay || m_queue.isEmpty())
+ return;
+ const auto current = m_queue.first();
- m_sendTimer.stop();
- m_responseTimer.stop();
- processQueueElement(response, m_current);
+ if (current.m_timerId != timerId)
+ return;
- m_state = Schedule; // reschedule, even if empty
- m_serialPort->clear(QSerialPort::AllDirections);
- QTimer::singleShot(m_interFrameDelayMilliseconds, [this]() { processQueue(); });
- });
+ qCDebug(QT_MODBUS) << "(RTU client) Receive timeout:" << current.requestPdu;
- using TypeId = void (QSerialPort::*)(QSerialPort::SerialPortError);
- QObject::connect(m_serialPort, static_cast<TypeId>(&QSerialPort::error),
- [this](QSerialPort::SerialPortError error) {
- if (error == QSerialPort::NoError)
- return;
-
- qCDebug(QT_MODBUS) << "(RTU server) QSerialPort error:" << error
- << (m_serialPort ? m_serialPort->errorString() : QString());
-
- Q_Q(QModbusRtuSerialMaster);
-
- switch (error) {
- case QSerialPort::DeviceNotFoundError:
- q->setError(QModbusDevice::tr("Referenced serial device does not exist."),
- QModbusDevice::ConnectionError);
- break;
- case QSerialPort::PermissionError:
- q->setError(QModbusDevice::tr("Cannot open serial device due to permissions."),
- QModbusDevice::ConnectionError);
- break;
- case QSerialPort::OpenError:
- case QSerialPort::NotOpenError:
- q->setError(QModbusDevice::tr("Cannot open serial device."),
- QModbusDevice::ConnectionError);
- break;
- case QSerialPort::WriteError:
- q->setError(QModbusDevice::tr("Write error."), QModbusDevice::WriteError);
- break;
- case QSerialPort::ReadError:
- q->setError(QModbusDevice::tr("Read error."), QModbusDevice::ReadError);
- break;
- case QSerialPort::ResourceError:
- q->setError(QModbusDevice::tr("Resource error."), QModbusDevice::ConnectionError);
- break;
- case QSerialPort::UnsupportedOperationError:
- q->setError(QModbusDevice::tr("Device operation is not supported error."),
- QModbusDevice::ConfigurationError);
- break;
- case QSerialPort::TimeoutError:
- q->setError(QModbusDevice::tr("Timeout error."), QModbusDevice::TimeoutError);
- break;
- case QSerialPort::UnknownError:
- q->setError(QModbusDevice::tr("Unknown error."), QModbusDevice::UnknownError);
- break;
- default:
- qCDebug(QT_MODBUS) << "(RTU server) Unhandled QSerialPort error" << error;
- break;
+ if (current.numberOfRetries <= 0) {
+ auto item = m_queue.dequeue();
+ if (item.reply) {
+ item.reply->setError(QModbusDevice::TimeoutError,
+ QModbusClient::tr("Request timeout."));
}
+ }
+
+ m_state = Idle;
+ scheduleNextRequest(m_interFrameDelayMilliseconds);
+ }
+
+ void onBytesWritten(qint64 bytes)
+ {
+ if (m_queue.isEmpty())
+ return;
+ auto &current = m_queue.first();
+
+ current.bytesWritten += bytes;
+ if (current.bytesWritten != current.adu.size())
+ return;
+
+ qCDebug(QT_MODBUS) << "(RTU client) Send successful:" << current.requestPdu;
+
+ 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)
+ {
+ if (error == QSerialPort::NoError)
+ return;
+
+ qCDebug(QT_MODBUS) << "(RTU server) QSerialPort error:" << error
+ << (m_serialPort ? m_serialPort->errorString() : QString());
+
+ Q_Q(QModbusRtuSerialMaster);
+
+ switch (error) {
+ case QSerialPort::DeviceNotFoundError:
+ q->setError(QModbusDevice::tr("Referenced serial device does not exist."),
+ QModbusDevice::ConnectionError);
+ break;
+ case QSerialPort::PermissionError:
+ q->setError(QModbusDevice::tr("Cannot open serial device due to permissions."),
+ QModbusDevice::ConnectionError);
+ break;
+ case QSerialPort::OpenError:
+ case QSerialPort::NotOpenError:
+ q->setError(QModbusDevice::tr("Cannot open serial device."),
+ QModbusDevice::ConnectionError);
+ break;
+ case QSerialPort::WriteError:
+ q->setError(QModbusDevice::tr("Write error."), QModbusDevice::WriteError);
+ break;
+ case QSerialPort::ReadError:
+ q->setError(QModbusDevice::tr("Read error."), QModbusDevice::ReadError);
+ break;
+ case QSerialPort::ResourceError:
+ q->setError(QModbusDevice::tr("Resource error."), QModbusDevice::ConnectionError);
+ break;
+ case QSerialPort::UnsupportedOperationError:
+ q->setError(QModbusDevice::tr("Device operation is not supported error."),
+ QModbusDevice::ConfigurationError);
+ break;
+ case QSerialPort::TimeoutError:
+ q->setError(QModbusDevice::tr("Timeout error."), QModbusDevice::TimeoutError);
+ break;
+ case QSerialPort::UnknownError:
+ q->setError(QModbusDevice::tr("Unknown error."), QModbusDevice::UnknownError);
+ break;
+ default:
+ qCDebug(QT_MODBUS) << "(RTU server) Unhandled QSerialPort error" << error;
+ break;
+ }
+ }
+
+ void setupSerialPort()
+ {
+ Q_Q(QModbusRtuSerialMaster);
+ m_serialPort = new QSerialPort(q);
+
+ QObject::connect(&m_responseTimer, &Timer::timeout, q, [this](int timerId) {
+ onResponseTimeout(timerId);
});
- QObject::connect(m_serialPort, &QSerialPort::bytesWritten, q, [this](qint64 bytes) {
- m_current.bytesWritten += bytes;
- if (m_state == Send && (m_current.bytesWritten == m_current.adu.size()) && !m_current.reply.isNull()) {
- // the if conditions above are copied from processQueue()
- qCDebug(QT_MODBUS) << "(RTU client) Send successful (quick):" << m_current.requestPdu;
- m_state = Receive;
- m_sendTimer.stop();
- m_responseTimer.start(m_responseTimeoutDuration);
- }
+ QObject::connect(m_serialPort, &QSerialPort::readyRead, q, [this]() {
+ onReadyRead();
});
QObject::connect(m_serialPort, &QSerialPort::aboutToClose, q, [this]() {
- Q_Q(QModbusRtuSerialMaster);
- Q_UNUSED(q); // To avoid unused variable warning in release mode
- Q_ASSERT(q->state() == QModbusDevice::ClosingState);
+ onAboutToClose();
+ });
- m_sendTimer.stop();
- m_responseTimer.stop();
+ QObject::connect(m_serialPort, &QSerialPort::bytesWritten, q, [this](qint64 bytes) {
+ onBytesWritten(bytes);
+ });
+
+ QObject::connect(m_serialPort, QOverload<QSerialPort::SerialPortError>::of(&QSerialPort::error),
+ q, [this](QSerialPort::SerialPortError error) {
+ onError(error);
});
}
@@ -244,7 +324,8 @@ public:
If the user set the timeout to be longer than the calculated one,
we'll keep the user defined.
*/
- void calculateInterFrameDelay() {
+ void calculateInterFrameDelay()
+ {
// The spec recommends a timeout value of 1.750 msec. Without such
// precise single-shot timers use a approximated value of 1.750 msec.
int delayMilliSeconds = 2;
@@ -258,7 +339,8 @@ public:
m_interFrameDelayMilliseconds = delayMilliSeconds;
}
- void setupEnvironment() {
+ void setupEnvironment()
+ {
if (m_serialPort) {
m_serialPort->setPortName(m_comPort);
m_serialPort->setParity(m_parity);
@@ -269,123 +351,71 @@ public:
calculateInterFrameDelay();
- responseBuffer.clear();
+ m_responseBuffer.clear();
m_state = QModbusRtuSerialMasterPrivate::Idle;
}
- void scheduleNextRequest() {
- Q_Q(QModbusRtuSerialMaster);
-
- m_state = Schedule;
- m_serialPort->clear(QSerialPort::AllDirections);
- QTimer::singleShot(m_interFrameDelayMilliseconds, q, [this]() { processQueue(); });
- }
-
QModbusReply *enqueueRequest(const QModbusRequest &request, int serverAddress,
const QModbusDataUnit &unit, QModbusReply::ReplyType type) override
{
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);
- if (m_state == Idle)
- scheduleNextRequest();
+ scheduleNextRequest(m_interFrameDelayMilliseconds);
+
return reply;
}
- void processQueue()
+ void scheduleNextRequest(int delay)
{
- Q_ASSERT_X(!m_sendTimer.isActive(), "processQueue", "send timer active");
- Q_ASSERT_X(!m_responseTimer.isActive(), "processQueue", "response timer active");
-
- auto writeAdu = [this]() {
- responseBuffer.clear();
- m_current.bytesWritten = 0;
- m_current.numberOfRetries--;
- m_serialPort->write(m_current.adu);
- m_sendTimer.start(m_interFrameDelayMilliseconds);
-
- qCDebug(QT_MODBUS) << "(RTU client) Sent Serial PDU:" << m_current.requestPdu;
- qCDebug(QT_MODBUS_LOW).noquote() << "(RTU client) Sent Serial ADU: 0x" + m_current.adu
- .toHex();
- };
-
- switch (m_state) {
- case Schedule:
- m_current = QueueElement();
- if (!m_queue.isEmpty()) {
- m_current = m_queue.dequeue();
- if (m_current.reply) {
- m_state = Send;
- QTimer::singleShot(0, [writeAdu]() { writeAdu(); });
- } else {
- QTimer::singleShot(0, [this]() { processQueue(); });
- }
- } else {
- m_state = Idle;
- }
- break;
+ Q_Q(QModbusRtuSerialMaster);
- case Send:
- // send timeout will always happen unless canceled by very quick bytesWritten
- if (m_current.reply.isNull()) {
- scheduleNextRequest();
- } else if (m_current.bytesWritten < m_current.adu.size()) {
- qCDebug(QT_MODBUS) << "(RTU client) Send failed:" << m_current.requestPdu;
-
- if (m_current.numberOfRetries <= 0) {
- if (m_current.reply) {
- m_current.reply->setError(QModbusDevice::TimeoutError,
- QModbusClient::tr("Request timeout."));
- }
- m_current = QueueElement();
- scheduleNextRequest();
- } else {
- m_serialPort->clear(QSerialPort::AllDirections);
- QTimer::singleShot(m_interFrameDelayMilliseconds, [writeAdu]() { writeAdu(); });
- }
- } else {
- qCDebug(QT_MODBUS) << "(RTU client) Send successful:" << m_current.requestPdu;
- m_state = Receive;
- m_responseTimer.start(m_responseTimeoutDuration);
- }
- break;
+ if (m_state == Idle && !m_queue.isEmpty()) {
+ m_state = WaitingForReplay;
+ QTimer::singleShot(delay, q, [this]() { processQueue(); });
+ }
+ }
- case Receive:
- // receive timeout will only happen after successful send
- qCDebug(QT_MODBUS) << "(RTU client) Receive timeout:" << m_current.requestPdu;
- if (m_current.reply.isNull()) {
- scheduleNextRequest();
- } else if (m_current.numberOfRetries <= 0) {
- if (m_current.reply) {
- m_current.reply->setError(QModbusDevice::TimeoutError,
- QModbusClient::tr("Response timeout."));
- }
- scheduleNextRequest();
- } else {
- m_state = Send;
- m_serialPort->clear(QSerialPort::AllDirections);
- QTimer::singleShot(m_interFrameDelayMilliseconds, [writeAdu]() { writeAdu(); });
- }
- break;
+ void processQueue()
+ {
+ m_responseBuffer.clear();
+ m_serialPort->clear(QSerialPort::AllDirections);
- case Idle:
- default:
- Q_ASSERT_X(false, "processQueue", QByteArray("unexpected state: ").append(m_state));
- break;
+ if (m_queue.isEmpty())
+ return;
+ auto &current = m_queue.first();
+
+ if (current.reply.isNull()) {
+ m_queue.dequeue();
+ m_state = Idle;
+ scheduleNextRequest(m_interFrameDelayMilliseconds);
+ } else {
+ current.bytesWritten = 0;
+ current.numberOfRetries--;
+ m_serialPort->write(current.adu);
+
+ qCDebug(QT_MODBUS) << "(RTU client) Sent Serial PDU:" << current.requestPdu;
+ qCDebug(QT_MODBUS_LOW).noquote() << "(RTU client) Sent Serial ADU: 0x" + current.adu
+ .toHex();
}
}
bool canMatchRequestAndResponse(const QModbusResponse &response, int sendingServer) const
{
- if (m_current.reply.isNull())
+ if (m_queue.isEmpty())
+ return false;
+ const auto &current = m_queue.first();
+
+ if (current.reply.isNull())
return false; // reply deleted
- if (m_current.reply->serverAddress() != sendingServer)
+ if (current.reply->serverAddress() != sendingServer)
return false; // server mismatch
- if (m_current.requestPdu.functionCode() != response.functionCode())
+ if (current.requestPdu.functionCode() != response.functionCode())
return false; // request for different function code
return true;
}
@@ -397,18 +427,18 @@ public:
return false;
}
- QTimer m_sendTimer;
- QTimer m_responseTimer;
-
- QueueElement m_current;
- QByteArray responseBuffer;
+ Timer m_responseTimer;
+ QByteArray m_responseBuffer;
QQueue<QueueElement> m_queue;
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
+#include "qmodbusrtuserialmaster_p.h"
+
#endif // QMODBUSSERIALMASTER_P_H
diff --git a/src/serialbus/qmodbusrtuserialslave.cpp b/src/serialbus/qmodbusrtuserialslave.cpp
index 899bd8d..36a845c 100644
--- a/src/serialbus/qmodbusrtuserialslave.cpp
+++ b/src/serialbus/qmodbusrtuserialslave.cpp
@@ -158,6 +158,6 @@ QModbusResponse QModbusRtuSerialSlave::processRequest(const QModbusPdu &request)
return QModbusServer::processRequest(request);
}
-#include "moc_qmodbusrtuserialslave.cpp"
-
QT_END_NAMESPACE
+
+#include "moc_qmodbusrtuserialslave.cpp"
diff --git a/src/serialbus/qmodbusrtuserialslave_p.h b/src/serialbus/qmodbusrtuserialslave_p.h
index e41aa7a..da59e5e 100644
--- a/src/serialbus/qmodbusrtuserialslave_p.h
+++ b/src/serialbus/qmodbusrtuserialslave_p.h
@@ -74,7 +74,7 @@ public:
Q_Q(QModbusRtuSerialSlave);
m_serialPort = new QSerialPort(q);
- QObject::connect(m_serialPort, &QSerialPort::readyRead, [this]() {
+ QObject::connect(m_serialPort, &QSerialPort::readyRead, q, [this]() {
if (m_interFrameTimer.isValid()
&& m_interFrameTimer.elapsed() > m_interFrameDelayMilliseconds
@@ -90,7 +90,7 @@ public:
m_interFrameTimer.start();
- const int size = m_serialPort->size();
+ const qint64 size = m_serialPort->size();
m_requestBuffer += m_serialPort->read(size);
const QModbusSerialAdu adu(QModbusSerialAdu::Rtu, m_requestBuffer);
@@ -218,7 +218,7 @@ public:
return;
}
- int writtenBytes = m_serialPort->write(result);
+ qint64 writtenBytes = m_serialPort->write(result);
if ((writtenBytes == -1) || (writtenBytes < result.size())) {
qCDebug(QT_MODBUS) << "(RTU server) Cannot write requested response to serial port.";
q->setError(QModbusRtuSerialSlave::tr("Could not write response to client"),
@@ -281,7 +281,7 @@ public:
});
using TypeId = void (QSerialPort::*)(QSerialPort::SerialPortError);
- QObject::connect(m_serialPort, static_cast<TypeId>(&QSerialPort::error),
+ QObject::connect(m_serialPort, static_cast<TypeId>(&QSerialPort::error), q,
[this](QSerialPort::SerialPortError error) {
if (error == QSerialPort::NoError)
return;
@@ -330,7 +330,7 @@ public:
}
});
- QObject::connect(m_serialPort, &QSerialPort::aboutToClose, [this]() {
+ QObject::connect(m_serialPort, &QSerialPort::aboutToClose, q, [this]() {
Q_Q(QModbusRtuSerialSlave);
// update state if socket closure was caused by remote side
if (q->state() != QModbusDevice::ClosingState)
diff --git a/src/serialbus/qmodbustcpclient_p.h b/src/serialbus/qmodbustcpclient_p.h
index e4dfa9e..db1d4e4 100644
--- a/src/serialbus/qmodbustcpclient_p.h
+++ b/src/serialbus/qmodbustcpclient_p.h
@@ -71,7 +71,7 @@ public:
m_socket = new QTcpSocket(q);
- QObject::connect(m_socket, &QAbstractSocket::connected, [this]() {
+ QObject::connect(m_socket, &QAbstractSocket::connected, q, [this]() {
qCDebug(QT_MODBUS) << "(TCP client) Connected to" << m_socket->peerAddress()
<< "on port" << m_socket->peerPort();
Q_Q(QModbusTcpClient);
@@ -79,7 +79,7 @@ public:
q->setState(QModbusDevice::ConnectedState);
});
- QObject::connect(m_socket, &QAbstractSocket::disconnected, [this]() {
+ QObject::connect(m_socket, &QAbstractSocket::disconnected, q, [this]() {
qCDebug(QT_MODBUS) << "(TCP client) Connection closed.";
Q_Q(QModbusTcpClient);
q->setState(QModbusDevice::UnconnectedState);
@@ -87,7 +87,7 @@ public:
});
using TypeId = void (QAbstractSocket::*)(QAbstractSocket::SocketError);
- QObject::connect(m_socket, static_cast<TypeId>(&QAbstractSocket::error),
+ QObject::connect(m_socket, static_cast<TypeId>(&QAbstractSocket::error), q,
[this](QAbstractSocket::SocketError /*error*/)
{
Q_Q(QModbusTcpClient);
@@ -100,7 +100,7 @@ public:
QModbusDevice::ConnectionError);
});
- QObject::connect(m_socket, &QIODevice::readyRead, [this](){
+ QObject::connect(m_socket, &QIODevice::readyRead, q, [this](){
responseBuffer += m_socket->read(m_socket->bytesAvailable());
qCDebug(QT_MODBUS_LOW) << "(TCP client) Response buffer:" << responseBuffer.toHex();
@@ -196,7 +196,7 @@ public:
using TypeId = void (QTimer::*)(int);
q->connect(q, &QModbusClient::timeoutChanged,
element.timer.data(), static_cast<TypeId>(&QTimer::setInterval));
- QObject::connect(element.timer.data(), &QTimer::timeout, [this, writeToSocket, tId]() {
+ QObject::connect(element.timer.data(), &QTimer::timeout, q, [this, writeToSocket, tId]() {
if (!m_transactionStore.contains(tId))
return;
diff --git a/src/serialbus/qmodbustcpserver.cpp b/src/serialbus/qmodbustcpserver.cpp
index 39aeda8..3a15e9e 100644
--- a/src/serialbus/qmodbustcpserver.cpp
+++ b/src/serialbus/qmodbustcpserver.cpp
@@ -110,7 +110,7 @@ bool QModbusTcpServer::open()
return false;
}
- if (d->m_tcpServer->listen(QHostAddress(url.host()), url.port()))
+ if (d->m_tcpServer->listen(QHostAddress(url.host()), quint16(url.port())))
setState(QModbusDevice::ConnectedState);
else
setError(d->m_tcpServer->errorString(), QModbusDevice::ConnectionError);
@@ -171,4 +171,66 @@ QModbusResponse QModbusTcpServer::processRequest(const QModbusPdu &request)
return QModbusServer::processRequest(request);
}
+/*!
+ Installs an \a observer that can be used to obtain notifications when a
+ new TCP client connects to this server instance. In addition, the \a observer
+ can be used to reject the incoming TCP connection.
+
+ QModbusTcpServer takes ownership of the given \a observer. Any previously set
+ observer will be deleted. The observer can be uninstalled by calling this
+ function with \c nullptr as parameter.
+
+ \sa QModbusTcpConnectionObserver
+ \since 5.13
+*/
+void QModbusTcpServer::installConnectionObserver(QModbusTcpConnectionObserver *observer)
+{
+ Q_D(QModbusTcpServer);
+
+ d->m_observer.reset(observer);
+}
+
+/*!
+ \class QModbusTcpConnectionObserver
+ \inmodule QtSerialBus
+ \since 5.13
+
+ \brief The QModbusTcpConnectionObserver class represents the interface for
+ objects that can be passed to \l QModbusTcpServer::installConnectionObserver.
+
+ The interface must be implemented by the developer to be able to monitor
+ every incoming TCP connection from another Modbus client.
+
+ \sa QModbusTcpServer::installConnectionObserver
+*/
+
+QModbusTcpConnectionObserver::~QModbusTcpConnectionObserver()
+{
+}
+
+/*!
+ \fn bool QModbusTcpConnectionObserver::acceptNewConnection(QTcpSocket *newClient)
+
+ This function is a callback for every incoming TCP connection. The user should
+ provide \a newClient to receive a notification when a new client connection
+ is established and to determine whether the connection is to be accepted.
+
+ The function should return \c true if the connection is to be accepted. Otherwise,
+ the socket is closed/rejected.
+*/
+
+/*!
+ \fn void QModbusTcpServer::modbusClientDisconnected(QTcpSocket *modbusClient)
+
+ This signal is emitted when a current TCP based \a modbusClient disconnects
+ from this Modbus TCP server. Note that there might be several TCP clients
+ connected at the same time.
+
+ Notifications on incoming new connections can be received by installing a
+ QModbusTcpConnectionObserver via \l installConnectionObserver().
+
+ \sa installConnectionObserver
+ \since 5.13
+*/
+
QT_END_NAMESPACE
diff --git a/src/serialbus/qmodbustcpserver.h b/src/serialbus/qmodbustcpserver.h
index 57276a5..cf24d42 100644
--- a/src/serialbus/qmodbustcpserver.h
+++ b/src/serialbus/qmodbustcpserver.h
@@ -43,6 +43,15 @@
QT_BEGIN_NAMESPACE
class QModbusTcpServerPrivate;
+class QTcpSocket;
+
+class Q_SERIALBUS_EXPORT QModbusTcpConnectionObserver
+{
+public:
+ virtual ~QModbusTcpConnectionObserver();
+
+ virtual bool acceptNewConnection(QTcpSocket *newClient) = 0;
+};
class Q_SERIALBUS_EXPORT QModbusTcpServer : public QModbusServer
{
@@ -53,6 +62,11 @@ public:
explicit QModbusTcpServer(QObject *parent = nullptr);
~QModbusTcpServer();
+ void installConnectionObserver(QModbusTcpConnectionObserver *observer);
+
+Q_SIGNALS:
+ void modbusClientDisconnected(QTcpSocket *modbusClient);
+
protected:
QModbusTcpServer(QModbusTcpServerPrivate &dd, QObject *parent = nullptr);
diff --git a/src/serialbus/qmodbustcpserver_p.h b/src/serialbus/qmodbustcpserver_p.h
index 90d1eaf..56c45e9 100644
--- a/src/serialbus/qmodbustcpserver_p.h
+++ b/src/serialbus/qmodbustcpserver_p.h
@@ -48,6 +48,8 @@
#include <private/qmodbusserver_p.h>
+#include <memory>
+
//
// W A R N I N G
// -------------
@@ -113,9 +115,9 @@ public:
void setupTcpServer()
{
- Q_Q(QModbusTcpServer);
- m_tcpServer = new QTcpServer(q);
- QObject::connect(m_tcpServer, &QTcpServer::newConnection, [this]() {
+ m_tcpServer = new QTcpServer(q_func());
+ QObject::connect(m_tcpServer, &QTcpServer::newConnection, q_func(), [this]() {
+ Q_Q(QModbusTcpServer);
auto *socket = m_tcpServer->nextPendingConnection();
if (!socket)
return;
@@ -123,19 +125,29 @@ public:
qCDebug(QT_MODBUS) << "(TCP server) Incoming socket from" << socket->peerAddress()
<< socket->peerName() << socket->peerPort();
+ if (m_observer && !m_observer->acceptNewConnection(socket)) {
+ qCDebug(QT_MODBUS) << "(TCP server) Connection rejected by observer";
+ socket->close();
+ socket->deleteLater();
+ return;
+ }
+
connections.append(socket);
auto buffer = new QByteArray();
- QObject::connect(socket, &QObject::destroyed, [buffer]() {
+ QObject::connect(socket, &QObject::destroyed, q, [buffer]() {
// cleanup buffer
delete buffer;
});
- QObject::connect(socket, &QTcpSocket::disconnected, [socket, this]() {
+ QObject::connect(socket, &QTcpSocket::disconnected, q, [socket, this]() {
connections.removeAll(socket);
+
+ Q_Q(QModbusTcpServer);
+ emit q->modbusClientDisconnected(socket);
socket->deleteLater();
});
- QObject::connect(socket, &QTcpSocket::readyRead, [buffer, socket, this]() {
+ QObject::connect(socket, &QTcpSocket::readyRead, q, [buffer, socket, this]() {
if (!socket)
return;
@@ -193,7 +205,7 @@ public:
return;
}
- int writtenBytes = socket->write(result);
+ qint64 writtenBytes = socket->write(result);
if (writtenBytes == -1 || writtenBytes < result.size()) {
qCDebug(QT_MODBUS) << "(TCP server) Cannot write requested response to socket.";
forwardError(QModbusTcpServer::tr("Could not write response to client"),
@@ -202,7 +214,8 @@ public:
}
});
});
- QObject::connect(m_tcpServer, &QTcpServer::acceptError,
+
+ QObject::connect(m_tcpServer, &QTcpServer::acceptError, q_func(),
[this](QAbstractSocket::SocketError /*sError*/) {
Q_Q(QModbusTcpServer);
@@ -214,6 +227,8 @@ public:
QTcpServer *m_tcpServer;
QVector<QTcpSocket *> connections;
+ std::unique_ptr<QModbusTcpConnectionObserver> m_observer;
+
static const qint8 mbpaHeaderSize = 7;
static const qint16 maxBytesModbusADU = 260;
};
diff --git a/src/serialbus/qserialbusglobal.h b/src/serialbus/qtserialbusglobal.h
index 736c4a8..31c1f85 100644
--- a/src/serialbus/qserialbusglobal.h
+++ b/src/serialbus/qtserialbusglobal.h
@@ -34,10 +34,11 @@
**
****************************************************************************/
-#ifndef QSERIALBUSGLOBAL_H
-#define QSERIALBUSGLOBAL_H
+#ifndef QTSERIALBUSGLOBAL_H
+#define QTSERIALBUSGLOBAL_H
#include <QtCore/qglobal.h>
+#include <QtSerialBus/qtserialbus-config.h>
QT_BEGIN_NAMESPACE
@@ -53,4 +54,4 @@ QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
-#endif // QSERIALBUSGLOBAL_H
+#endif // QTSERIALBUSGLOBAL_H
diff --git a/src/serialbus/serialbus.pro b/src/serialbus/serialbus.pro
index 14583bc..3abba31 100644
--- a/src/serialbus/serialbus.pro
+++ b/src/serialbus/serialbus.pro
@@ -1,7 +1,8 @@
TARGET = QtSerialBus
QT = core-private
-QT_FOR_PRIVATE = network serialport
+QT_FOR_PRIVATE = network
+
CONFIG += c++11
QMAKE_DOCS = $$PWD/doc/qtserialbus.qdocconf
@@ -12,16 +13,14 @@ PUBLIC_HEADERS += \
qcanbusfactory.h \
qcanbusframe.h \
qcanbus.h \
- qserialbusglobal.h \
+ qtserialbusglobal.h \
qmodbusserver.h \
qmodbusdevice.h \
qmodbusdataunit.h \
qmodbusclient.h \
qmodbusreply.h \
- qmodbusrtuserialmaster.h \
qmodbustcpclient.h \
qmodbustcpserver.h \
- qmodbusrtuserialslave.h \
qmodbuspdu.h \
qmodbusdeviceidentification.h
@@ -31,10 +30,8 @@ PRIVATE_HEADERS += \
qmodbusserver_p.h \
qmodbusclient_p.h \
qmodbusdevice_p.h \
- qmodbusrtuserialmaster_p.h \
qmodbustcpclient_p.h \
qmodbustcpserver_p.h \
- qmodbusrtuserialslave_p.h \
qmodbus_symbols_p.h \
qmodbuscommevent_p.h \
qmodbusadu_p.h \
@@ -50,13 +47,26 @@ SOURCES += \
qmodbusdataunit.cpp \
qmodbusclient.cpp \
qmodbusreply.cpp \
- qmodbusrtuserialmaster.cpp \
qmodbustcpclient.cpp \
qmodbustcpserver.cpp \
- qmodbusrtuserialslave.cpp \
qmodbuspdu.cpp \
qmodbusdeviceidentification.cpp
+qtConfig(modbus-serialport) {
+ QT_FOR_PRIVATE += serialport
+
+ PUBLIC_HEADERS += \
+ qmodbusrtuserialmaster.h \
+ qmodbusrtuserialslave.h
+
+ PRIVATE_HEADERS += \
+ qmodbusrtuserialmaster_p.h \
+ qmodbusrtuserialslave_p.h
+
+ SOURCES += \
+ qmodbusrtuserialmaster.cpp \
+ qmodbusrtuserialslave.cpp
+}
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
MODULE_PLUGIN_TYPES = \