diff options
28 files changed, 274 insertions, 40 deletions
diff --git a/.qmake.conf b/.qmake.conf index 96f7a81..a93cfcc 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.0 +MODULE_VERSION = 6.0.0 diff --git a/dependencies.yaml b/dependencies.yaml new file mode 100644 index 0000000..06ed447 --- /dev/null +++ b/dependencies.yaml @@ -0,0 +1,7 @@ +dependencies: + ../qtbase: + ref: 4c5f6eb74cfb3282513c0837c80a08705c1da844 + required: true + ../qtserialport: + ref: 543e41db0f13f552c5bb36e58b39045b70f369b5 + required: false diff --git a/examples/serialbus/can/connectdialog.cpp b/examples/serialbus/can/connectdialog.cpp index 601ef2c..a0430b4 100644 --- a/examples/serialbus/can/connectdialog.cpp +++ b/examples/serialbus/can/connectdialog.cpp @@ -120,6 +120,10 @@ void ConnectDialog::interfaceChanged(const QString &interface) if (serialNumber.isEmpty()) serialNumber = tr("n/a"); m_ui->serialNumberLabel->setText(tr("Serial: %1").arg(serialNumber)); + QString alias = info.alias(); + if (alias.isEmpty()) + alias = tr("n/a"); + m_ui->aliasLabel->setText(tr("Alias: %1").arg(alias)); m_ui->channelLabel->setText(tr("Channel: %1").arg(info.channel())); m_ui->isVirtual->setChecked(info.isVirtual()); m_ui->isFlexibleDataRateCapable->setChecked(info.hasFlexibleDataRate()); diff --git a/examples/serialbus/can/connectdialog.ui b/examples/serialbus/can/connectdialog.ui index 6d4f261..b4ba898 100644 --- a/examples/serialbus/can/connectdialog.ui +++ b/examples/serialbus/can/connectdialog.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>446</width> - <height>395</height> + <height>418</height> </rect> </property> <property name="windowTitle"> @@ -206,6 +206,13 @@ </widget> </item> <item> + <widget class="QLabel" name="aliasLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> <widget class="QLabel" name="channelLabel"> <property name="text"> <string/> diff --git a/examples/serialbus/modbus/adueditor/plaintextedit.h b/examples/serialbus/modbus/adueditor/plaintextedit.h index cbc590c..f5505fe 100644 --- a/examples/serialbus/modbus/adueditor/plaintextedit.h +++ b/examples/serialbus/modbus/adueditor/plaintextedit.h @@ -59,6 +59,11 @@ class PlainTextEdit : public QPlainTextEdit Q_OBJECT Q_DISABLE_COPY(PlainTextEdit) +public Q_SLOT: + void setFocus() { + QWidget::setFocus(); + } + public: explicit PlainTextEdit(QWidget *parent = nullptr) : QPlainTextEdit(parent) diff --git a/src/plugins/canbus/passthrucan/passthrucanbackend.cpp b/src/plugins/canbus/passthrucan/passthrucanbackend.cpp index 2c18160..380f6ea 100644 --- a/src/plugins/canbus/passthrucan/passthrucanbackend.cpp +++ b/src/plugins/canbus/passthrucan/passthrucanbackend.cpp @@ -200,7 +200,7 @@ bool PassThruCanBackend::open() QByteArray subDev; if (splitPos >= 0) - subDev = m_deviceName.midRef(splitPos + 1).toLatin1(); + subDev = QStringView{m_deviceName}.mid(splitPos + 1).toLatin1(); const QString library = libraryForAdapter(adapter); if (library.isEmpty()) { diff --git a/src/plugins/canbus/peakcan/peakcan_symbols_p.h b/src/plugins/canbus/peakcan/peakcan_symbols_p.h index 12de76f..9031592 100644 --- a/src/plugins/canbus/peakcan/peakcan_symbols_p.h +++ b/src/plugins/canbus/peakcan/peakcan_symbols_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2017 Denis Shienkov <denis.shienkov@gmail.com> +** Copyright (c) 2020 Andre Hartmann <aha_1980@gmx.de> ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -168,7 +169,7 @@ #define PCAN_PCC 0x06U // PCAN-PC Card // PCAN parameters -#define PCAN_DEVICE_NUMBER 0x01U // PCAN-USB device number parameter +#define PCAN_DEVICE_ID 0x01U // Device identifier parameter #define PCAN_5VOLTS_POWER 0x02U // PCAN-PC Card 5-Volt power parameter #define PCAN_RECEIVE_EVENT 0x03U // PCAN receive event handler parameter #define PCAN_MESSAGE_FILTER 0x04U // PCAN message filter parameter @@ -197,6 +198,8 @@ #define PCAN_BUSSPEED_DATA 0x1BU // Configured CAN data speed as Bits per seconds #define PCAN_IP_ADDRESS 0x1CU // Remote address of a LAN channel as string in IPv4 format #define PCAN_LAN_SERVICE_STATUS 0x1DU // Status of the Virtual PCAN-Gateway Service +#define PCAN_ATTACHED_CHANNELS_COUNT 0x2AU // Get the amount of PCAN channels attached to a system +#define PCAN_ATTACHED_CHANNELS 0x2BU // Get information about PCAN channels attached to a system #define FEATURE_FD_CAPABLE 0x01U // Device supports flexible data-rate (CAN-FD) @@ -225,6 +228,10 @@ #define TRACE_FILE_TIME 0x04U // Includes the start time into the name of the trace file #define TRACE_FILE_OVERWRITE 0x80U // Causes the overwriting of available traces (same name) +// Other constants +#define MAX_LENGTH_HARDWARE_NAME 33 // Maximum length of the name of a device: 32 characters + terminator +#define MAX_LENGTH_VERSION_STRING 18 // Maximum length of a version string: 17 characters + terminator + // PCAN message types #define PCAN_MESSAGE_STANDARD 0x00U // The PCAN message is a CAN Standard Frame (11-bit identifier) #define PCAN_MESSAGE_RTR 0x01U // The PCAN message is a CAN Remote-Transfer-Request Frame @@ -312,6 +319,18 @@ typedef struct tagTPCANMsgFD quint8 DATA[64]; // Data of the message (DATA[0]..DATA[63]) } TPCANMsgFD; +// Describes an available PCAN channel +typedef struct tagTPCANChannelInformation +{ + TPCANHandle channel_handle; // PCAN channel handle + TPCANDevice device_type; // Kind of PCAN device + quint8 controller_number; // CAN-Controller number + quint32 device_features; // Device capabilities flag (see FEATURE_*) + char device_name[MAX_LENGTH_HARDWARE_NAME]; // Device name + quint32 device_id; // Device number + quint32 channel_condition; // Availability status of a PCAN-Channel +} TPCANChannelInformation; + #define GENERATE_SYMBOL_VARIABLE(returnType, symbolName, ...) \ typedef returnType (DRV_CALLBACK_TYPE *fp_##symbolName)(__VA_ARGS__); \ static fp_##symbolName symbolName; diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp index 6e1af1c..0b4cf5b 100644 --- a/src/plugins/canbus/peakcan/peakcanbackend.cpp +++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2017 Denis Shienkov <denis.shienkov@gmail.com> +** Copyright (c) 2020 Andre Hartmann <aha_1980@gmx.de> ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -46,6 +47,7 @@ #include <QtCore/qloggingcategory.h> #include <algorithm> +#include <vector> #ifdef Q_OS_WIN32 # include <QtCore/qwineventnotifier.h> @@ -64,7 +66,7 @@ Q_GLOBAL_STATIC(QLibrary, pcanLibrary) bool PeakCanBackend::canCreate(QString *errorReason) { #ifdef LINK_LIBPCANBASIC - return true; + Q_UNUSED(errorReason); #else static bool symbolsResolved = resolvePeakCanSymbols(pcanLibrary()); if (Q_UNLIKELY(!symbolsResolved)) { @@ -73,8 +75,17 @@ bool PeakCanBackend::canCreate(QString *errorReason) *errorReason = pcanLibrary()->errorString(); return false; } - return true; #endif + + char apiVersion[32]; + TPCANStatus stat = CAN_GetValue(PCAN_NONEBUS, PCAN_API_VERSION, apiVersion, sizeof(apiVersion)); + if (Q_UNLIKELY(stat != PCAN_ERROR_OK)) { + qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot resolve PCAN-API version!"); + return false; + } + qCInfo(QT_CANBUS_PLUGINS_PEAKCAN, "Using PCAN-API version: %s", apiVersion); + + return true; } struct PcanChannel{ @@ -117,7 +128,7 @@ static const PcanChannel pcanChannels[] = { { "none", PCAN_NONEBUS } }; -QList<QCanBusDeviceInfo> PeakCanBackend::interfaces() +QList<QCanBusDeviceInfo> PeakCanBackend::interfacesByChannelCondition() { QList<QCanBusDeviceInfo> result; @@ -143,15 +154,81 @@ QList<QCanBusDeviceInfo> PeakCanBackend::interfaces() if (chnStat != PCAN_ERROR_OK) channel = 0; + QString alias; + quint32 deviceId = 0; + const TPCANStatus idStat = ::CAN_GetValue(index, PCAN_DEVICE_ID, + &deviceId, sizeof(deviceId)); + if (idStat == PCAN_ERROR_OK) + alias = QString::number(deviceId); + result.append(std::move(createDeviceInfo(QLatin1String(pcanChannels[i].name), QString(), QLatin1String(description), - channel, false, isFd))); + alias, channel, false, isFd))); + } + } + + return result; +} + +QList<QCanBusDeviceInfo> PeakCanBackend::interfacesByAttachedChannels(bool *ok) +{ + *ok = true; + quint32 count = 0; + const TPCANStatus countStat = ::CAN_GetValue(0, PCAN_ATTACHED_CHANNELS_COUNT, + &count, sizeof(count)); + if (Q_UNLIKELY(countStat != PCAN_ERROR_OK)) { + qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot query PCAN_ATTACHED_CHANNELS_COUNT."); + *ok = false; + return {}; + } + if (count == 0) + return {}; + + std::vector<TPCANChannelInformation> infos(count); + const TPCANStatus infosStat = ::CAN_GetValue(0, PCAN_ATTACHED_CHANNELS, infos.data(), + infos.size() * sizeof(TPCANChannelInformation)); + if (Q_UNLIKELY(infosStat != PCAN_ERROR_OK)) { + qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot query PCAN_ATTACHED_CHANNELS."); + *ok = false; + return {}; + } + + QList<QCanBusDeviceInfo> result; + for (quint32 i = 0; i < count; ++i) { + auto info = infos[i]; + if (info.channel_condition & PCAN_CHANNEL_AVAILABLE) { + const quint32 deviceId = info.channel_handle; + const auto pcanChannel = std::find_if(std::begin(pcanChannels), std::end(pcanChannels), + [deviceId](PcanChannel channel) { + return channel.index == deviceId; + }); + const QString name = pcanChannel->name; + const QString description = info.device_name; + const QString alias = QString::number(info.device_id); + const int channel = info.controller_number; + const bool isCanFd = (info.device_features & FEATURE_FD_CAPABLE); + + result.append(std::move(createDeviceInfo(name, QString(), description, alias, + channel, false, isCanFd))); } } return result; } +QList<QCanBusDeviceInfo> PeakCanBackend::interfaces() +{ +#ifdef Q_OS_WIN + bool ok = false; + const QList<QCanBusDeviceInfo> attachedChannelsResult = interfacesByAttachedChannels(&ok); + if (ok) + return attachedChannelsResult; +#endif + + const QList<QCanBusDeviceInfo> result = interfacesByChannelCondition(); + return result; +} + #if defined(Q_OS_WIN32) class PeakCanReadNotifier : public QWinEventNotifier { diff --git a/src/plugins/canbus/peakcan/peakcanbackend.h b/src/plugins/canbus/peakcan/peakcanbackend.h index a9e108e..0ee74c3 100644 --- a/src/plugins/canbus/peakcan/peakcanbackend.h +++ b/src/plugins/canbus/peakcan/peakcanbackend.h @@ -69,6 +69,8 @@ public: QString interpretErrorFrame(const QCanBusFrame &errorFrame) override; static bool canCreate(QString *errorReason); + static QList<QCanBusDeviceInfo> interfacesByChannelCondition(); + static QList<QCanBusDeviceInfo> interfacesByAttachedChannels(bool *ok); static QList<QCanBusDeviceInfo> interfaces(); private: diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp index 550f744..5d719d8 100644 --- a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp +++ b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp @@ -299,7 +299,7 @@ void VectorCanBackendPrivate::setupChannel(const QString &interfaceName) { Q_Q(VectorCanBackend); if (Q_LIKELY(interfaceName.startsWith(QStringLiteral("can")))) { - const QStringRef ref = interfaceName.midRef(3); + const QStringView ref = QStringView{interfaceName}.mid(3); bool ok = false; channelIndex = ref.toInt(&ok); if (ok && (channelIndex >= 0 && channelIndex < XL_CONFIG_MAX_CHANNELS)) { diff --git a/src/serialbus/doc/src/peakcan.qdoc b/src/serialbus/doc/src/peakcan.qdoc index a38ddf7..c10263b 100644 --- a/src/serialbus/doc/src/peakcan.qdoc +++ b/src/serialbus/doc/src/peakcan.qdoc @@ -34,10 +34,13 @@ \l{http://www.peak-system.com/}{PEAK-System} CAN adapters. This plugin requires the PCAN device drivers and the PCAN-Basic library - version 4.0.0 or higher on Windows (pcanbasic.dll) and Linux (libpcanbasic.so). - On macOS the plugin requires the PCBUSB library from + version 4.4.0 or higher on Windows (pcanbasic.dll) resp. 4.0.0 on Linux + (libpcanbasic.so). On macOS the plugin requires the PCBUSB library from \l{http://www.mac-can.com}{UV Software}. + \note QCanBusDeviceInfo::alias() is only supported on Windows and with + PCAN-Basic 4.4.0 or higher. + \section1 Creating CAN Bus Devices At first it is necessary to check that QCanBus provides the desired plugin: @@ -126,6 +129,11 @@ \list \li QCanBusDevice::resetController() \li QCanBusDevice::busStatus() + \li QCanBusDeviceInfo::alias() (Windows and PCAN-Basic >= 4.4.0 only): + Returns the PCAN_DEVICE_ID which can be set to a user defined value + from 0..255 resp. 0..4294967295 (depending on the device) with PCAN-View. + The default value is 255 resp. 4294967295. + \endlist */ diff --git a/src/serialbus/qcanbusdevice.cpp b/src/serialbus/qcanbusdevice.cpp index 5b6c343..eab2a7e 100644 --- a/src/serialbus/qcanbusdevice.cpp +++ b/src/serialbus/qcanbusdevice.cpp @@ -984,7 +984,8 @@ void QCanBusDevice::setState(QCanBusDevice::CanBusDeviceState newState) QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, bool isVirtual, bool isFlexibleDataRateCapable) { - return createDeviceInfo(name, QString(), QString(), 0, isVirtual, isFlexibleDataRateCapable); + return createDeviceInfo(name, QString(), QString(), QString(), + 0, isVirtual, isFlexibleDataRateCapable); } /*! @@ -998,10 +999,27 @@ QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, const QSt const QString &description, int channel, bool isVirtual, bool isFlexibleDataRateCapable) { + return createDeviceInfo(name, serialNumber, description, QString(), + channel, isVirtual, isFlexibleDataRateCapable); +} + +/*! + \since 6.0 + Returns a QCanBusDeviceInfo created from the given parameters \a name, + \a serialNumber, \a description, \a alias, \a channel, \a isVirtual, + and \a isFlexibleDataRateCapable. + \internal + */ +QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, const QString &serialNumber, + const QString &description, const QString &alias, + int channel, + bool isVirtual, bool isFlexibleDataRateCapable) +{ QScopedPointer<QCanBusDeviceInfoPrivate> info(new QCanBusDeviceInfoPrivate); info->name = name; info->serialNumber = serialNumber; info->description = description; + info->alias = alias; info->channel = channel; info->hasFlexibleDataRate = isFlexibleDataRateCapable; info->isVirtual = isVirtual; diff --git a/src/serialbus/qcanbusdevice.h b/src/serialbus/qcanbusdevice.h index 5d2d976..0afd896 100644 --- a/src/serialbus/qcanbusdevice.h +++ b/src/serialbus/qcanbusdevice.h @@ -191,6 +191,10 @@ protected: static QCanBusDeviceInfo createDeviceInfo(const QString &name, const QString &serialNumber, const QString &description, int channel, bool isVirtual, bool isFlexibleDataRateCapable); + static QCanBusDeviceInfo createDeviceInfo(const QString &name, const QString &serialNumber, + const QString &description, + const QString &alias, int channel, + bool isVirtual, bool isFlexibleDataRateCapable); }; Q_DECLARE_TYPEINFO(QCanBusDevice::CanBusError, Q_PRIMITIVE_TYPE); diff --git a/src/serialbus/qcanbusdeviceinfo.cpp b/src/serialbus/qcanbusdeviceinfo.cpp index 78dcd89..55d15df 100644 --- a/src/serialbus/qcanbusdeviceinfo.cpp +++ b/src/serialbus/qcanbusdeviceinfo.cpp @@ -110,6 +110,8 @@ QString QCanBusDeviceInfo::description() const \since 5.11 Returns the serial number of the CAN bus interface as string, if available. Otherwise, an empty string is returned. + + \sa alias() */ QString QCanBusDeviceInfo::serialNumber() const { @@ -117,6 +119,24 @@ QString QCanBusDeviceInfo::serialNumber() const } /*! + \since 6.0 + Returns a user defineable alias associated with this CAN bus interface. + + Some CAN bus interfaces can have a user defined alias associated. This is mostly + done with the CAN hardware vendors tools. The alias allows to identify this + hardware later, especially when multiple interfaces are connected. + + \note In contrast to serialNumber(), the alias is not guaranteed to be unique. + + If that function is not supported by the CAN plugin, an empty string is returned. + \sa serialNumber() +*/ +QString QCanBusDeviceInfo::alias() const +{ + return d_ptr->alias; +} + +/*! \since 5.11 Returns the sequential channel number of the CAN bus interface, starting with zero. For example, a two channel CAN interface may have the channels diff --git a/src/serialbus/qcanbusdeviceinfo.h b/src/serialbus/qcanbusdeviceinfo.h index c46302d..487a94d 100644 --- a/src/serialbus/qcanbusdeviceinfo.h +++ b/src/serialbus/qcanbusdeviceinfo.h @@ -67,6 +67,7 @@ public: QString name() const; QString description() const; QString serialNumber() const; + QString alias() const; int channel() const; bool hasFlexibleDataRate() const; diff --git a/src/serialbus/qcanbusdeviceinfo_p.h b/src/serialbus/qcanbusdeviceinfo_p.h index 78c9e1c..637343b 100644 --- a/src/serialbus/qcanbusdeviceinfo_p.h +++ b/src/serialbus/qcanbusdeviceinfo_p.h @@ -64,6 +64,7 @@ public: QString name; QString description; QString serialNumber; + QString alias; int channel = 0; bool hasFlexibleDataRate = false; bool isVirtual = false; diff --git a/src/serialbus/qcanbusfactory.h b/src/serialbus/qcanbusfactory.h index cd7322b..f8cb533 100644 --- a/src/serialbus/qcanbusfactory.h +++ b/src/serialbus/qcanbusfactory.h @@ -58,8 +58,8 @@ Q_DECLARE_INTERFACE(QCanBusFactory, "org.qt-project.Qt.QCanBusFactory") class Q_SERIALBUS_EXPORT QCanBusFactoryV2 : public QCanBusFactory { public: - virtual QCanBusDevice *createDevice(const QString &interfaceName, - QString *errorMessage) const = 0; + QCanBusDevice *createDevice(const QString &interfaceName, + QString *errorMessage) const override = 0; virtual QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const = 0; protected: diff --git a/src/serialbus/qmodbusclient_p.h b/src/serialbus/qmodbusclient_p.h index f9a0dfb..05c799a 100644 --- a/src/serialbus/qmodbusclient_p.h +++ b/src/serialbus/qmodbusclient_p.h @@ -42,6 +42,7 @@ #include <QtSerialBus/qmodbuspdu.h> #include <private/qmodbusdevice_p.h> +#include <limits.h> // // W A R N I N G diff --git a/src/serialbus/qmodbusdevice.cpp b/src/serialbus/qmodbusdevice.cpp index ab8e126..32bd936 100644 --- a/src/serialbus/qmodbusdevice.cpp +++ b/src/serialbus/qmodbusdevice.cpp @@ -95,11 +95,6 @@ QModbusDevice::~QModbusDevice() \value NetworkPortParameter This parameter holds the network port. \c int \value NetworkAddressParameter This parameter holds the host address for network communication. \c QString - - User options: - - \value UserParameter This enum value has been deprecated. There - will be no replacement. */ /*! @@ -120,7 +115,7 @@ QModbusDevice::~QModbusDevice() \sa ConnectionParameter */ -QVariant QModbusDevice::connectionParameter(int parameter) const +QVariant QModbusDevice::connectionParameter(ConnectionParameter parameter) const { Q_D(const QModbusDevice); switch (parameter) { @@ -143,7 +138,7 @@ QVariant QModbusDevice::connectionParameter(int parameter) const default: break; } - return d->m_userConnectionParams.value(parameter); // ### Qt6: remove + return {}; } /*! @@ -154,7 +149,7 @@ QVariant QModbusDevice::connectionParameter(int parameter) const \sa ConnectionParameter \sa connectionParameter() */ -void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value) +void QModbusDevice::setConnectionParameter(ConnectionParameter parameter, const QVariant &value) { Q_D(QModbusDevice); switch (parameter) { @@ -182,7 +177,7 @@ void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value) d->m_networkAddress = value.toString(); break; default: - d->m_userConnectionParams.insert(parameter, value); // ### Qt6: remove + Q_ASSERT_X(false, "", "Connection parameter not supported."); break; } } @@ -217,6 +212,27 @@ void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value) */ /*! + \since 6.0 + \enum QModbusDevice::IntermediateError + + This enum describes possible errors that can happen during a full send and + receive cycle for a Modbus reply. + + \value ResponseCrcError A Modbus response with a wrong CRC was received. + \value ResponseRequestMismatch A Modbus response was received but did not + match the open request, probably due to the + PDU's function code not matching. + + If any of the above intermediate errors occurred, the frame is likely + resent until the maximum number of retries has been reached. + + The list of intermediate errors can be inspected from the \l QModbusReply + intermediate errors function. + + \sa QModbusClient::numberOfRetries(), QModbusReply::intermediateErrors() +*/ + +/*! \fn QModbusDevice::errorOccurred(QModbusDevice::Error error) This signal is emitted when an error of the type, \a error, occurs. diff --git a/src/serialbus/qmodbusdevice.h b/src/serialbus/qmodbusdevice.h index 0e6dad7..e620613 100644 --- a/src/serialbus/qmodbusdevice.h +++ b/src/serialbus/qmodbusdevice.h @@ -79,18 +79,22 @@ public: SerialStopBitsParameter, NetworkPortParameter, - NetworkAddressParameter, - - // Reserved - UserParameter = 0x100 // ### Qt6: remove + NetworkAddressParameter }; Q_ENUM(ConnectionParameter) + enum IntermediateError + { + ResponseCrcError, + ResponseRequestMismatch + }; + Q_ENUM(IntermediateError) + explicit QModbusDevice(QObject *parent = nullptr); ~QModbusDevice(); - QVariant connectionParameter(int parameter) const; - void setConnectionParameter(int parameter, const QVariant &value); + QVariant connectionParameter(ConnectionParameter parameter) const; + void setConnectionParameter(ConnectionParameter parameter, const QVariant &value); bool connectDevice(); void disconnectDevice(); @@ -118,6 +122,7 @@ protected: Q_DECLARE_TYPEINFO(QModbusDevice::Error, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QModbusDevice::State, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QModbusDevice::ConnectionParameter, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QModbusDevice::IntermediateError, Q_PRIMITIVE_TYPE); QT_END_NAMESPACE diff --git a/src/serialbus/qmodbusdevice_p.h b/src/serialbus/qmodbusdevice_p.h index 1526397..c60ffc4 100644 --- a/src/serialbus/qmodbusdevice_p.h +++ b/src/serialbus/qmodbusdevice_p.h @@ -78,8 +78,6 @@ public: int m_networkPort = 502; QString m_networkAddress = QStringLiteral("127.0.0.1"); - QHash<int, QVariant> m_userConnectionParams; // ### Qt6: remove - virtual QIODevice *device() const { return nullptr; } }; diff --git a/src/serialbus/qmodbuspdu.cpp b/src/serialbus/qmodbuspdu.cpp index 9ca9027..1f13a0e 100644 --- a/src/serialbus/qmodbuspdu.cpp +++ b/src/serialbus/qmodbuspdu.cpp @@ -439,7 +439,7 @@ static QDataStream &pduFromStream(QDataStream &stream, QModbusPdu &pdu, Type typ QDebug operator<<(QDebug debug, const QModbusPdu &pdu) { QDebugStateSaver _(debug); - debug.nospace().noquote() << "0x" << Qt::hex << qSetFieldWidth(2) << qSetPadChar('0') + debug.nospace().noquote() << "0x" << Qt::hex << qSetFieldWidth(2) << qSetPadChar(u'0') << (pdu.isException() ? pdu.functionCode() | QModbusPdu::ExceptionByte : pdu.functionCode()) << qSetFieldWidth(0) << pdu.data().toHex(); return debug; diff --git a/src/serialbus/qmodbuspdu.h b/src/serialbus/qmodbuspdu.h index e93ec4c..f0542d9 100644 --- a/src/serialbus/qmodbuspdu.h +++ b/src/serialbus/qmodbuspdu.h @@ -249,7 +249,7 @@ public: : QModbusResponse(FunctionCode(quint8(fc) | ExceptionByte), static_cast<quint8> (ec)) {} - void setFunctionCode(FunctionCode c) { + void setFunctionCode(FunctionCode c) override { QModbusPdu::setFunctionCode(FunctionCode(quint8(c) | ExceptionByte)); } void setExceptionCode(ExceptionCode ec) { QModbusPdu::encodeData(quint8(ec)); } diff --git a/src/serialbus/qmodbusreply.cpp b/src/serialbus/qmodbusreply.cpp index caa2dd9..e5561c2 100644 --- a/src/serialbus/qmodbusreply.cpp +++ b/src/serialbus/qmodbusreply.cpp @@ -53,6 +53,7 @@ public: QString m_errorText; QModbusResponse m_response; QModbusReply::ReplyType m_type; + QVector<QModbusDevice::IntermediateError> m_intermediateErrors; }; /*! @@ -239,7 +240,6 @@ QString QModbusReply::errorString() const return d->m_errorText; } - /*! Returns the type of the reply. @@ -278,6 +278,41 @@ void QModbusReply::setRawResult(const QModbusResponse &response) d->m_response = response; } +/*! + \since 6.0 + \fn void intermediateErrorOccurred(QModbusDevice::IntermediateError error) + + This signal is emitted when an error has been detected in the processing of + this reply. The error will be described by the error code \a error. +*/ + +/*! + \since 6.0 + + Returns the list of intermediate errors that might have happened during + the send-receive cycle of a Modbus request until the QModbusReply reports + to be finished. +*/ +QVector<QModbusDevice::IntermediateError> QModbusReply::intermediateErrors() const +{ + Q_D(const QModbusReply); + return d->m_intermediateErrors; +} + +/*! + \internal + \since 6.0 + + Adds an intermediate error to the list of intermediate errors. + This will also cause the \l intermediateErrorOccurred() signal to be emitted. +*/ +void QModbusReply::addIntermediateError(QModbusDevice::IntermediateError error) +{ + Q_D(QModbusReply); + d->m_intermediateErrors.append(error); + emit intermediateErrorOccurred(error); +} + QT_END_NAMESPACE #include "moc_qmodbusreply.cpp" diff --git a/src/serialbus/qmodbusreply.h b/src/serialbus/qmodbusreply.h index ffefc89..7381912 100644 --- a/src/serialbus/qmodbusreply.h +++ b/src/serialbus/qmodbusreply.h @@ -37,6 +37,7 @@ #ifndef QMODBUSREPLY_H #define QMODBUSREPLY_H +#include <QtCore/qvector.h> #include <QtSerialBus/qmodbusdataunit.h> #include <QtSerialBus/qmodbusdevice.h> #include <QtSerialBus/qmodbuspdu.h> @@ -77,9 +78,13 @@ public: void setFinished(bool isFinished); void setError(QModbusDevice::Error error, const QString &errorText); + QVector<QModbusDevice::IntermediateError> intermediateErrors() const; + void addIntermediateError(QModbusDevice::IntermediateError error); + Q_SIGNALS: void finished(); void errorOccurred(QModbusDevice::Error error); + void intermediateErrorOccurred(QModbusDevice::IntermediateError error); }; Q_DECLARE_TYPEINFO(QModbusReply::ReplyType, Q_PRIMITIVE_TYPE); diff --git a/src/serialbus/qmodbusrtuserialmaster_p.h b/src/serialbus/qmodbusrtuserialmaster_p.h index d206eec..4c75951 100644 --- a/src/serialbus/qmodbusrtuserialmaster_p.h +++ b/src/serialbus/qmodbusrtuserialmaster_p.h @@ -98,7 +98,7 @@ private: class QModbusRtuSerialMasterPrivate : public QModbusClientPrivate { Q_DECLARE_PUBLIC(QModbusRtuSerialMaster) - enum State + enum State { Idle, WaitingForReplay, @@ -165,6 +165,7 @@ public: qCWarning(QT_MODBUS) << "(RTU client) Discarding response with wrong CRC, received:" << adu.checksum<quint16>() << ", calculated CRC:" << QModbusSerialAdu::calculateCRC(adu.data(), adu.size()); + m_queue.first().reply->addIntermediateError(QModbusClient::ResponseCrcError); return; } @@ -172,6 +173,7 @@ public: if (!canMatchRequestAndResponse(response, adu.serverAddress())) { qCWarning(QT_MODBUS) << "(RTU client) Cannot match response with open request, " "ignoring"; + m_queue.first().reply->addIntermediateError(QModbusClient::ResponseRequestMismatch); return; } diff --git a/src/serialbus/qmodbustcpclient_p.h b/src/serialbus/qmodbustcpclient_p.h index 4c574a1..cdac792 100644 --- a/src/serialbus/qmodbustcpclient_p.h +++ b/src/serialbus/qmodbustcpclient_p.h @@ -86,8 +86,7 @@ public: cleanupTransactionStore(); }); - QObject::connect(m_socket, - &QAbstractSocket::errorOccurred, q, + QObject::connect(m_socket, &QAbstractSocket::errorOccurred, q, [this](QAbstractSocket::SocketError /*error*/) { Q_Q(QModbusTcpClient); diff --git a/src/tools/canbusutil/canbusutil.cpp b/src/tools/canbusutil/canbusutil.cpp index b07d97c..9b34fac 100644 --- a/src/tools/canbusutil/canbusutil.cpp +++ b/src/tools/canbusutil/canbusutil.cpp @@ -133,7 +133,7 @@ bool CanBusUtil::parseDataField(quint32 &id, QString &payload) return false; } - id = m_data.leftRef(hashMarkPos).toUInt(nullptr, 16); + id = QStringView{m_data}.left(hashMarkPos).toUInt(nullptr, 16); payload = m_data.right(m_data.size() - hashMarkPos - 1); return true; @@ -148,7 +148,7 @@ bool CanBusUtil::setFrameFromPayload(QString payload, QCanBusFrame *frame) return true; bool ok = false; - int rtrFrameLength = payload.midRef(1).toInt(&ok); + int rtrFrameLength = QStringView{payload}.mid(1).toInt(&ok); if (ok && rtrFrameLength >= 0 && rtrFrameLength <= 8) { // payload = "R8" frame->setPayload(QByteArray(rtrFrameLength, 0)); return true; @@ -172,7 +172,7 @@ bool CanBusUtil::setFrameFromPayload(QString payload, QCanBusFrame *frame) if (payload.size() % 2 != 0) { if (frame->hasFlexibleDataRateFormat()) { enum { BitrateSwitchFlag = 1, ErrorStateIndicatorFlag = 2 }; - const int flags = payload.leftRef(1).toInt(nullptr, 16); + const int flags = QStringView{payload}.left(1).toInt(nullptr, 16); frame->setBitrateSwitch(flags & BitrateSwitchFlag); frame->setErrorStateIndicator(flags & ErrorStateIndicatorFlag); payload.remove(0, 1); |