summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2018-10-27 03:01:09 +0200
committerAlex Blasche <alexander.blasche@qt.io>2018-10-29 11:07:39 +0100
commit8c4b7368b5b8c499a3cdf40b2f4ae8bbfc616dd0 (patch)
tree5dafb3e927b8e307bea1b6fcb3512aeed30b7194
parentfbb3abbca7cdb37e8d663175c96bc808ac0a1899 (diff)
parentdf179c4c18d8feeef48e38cc76cd2a0395ba5de1 (diff)
Merge remote-tracking branch 'origin/5.12' into dev
Conflicts: src/serialbus/qmodbusrtuserialslave_p.h Change-Id: I97217954a0bc539d08365e965909771c4032eca9
-rw-r--r--src/serialbus/qmodbusrtuserialmaster_p.h17
-rw-r--r--src/serialbus/qmodbusrtuserialslave_p.h24
-rw-r--r--src/serialbus/qmodbusserver.cpp11
-rw-r--r--tests/auto/qmodbusserver/tst_qmodbusserver.cpp66
4 files changed, 110 insertions, 8 deletions
diff --git a/src/serialbus/qmodbusrtuserialmaster_p.h b/src/serialbus/qmodbusrtuserialmaster_p.h
index 770a39b..104c365 100644
--- a/src/serialbus/qmodbusrtuserialmaster_p.h
+++ b/src/serialbus/qmodbusrtuserialmaster_p.h
@@ -151,8 +151,10 @@ public:
return;
}
- if (m_state != State::Receive)
+ if (m_state != State::Receive) {
+ qCDebug(QT_MODBUS) << "(RTU server) Ignoring response due to non receive state";
return;
+ }
m_sendTimer.stop();
m_responseTimer.stop();
@@ -215,6 +217,13 @@ public:
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::aboutToClose, q, [this]() {
@@ -265,9 +274,11 @@ public:
}
void scheduleNextRequest() {
+ Q_Q(QModbusRtuSerialMaster);
+
m_state = Schedule;
m_serialPort->clear(QSerialPort::AllDirections);
- QTimer::singleShot(m_interFrameDelayMilliseconds, [this]() { processQueue(); });
+ QTimer::singleShot(m_interFrameDelayMilliseconds, q, [this]() { processQueue(); });
}
QModbusReply *enqueueRequest(const QModbusRequest &request, int serverAddress,
@@ -319,7 +330,7 @@ public:
break;
case Send:
- // send timeout will always happen
+ // send timeout will always happen unless cancelled by very quick bytesWritten
if (m_current.reply.isNull()) {
scheduleNextRequest();
} else if (m_current.bytesWritten < m_current.adu.size()) {
diff --git a/src/serialbus/qmodbusrtuserialslave_p.h b/src/serialbus/qmodbusrtuserialslave_p.h
index 99f1a4a..70f28cd 100644
--- a/src/serialbus/qmodbusrtuserialslave_p.h
+++ b/src/serialbus/qmodbusrtuserialslave_p.h
@@ -39,7 +39,9 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qelapsedtimer.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmath.h>
#include <QtSerialBus/qmodbusrtuserialslave.h>
#include <QtSerialPort/qserialport.h>
@@ -73,6 +75,21 @@ public:
m_serialPort = new QSerialPort(q);
QObject::connect(m_serialPort, &QSerialPort::readyRead, [this]() {
+
+ if (m_interFrameTimer.isValid()
+ && m_interFrameTimer.elapsed() > m_interFrameDelayMilliseconds
+ && !m_requestBuffer.isEmpty()) {
+ // This permits response buffer clearing if it contains garbage
+ // but still permits cases where very slow baud rates can cause
+ // chunked and delayed packets
+ qCDebug(QT_MODBUS_LOW) << "(RTU server) Dropping older ADU fragments due to larger than 3.5 char delay (expected:"
+ << m_interFrameDelayMilliseconds << ", max:"
+ << m_interFrameTimer.elapsed() << ")";
+ m_requestBuffer.clear();
+ }
+
+ m_interFrameTimer.start();
+
const qint64 size = m_serialPort->size();
m_requestBuffer += m_serialPort->read(size);
@@ -330,12 +347,19 @@ public:
m_serialPort->setStopBits(m_stopBits);
}
+ // for calulcation details see
+ // QModbusRtuSerialMasterPrivate::calculateInterFrameDelay()
+ m_interFrameDelayMilliseconds = qMax(m_interFrameDelayMilliseconds,
+ qCeil(3500. / (qreal(m_baudRate) / 11.)));
+
m_requestBuffer.clear();
}
QByteArray m_requestBuffer;
bool m_processesBroadcast = false;
QSerialPort *m_serialPort = nullptr;
+ QElapsedTimer m_interFrameTimer;
+ int m_interFrameDelayMilliseconds = 2;
};
QT_END_NAMESPACE
diff --git a/src/serialbus/qmodbusserver.cpp b/src/serialbus/qmodbusserver.cpp
index 5c0f8dd..929ac9a 100644
--- a/src/serialbus/qmodbusserver.cpp
+++ b/src/serialbus/qmodbusserver.cpp
@@ -502,10 +502,11 @@ bool QModbusServer::writeData(const QModbusDataUnit &newData)
return false;
bool changeRequired = false;
- for (int i = newData.startAddress(); i <= rangeEndAddress; i++) {
- quint16 newValue = newData.value(i - newData.startAddress());
- changeRequired |= (current.value(i) != newValue);
- current.setValue(i, newValue);
+ for (uint i = 0; i < newData.valueCount(); i++) {
+ const quint16 newValue = newData.value(i);
+ const int translatedIndex = newData.startAddress() - current.startAddress() + i;
+ changeRequired |= (current.value(translatedIndex) != newValue);
+ current.setValue(translatedIndex, newValue);
}
if (changeRequired)
@@ -553,7 +554,7 @@ bool QModbusServer::readData(QModbusDataUnit *newData) const
if (rangeEndAddress < current.startAddress() || rangeEndAddress > internalRangeEndAddress)
return false;
- newData->setValues(current.values().mid(newData->startAddress(), newData->valueCount()));
+ newData->setValues(current.values().mid(newData->startAddress() - current.startAddress(), newData->valueCount()));
return true;
}
diff --git a/tests/auto/qmodbusserver/tst_qmodbusserver.cpp b/tests/auto/qmodbusserver/tst_qmodbusserver.cpp
index 7a4d4d1..6fe284d 100644
--- a/tests/auto/qmodbusserver/tst_qmodbusserver.cpp
+++ b/tests/auto/qmodbusserver/tst_qmodbusserver.cpp
@@ -1046,6 +1046,72 @@ private slots:
}
}
+ void tst_dataCallsShiftedIndex()
+ {
+ TestServer overlapIndex;
+ const quint16 dataCount = 4;
+
+ QModbusDataUnitMap map;
+ map.insert(QModbusDataUnit::HoldingRegisters, {QModbusDataUnit::HoldingRegisters, 3, dataCount});
+ server.setMap(map);
+ QCOMPARE(map.value(QModbusDataUnit::HoldingRegisters).valueCount(), dataCount);
+
+ QVERIFY(server.setData(QModbusDataUnit::HoldingRegisters, 3, 0xaaaa));
+ QVERIFY(server.setData(QModbusDataUnit::HoldingRegisters, 4, 0xbbbb));
+ QVERIFY(server.setData(QModbusDataUnit::HoldingRegisters, 5, 0xcccc));
+ QVERIFY(server.setData(QModbusDataUnit::HoldingRegisters, 6, 0xdddd));
+
+ // ********** Test individual access ********** //
+ quint16 data = 0;
+ QVERIFY(server.data(QModbusDataUnit::HoldingRegisters, 3, &data));
+ QCOMPARE(data, 0xaaaa);
+ QVERIFY(server.data(QModbusDataUnit::HoldingRegisters, 4, &data));
+ QCOMPARE(data, 0xbbbb);
+ QVERIFY(server.data(QModbusDataUnit::HoldingRegisters, 5, &data));
+ QCOMPARE(data, 0xcccc);
+ QVERIFY(server.data(QModbusDataUnit::HoldingRegisters, 6, &data));
+ QCOMPARE(data, 0xdddd);
+
+
+ // block write at start
+ QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 3, 3);
+ for (int i = 0; i < 3; i++)
+ unit.setValue(i, quint16(0x1111 + i));
+ QVERIFY(server.setData(unit));
+
+ QModbusDataUnit results(QModbusDataUnit::HoldingRegisters, 3, 3);
+ QVERIFY(server.data(&results));
+ QCOMPARE(results.values(), QVector<quint16>({0x1111, 0x1112, 0x1113}));
+
+ //i block write at end
+ unit.setStartAddress(4);
+ results.setStartAddress(4);
+ unit.setValues({0x1, 0x2, 0x3});
+ QVERIFY(server.setData(unit));
+ QVERIFY(server.data(&results));
+ QCOMPARE(results.values(), QVector<quint16>({0x1, 0x2, 0x3}));
+
+
+ unit.setStartAddress(2); // overlap in front
+ QVERIFY(!server.setData(unit));
+ unit.setStartAddress(5); // overlap at end
+ QVERIFY(!server.setData(unit));
+
+ data = 0;
+ QVERIFY(!server.data(QModbusDataUnit::HoldingRegisters, 7, &data));
+ QCOMPARE(data, 0);
+ QVERIFY(!server.data(QModbusDataUnit::HoldingRegisters, 2, &data));
+ QCOMPARE(data, 0);
+
+ QVERIFY(!server.setData(QModbusDataUnit::HoldingRegisters, 7, 0xabcd));
+ QVERIFY(!server.setData(QModbusDataUnit::HoldingRegisters, 2, 0xabcd));
+
+ QVERIFY(!server.data(QModbusDataUnit::HoldingRegisters, 7, &data));
+ QCOMPARE(data, 0);
+ QVERIFY(!server.data(QModbusDataUnit::HoldingRegisters, 2, &data));
+ QCOMPARE(data, 0);
+ }
+
void tst_serverAddress()
{
server.setServerAddress(56);