diff options
author | Alex Blasche <alexander.blasche@qt.io> | 2018-10-27 03:01:09 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@qt.io> | 2018-10-29 11:07:39 +0100 |
commit | 8c4b7368b5b8c499a3cdf40b2f4ae8bbfc616dd0 (patch) | |
tree | 5dafb3e927b8e307bea1b6fcb3512aeed30b7194 | |
parent | fbb3abbca7cdb37e8d663175c96bc808ac0a1899 (diff) | |
parent | df179c4c18d8feeef48e38cc76cd2a0395ba5de1 (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.h | 17 | ||||
-rw-r--r-- | src/serialbus/qmodbusrtuserialslave_p.h | 24 | ||||
-rw-r--r-- | src/serialbus/qmodbusserver.cpp | 11 | ||||
-rw-r--r-- | tests/auto/qmodbusserver/tst_qmodbusserver.cpp | 66 |
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); |