diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | dist/changes-5.12.10 | 28 | ||||
-rw-r--r-- | dist/changes-5.15.2 | 25 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/libsocketcan.cpp | 10 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcanbackend.cpp | 2 | ||||
-rw-r--r-- | src/serialbus/qcanbusdevice.cpp | 2 | ||||
-rw-r--r-- | src/serialbus/qcanbusdeviceinfo.h | 2 | ||||
-rw-r--r-- | src/serialbus/qmodbusclient.cpp | 12 | ||||
-rw-r--r-- | src/serialbus/qmodbusdevice.cpp | 7 | ||||
-rw-r--r-- | src/serialbus/qmodbuspdu.cpp | 124 | ||||
-rw-r--r-- | src/serialbus/qmodbuspdu.h | 2 | ||||
-rw-r--r-- | src/serialbus/qmodbusreply.cpp | 10 | ||||
-rw-r--r-- | tests/auto/qmodbusreply/tst_qmodbusreply.cpp | 2 |
13 files changed, 166 insertions, 62 deletions
diff --git a/.qmake.conf b/.qmake.conf index d07755f..3edcad8 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) CONFIG += warning_clean DEFINES += QT_NO_FOREACH -MODULE_VERSION = 5.15.1 +MODULE_VERSION = 5.15.13 diff --git a/dist/changes-5.12.10 b/dist/changes-5.12.10 new file mode 100644 index 0000000..c9b97b2 --- /dev/null +++ b/dist/changes-5.12.10 @@ -0,0 +1,28 @@ +Qt 5.12.10 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.9. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + https://doc.qt.io/qt-5.12/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + +**************************************************************************** +* Library * +**************************************************************************** + + diff --git a/dist/changes-5.15.2 b/dist/changes-5.15.2 new file mode 100644 index 0000000..dbef3fc --- /dev/null +++ b/dist/changes-5.15.2 @@ -0,0 +1,25 @@ +Qt 5.15.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.15.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + https://doc.qt.io/qt-5.15/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* SocketCAN * +**************************************************************************** + + - [QTBUG-87328] Fixed that libsocketcan could not be loaded when no + symlink libsocketcan.so -> libsocketcan.so.2 was present. diff --git a/src/plugins/canbus/socketcan/libsocketcan.cpp b/src/plugins/canbus/socketcan/libsocketcan.cpp index c6144db..acc29c7 100644 --- a/src/plugins/canbus/socketcan/libsocketcan.cpp +++ b/src/plugins/canbus/socketcan/libsocketcan.cpp @@ -87,10 +87,14 @@ LibSocketCan::LibSocketCan(QString *errorString) { #if QT_CONFIG(library) auto resolveSymbols = [](QLibrary *library) { + const QString libName = QStringLiteral("socketcan"); if (!library->isLoaded()) { - library->setFileName(QStringLiteral("socketcan")); - if (!library->load()) - return false; + library->setFileName(libName); + if (!library->load()) { + library->setFileNameAndVersion(libName, 2); + if (!library->load()) + return false; + } } RESOLVE_SYMBOL(can_do_start); diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp index 572fef8..fe22494 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.cpp +++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp @@ -349,7 +349,7 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu case QCanBusDevice::BitRateKey: { const quint32 bitRate = value.toUInt(); - libSocketCan->setBitrate(canSocketName, bitRate); + success = libSocketCan->setBitrate(canSocketName, bitRate); break; } default: diff --git a/src/serialbus/qcanbusdevice.cpp b/src/serialbus/qcanbusdevice.cpp index 5b6c343..7cf0c7e 100644 --- a/src/serialbus/qcanbusdevice.cpp +++ b/src/serialbus/qcanbusdevice.cpp @@ -606,7 +606,7 @@ void QCanBusDevice::clear(QCanBusDevice::Directions direction) clearError(); if (direction & Direction::Input) { - QMutexLocker(&d->incomingFramesGuard); + QMutexLocker locker(&d->incomingFramesGuard); d->incomingFrames.clear(); } diff --git a/src/serialbus/qcanbusdeviceinfo.h b/src/serialbus/qcanbusdeviceinfo.h index c46302d..ee8d7ae 100644 --- a/src/serialbus/qcanbusdeviceinfo.h +++ b/src/serialbus/qcanbusdeviceinfo.h @@ -54,7 +54,7 @@ public: void swap(QCanBusDeviceInfo &other) Q_DECL_NOTHROW { - qSwap(d_ptr, other.d_ptr); + d_ptr.swap(other.d_ptr); } QCanBusDeviceInfo &operator=(const QCanBusDeviceInfo &other); diff --git a/src/serialbus/qmodbusclient.cpp b/src/serialbus/qmodbusclient.cpp index 56a1ab5..a5e3888 100644 --- a/src/serialbus/qmodbusclient.cpp +++ b/src/serialbus/qmodbusclient.cpp @@ -222,8 +222,12 @@ QModbusClient::QModbusClient(QModbusClientPrivate &dd, QObject *parent) : } /*! - Processes a Modbus server \a response and stores the decoded information in \a data. Returns - true on success; otherwise false. + Processes a Modbus server \a response and stores the decoded information in + \a data. Returns \c true on success; otherwise \c false. + + \note The default implementation does not support all + \l {QModbusPdu::}{FunctionCode}s. Override this method in a custom Modbus + client implementations to handle the needed functions. */ bool QModbusClient::processResponse(const QModbusResponse &response, QModbusDataUnit *data) { @@ -361,13 +365,13 @@ void QModbusClientPrivate::processQueueElement(const QModbusResponse &pdu, return; } - if (element.reply->type() != QModbusReply::Common) { + if (element.reply->type() == QModbusReply::Broadcast) { element.reply->setFinished(true); return; } QModbusDataUnit unit = element.unit; - if (!processResponse(pdu, &unit)) { + if (!q_func()->processResponse(pdu, &unit)) { element.reply->setError(QModbusDevice::UnknownError, QModbusClient::tr("An invalid response has been received.")); return; diff --git a/src/serialbus/qmodbusdevice.cpp b/src/serialbus/qmodbusdevice.cpp index ab8e126..58bdc6d 100644 --- a/src/serialbus/qmodbusdevice.cpp +++ b/src/serialbus/qmodbusdevice.cpp @@ -204,6 +204,13 @@ void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value) \value ReplyAbortedError The reply was aborted due to a disconnection of the device. \value UnknownError An unknown error occurred. + + \note An UnknownError can also indicate that the received + \l {QModbusPdu::}{FunctionCode} is not supported in the current + implementation. In this case custom Modbus client implementations need to + override the \l {QModbusClient::}{processResponse()} and + \l {QModbusClient::}{processPrivateResponse()} methods to provide support + for needed functions. */ /*! diff --git a/src/serialbus/qmodbuspdu.cpp b/src/serialbus/qmodbuspdu.cpp index 9ca9027..e23fa7b 100644 --- a/src/serialbus/qmodbuspdu.cpp +++ b/src/serialbus/qmodbuspdu.cpp @@ -48,13 +48,23 @@ Q_GLOBAL_STATIC(ReqSizeCalc, requestSizeCalculators); using ResSizeCalc = QHash<quint8, QModbusResponse::CalcFuncPtr>; Q_GLOBAL_STATIC(ResSizeCalc, responseSizeCalculators); -namespace Private { +struct QModbusPduPrivate +{ + QModbusPduPrivate() = delete; + Q_DISABLE_COPY_MOVE(QModbusPduPrivate) enum struct Type { Request, Response }; +/*! + \internal + + Returns the minimum data size in bytes for the given \a pdu and the + Modbus PDU \a type. If the PDU's function code is invalid, undefined + or unknown, the return value will be \c {-1}. +*/ static int minimumDataSize(const QModbusPdu &pdu, Type type) { if (pdu.isException()) @@ -103,44 +113,54 @@ static int minimumDataSize(const QModbusPdu &pdu, Type type) return -1; } -static QDataStream &pduFromStream(QDataStream &stream, QModbusPdu &pdu, Type type) +/*! + \internal + + Extracts a Modbus PDU from a \a stream into the given \a pdu based on \a type. +*/ +static QDataStream &pduFromStream(QDataStream &stream, Type type, QModbusPdu *pdu) { - quint8 codeByte = 0; - if (stream.readRawData(reinterpret_cast<char *>(&codeByte), sizeof(quint8)) != sizeof(quint8)) + struct RAII { + RAII(QModbusPdu *ptr = nullptr) + : tmp(ptr) {} + QModbusPdu *tmp{ nullptr }; + ~RAII() { if (tmp) *tmp = {}; } + } raii = { pdu }; + + QModbusPdu::FunctionCode code = QModbusPdu::FunctionCode::Invalid; + stream >> code; + if (stream.status() == QDataStream::ReadPastEnd) return stream; - QModbusPdu::FunctionCode code = QModbusPdu::FunctionCode(codeByte); - pdu.setFunctionCode(code); - - auto needsAdditionalRead = [](QModbusPdu &pdu, int size) -> bool { - if (size < 0) - pdu.setFunctionCode(QModbusResponse::Invalid); - if (size <= 0) - return false; - return true; - }; + pdu->setFunctionCode(code); - const bool isResponse = (type == Type::Response); - int size = isResponse ? QModbusResponse::minimumDataSize(pdu) - : QModbusRequest::minimumDataSize(pdu); - if (!needsAdditionalRead(pdu, size)) + if (code == QModbusPdu::Invalid) // shortcut return stream; - QByteArray data(size, Qt::Uninitialized); - if (stream.device()->peek(data.data(), data.size()) != size) - return stream; + constexpr const int MaxPduDataSize = 252; // in bytes - pdu.setData(data); - size = isResponse ? QModbusResponse::calculateDataSize(pdu) - : QModbusRequest::calculateDataSize(pdu); - if (!needsAdditionalRead(pdu, size)) + // The calculateDataSize(...) function might need some data inside the + // given PDU argument to be able to figure out the right data size (e.g. + // WriteMultipleCoils contains some kind of "header"). So fake fill the PDU + // with the maximum available data but no more than the allowed max PDU + // data size. + QByteArray data(MaxPduDataSize, Qt::Uninitialized); + int read = stream.device()->peek(data.data(), MaxPduDataSize); + if (read < 0) return stream; + data.resize(read); + pdu->setData(data); + + const bool isResponse = (type == Type::Response); + int size = isResponse ? QModbusResponse::calculateDataSize(*pdu) + : QModbusRequest::calculateDataSize(*pdu); + if (isResponse && (code == QModbusPdu::EncapsulatedInterfaceTransport)) { quint8 meiType; - pdu.decodeData(&meiType); + pdu->decodeData(&meiType); if (meiType == EncapsulatedInterfaceTransport::ReadDeviceIdentification) { int left = size, offset = 0; - while ((left > 0) && (size <= 252)) { // The maximum PDU data size is 252 bytes. + while ((left > 0) && (size <= MaxPduDataSize)) { data.resize(size); const int read = stream.readRawData(data.data() + offset, size - offset); if ((read < 0) || (read != (size - offset))) { @@ -152,35 +172,31 @@ static QDataStream &pduFromStream(QDataStream &stream, QModbusPdu &pdu, Type typ left = QModbusResponse::calculateDataSize(QModbusResponse(code, data)) - offset; size += left; } - if ((stream.status() == QDataStream::Ok) && (size <= 252)) { - pdu.setData(data); + if ((stream.status() == QDataStream::Ok) && (size <= MaxPduDataSize)) { + raii = {}; + pdu->setData(data); return stream; // early return to avoid second read } } else { data.resize(int(stream.device()->size() - 1)); // One byte for the function code. } - } else if (pdu.functionCode() == QModbusPdu::Diagnostics) { + } else if (pdu->functionCode() == QModbusPdu::Diagnostics) { quint16 subCode; - pdu.decodeData(&subCode); + pdu->decodeData(&subCode); if (subCode == Diagnostics::ReturnQueryData) data.resize(int(stream.device()->size() - 1)); // One byte for the function code. } - // reset what we have so far, next read might fail as well - pdu.setData(QByteArray()); - pdu.setFunctionCode(QModbusPdu::Invalid); - - if (data.size() <= 252) { // The maximum PDU data size is 252 bytes. + if (data.size() <= MaxPduDataSize) { data.resize(size); if (stream.readRawData(data.data(), data.size()) == size) { - pdu.setData(data); - pdu.setFunctionCode(code); + raii = {}; + pdu->setData(data); } } return stream; } - -} // namespace Private +}; /*! \class QModbusPdu @@ -533,7 +549,7 @@ QDataStream &operator<<(QDataStream &stream, const QModbusPdu &pdu) */ int QModbusRequest::minimumDataSize(const QModbusRequest &request) { - return Private::minimumDataSize(request, Private::Type::Request); + return QModbusPduPrivate::minimumDataSize(request, QModbusPduPrivate::Type::Request); } /*! @@ -555,7 +571,7 @@ int QModbusRequest::calculateDataSize(const QModbusRequest &request) return 1; int size = -1; - int minimum = Private::minimumDataSize(request, Private::Type::Request); + int minimum = QModbusPduPrivate::minimumDataSize(request, QModbusPduPrivate::Type::Request); if (minimum < 0) return size; @@ -608,6 +624,22 @@ void QModbusRequest::registerDataSizeCalculator(FunctionCode fc, CalcFuncPtr cal } /*! + \internal + + Reads a FunctionCode from a \a stream. + In stream we serialize FunctionCode as one byte, so we use a temporary char + variable to make the code work on both little endian and big endian systems. + If reading from stream fails, code will retain original value. +*/ +QDataStream &operator>>(QDataStream &stream, QModbusPdu::FunctionCode &code) +{ + char buffer; + if (stream.readRawData(&buffer, 1) == 1) + code = static_cast<QModbusPdu::FunctionCode>(buffer); + return stream; +} + +/*! \relates QModbusRequest Reads a \a pdu from the \a stream and returns a reference to the stream. @@ -620,7 +652,7 @@ void QModbusRequest::registerDataSizeCalculator(FunctionCode fc, CalcFuncPtr cal */ QDataStream &operator>>(QDataStream &stream, QModbusRequest &pdu) { - return Private::pduFromStream(stream, pdu, Private::Type::Request); + return QModbusPduPrivate::pduFromStream(stream, QModbusPduPrivate::Type::Request, &pdu); } /*! @@ -689,7 +721,7 @@ QDataStream &operator>>(QDataStream &stream, QModbusRequest &pdu) */ int QModbusResponse::minimumDataSize(const QModbusResponse &response) { - return Private::minimumDataSize(response, Private::Type::Response); + return QModbusPduPrivate::minimumDataSize(response, QModbusPduPrivate::Type::Response); } /*! @@ -711,7 +743,7 @@ int QModbusResponse::calculateDataSize(const QModbusResponse &response) return 1; int size = -1; - int minimum = Private::minimumDataSize(response, Private::Type::Response); + int minimum = QModbusPduPrivate::minimumDataSize(response, QModbusPduPrivate::Type::Response); if (minimum < 0) return size; @@ -806,7 +838,7 @@ void QModbusResponse::registerDataSizeCalculator(FunctionCode fc, CalcFuncPtr ca */ QDataStream &operator>>(QDataStream &stream, QModbusResponse &pdu) { - return Private::pduFromStream(stream, pdu, Private::Type::Response); + return QModbusPduPrivate::pduFromStream(stream, QModbusPduPrivate::Type::Response, &pdu); } /*! diff --git a/src/serialbus/qmodbuspdu.h b/src/serialbus/qmodbuspdu.h index e93ec4c..5bca0d3 100644 --- a/src/serialbus/qmodbuspdu.h +++ b/src/serialbus/qmodbuspdu.h @@ -183,9 +183,11 @@ private: FunctionCode m_code = Invalid; QByteArray m_data; friend class QModbusSerialAdu; + friend struct QModbusPduPrivate; }; Q_SERIALBUS_EXPORT QDebug operator<<(QDebug debug, const QModbusPdu &pdu); Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &stream, const QModbusPdu &pdu); +Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &stream, QModbusPdu::FunctionCode &code); class QModbusRequest : public QModbusPdu { diff --git a/src/serialbus/qmodbusreply.cpp b/src/serialbus/qmodbusreply.cpp index caa2dd9..374fb81 100644 --- a/src/serialbus/qmodbusreply.cpp +++ b/src/serialbus/qmodbusreply.cpp @@ -147,15 +147,17 @@ void QModbusReply::setFinished(bool isFinished) If the request has not finished, has failed with an error or was a write request then the returned \l QModbusDataUnit instance is invalid. - \note If the \l type() of the reply is \l QModbusReply::Raw, the return - value will always be invalid. + \note If the \l type() of the reply is \l QModbusReply::Broadcast, the + return value will always be invalid. If the l type() of the reply is + \l QModbusReply::Raw, the return value might be invalid depending on the + implementation of \l QModbusClient::processPrivateResponse(). - \sa type(), rawResult() + \sa type(), rawResult(), QModbusClient::processPrivateResponse() */ QModbusDataUnit QModbusReply::result() const { Q_D(const QModbusReply); - if (type() == QModbusReply::Common) + if (type() != QModbusReply::Broadcast) return d->m_unit; return QModbusDataUnit(); } diff --git a/tests/auto/qmodbusreply/tst_qmodbusreply.cpp b/tests/auto/qmodbusreply/tst_qmodbusreply.cpp index 810fbee..3ac0395 100644 --- a/tests/auto/qmodbusreply/tst_qmodbusreply.cpp +++ b/tests/auto/qmodbusreply/tst_qmodbusreply.cpp @@ -213,7 +213,7 @@ void tst_QModbusReply::tst_setResult() replyRawTest.setRawResult(response); QCOMPARE(finishedSpy.count(), 0); QCOMPARE(errorSpyRaw.count(), 0); - QCOMPARE(replyRawTest.result().isValid(), false); + QCOMPARE(replyRawTest.result().isValid(), true); QCOMPARE(replyRawTest.rawResult().isValid(), true); tmp = replyRawTest.rawResult(); |