Add timeout and number of retries to the modbus RTU master and propagate the settings to the API

This commit is contained in:
Simon Stürz 2021-04-26 15:57:58 +02:00
parent 16382eb620
commit 11f62d0555
6 changed files with 97 additions and 16 deletions

View File

@ -53,6 +53,9 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject *
modbusRtuMasterDescription.insert("parity", enumRef<SerialPort::SerialPortParity>());
modbusRtuMasterDescription.insert("stopBits", enumRef<SerialPort::SerialPortStopBits>());
modbusRtuMasterDescription.insert("dataBits", enumRef<SerialPort::SerialPortDataBits>());
modbusRtuMasterDescription.insert("numberOfRetries", enumValueName(Uint));
modbusRtuMasterDescription.insert("timeout", enumValueName(Uint));
registerObject("ModbusRtuMaster", modbusRtuMasterDescription);
QVariantMap params, returns;
@ -91,24 +94,26 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject *
// ModbusRtuMasterRemoved notification
params.clear();
description = "Emitted whenever a new modbus RTU master has been removed from the system.";
description = "Emitted whenever a modbus RTU master has been removed from the system.";
params.insert("modbusUuid", enumValueName(Uuid));
registerNotification("ModbusRtuMasterRemoved", description, params);
// ModbusRtuMasterChanged notification
params.clear();
description = "Emitted whenever a new modbus RTU master has been changed to the system.";
description = "Emitted whenever a modbus RTU master has been changed in the system.";
params.insert("modbusRtuMaster", objectRef("ModbusRtuMaster"));
registerNotification("ModbusRtuMasterChanged", description, params);
// AddModbusRtuMaster
params.clear(); returns.clear();
description = "Add a new modbus RTU master with the given configuration.";
description = "Add a new modbus RTU master with the given configuration. The timeout value is in milli seconds and the minimum value is 10 ms.";
params.insert("serialPort", enumValueName(String));
params.insert("baudrate", enumValueName(Uint));
params.insert("parity", enumRef<SerialPort::SerialPortParity>());
params.insert("dataBits", enumRef<SerialPort::SerialPortDataBits>());
params.insert("stopBits", enumRef<SerialPort::SerialPortStopBits>());
params.insert("numberOfRetries", enumValueName(Uint));
params.insert("timeout", enumValueName(Uint));
returns.insert("o:modbusUuid", enumValueName(Uuid));
returns.insert("modbusError", enumRef<ModbusRtuManager::ModbusRtuError>());
registerMethod("AddModbusRtuMaster", description, params, returns);
@ -129,6 +134,8 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject *
params.insert("parity", enumRef<SerialPort::SerialPortParity>());
params.insert("dataBits", enumRef<SerialPort::SerialPortDataBits>());
params.insert("stopBits", enumRef<SerialPort::SerialPortStopBits>());
params.insert("numberOfRetries", enumValueName(Uint));
params.insert("timeout", enumValueName(Uint));
returns.insert("modbusError", enumRef<ModbusRtuManager::ModbusRtuError>());
registerMethod("ReconfigureModbusRtuMaster", description, params, returns);
@ -211,10 +218,16 @@ JsonReply *ModbusRtuHandler::AddModbusRtuMaster(const QVariantMap &params)
QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(enumNameToValue<SerialPort::SerialPortParity>(params.value("parity").toString()));
QSerialPort::StopBits stopBits = static_cast<QSerialPort::StopBits>(enumNameToValue<SerialPort::SerialPortStopBits>(params.value("stopBits").toString()));
QSerialPort::DataBits dataBits = static_cast<QSerialPort::DataBits>(enumNameToValue<SerialPort::SerialPortDataBits>(params.value("dataBits").toString()));
QPair<ModbusRtuManager::ModbusRtuError, QUuid> result = m_modbusRtuManager->addNewModbusRtuMaster(serialPort, baudrate, parity, dataBits, stopBits);
uint numberOfRetries = params.value("numberOfRetries").toUInt();
uint timeout = params.value("timeout").toUInt();
QVariantMap returnMap;
if (timeout < 10) {
returnMap.insert("modbusError", enumValueName<ModbusRtuManager::ModbusRtuError>(ModbusRtuManager::ModbusRtuErrorInvalidTimeoutValue));
return createReply(returnMap);
}
QPair<ModbusRtuManager::ModbusRtuError, QUuid> result = m_modbusRtuManager->addNewModbusRtuMaster(serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout);
returnMap.insert("modbusError", enumValueName<ModbusRtuManager::ModbusRtuError>(result.first));
if (result.first == ModbusRtuManager::ModbusRtuErrorNoError) {
returnMap.insert("modbusUuid", result.second);
@ -240,9 +253,16 @@ JsonReply *ModbusRtuHandler::ReconfigureModbusRtuMaster(const QVariantMap &param
QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(enumNameToValue<SerialPort::SerialPortParity>(params.value("parity").toString()));
QSerialPort::StopBits stopBits = static_cast<QSerialPort::StopBits>(enumNameToValue<SerialPort::SerialPortStopBits>(params.value("stopBits").toString()));
QSerialPort::DataBits dataBits = static_cast<QSerialPort::DataBits>(enumNameToValue<SerialPort::SerialPortDataBits>(params.value("dataBits").toString()));
uint numberOfRetries = params.value("numberOfRetries").toUInt();
uint timeout = params.value("timeout").toUInt();
ModbusRtuManager::ModbusRtuError result = m_modbusRtuManager->reconfigureModbusRtuMaster(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits);
QVariantMap returnMap;
if (timeout < 10) {
returnMap.insert("modbusError", enumValueName<ModbusRtuManager::ModbusRtuError>(ModbusRtuManager::ModbusRtuErrorInvalidTimeoutValue));
return createReply(returnMap);
}
ModbusRtuManager::ModbusRtuError result = m_modbusRtuManager->reconfigureModbusRtuMaster(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout);
returnMap.insert("modbusError", enumValueName<ModbusRtuManager::ModbusRtuError>(result));
return createReply(returnMap);
}
@ -258,6 +278,8 @@ QVariantMap ModbusRtuHandler::packModbusRtuMaster(ModbusRtuMaster *modbusRtuMast
modbusRtuMasterMap.insert("parity", enumValueName<SerialPort::SerialPortParity>(static_cast<SerialPort::SerialPortParity>(modbusRtuMaster->parity())));
modbusRtuMasterMap.insert("stopBits", enumValueName<SerialPort::SerialPortStopBits>(static_cast<SerialPort::SerialPortStopBits>(modbusRtuMaster->stopBits())));
modbusRtuMasterMap.insert("dataBits", enumValueName<SerialPort::SerialPortDataBits>(static_cast<SerialPort::SerialPortDataBits>(modbusRtuMaster->dataBits())));
modbusRtuMasterMap.insert("numberOfRetries", modbusRtuMaster->numberOfRetries());
modbusRtuMasterMap.insert("timeout", modbusRtuMaster->timeout());
return modbusRtuMasterMap;
}

View File

@ -98,7 +98,7 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid)
return nullptr;
}
QPair<ModbusRtuManager::ModbusRtuError, QUuid> ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits)
QPair<ModbusRtuManager::ModbusRtuError, QUuid> ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout)
{
if (!supported()) {
qCWarning(dcModbusRtu()) << "Cannot add new modbus RTU master because serialbus is not suppoerted on this platform.";
@ -112,7 +112,7 @@ QPair<ModbusRtuManager::ModbusRtuError, QUuid> ModbusRtuManager::addNewModbusRt
}
QUuid modbusUuid = QUuid::createUuid();
ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, this);
ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout, this);
ModbusRtuMaster *modbus = qobject_cast<ModbusRtuMaster *>(modbusMaster);
qCDebug(dcModbusRtu()) << "Adding new" << modbus << parity << dataBits << stopBits;
@ -130,7 +130,7 @@ QPair<ModbusRtuManager::ModbusRtuError, QUuid> ModbusRtuManager::addNewModbusRt
return QPair<ModbusRtuError, QUuid>(ModbusRtuErrorNoError, modbusUuid);
}
ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits)
ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout)
{
if (!supported()) {
qCWarning(dcModbusRtu()) << "Cannot reconfigure modbus RTU master because serialbus is not suppoerted on this platform.";
@ -142,6 +142,7 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(co
return ModbusRtuErrorUuidNotFound;
}
// Take the modbus masters
ModbusRtuMasterImpl *modbusMaster = qobject_cast<ModbusRtuMasterImpl *>(m_modbusRtuMasters.value(modbusUuid));
// Disconnect
@ -153,6 +154,8 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(co
modbusMaster->setParity(parity);
modbusMaster->setDataBits(dataBits);
modbusMaster->setStopBits(stopBits);
modbusMaster->setNumberOfRetries(numberOfRetries);
modbusMaster->setTimeout(timeout);
// Connect again
if (!modbusMaster->connectDevice()) {
@ -214,9 +217,11 @@ void ModbusRtuManager::loadRtuMasters()
QSerialPort::Parity parity = static_cast<QSerialPort::Parity>(settings.value("parity").toInt());
QSerialPort::DataBits dataBits = static_cast<QSerialPort::DataBits>(settings.value("dataBits").toInt());
QSerialPort::StopBits stopBits = static_cast<QSerialPort::StopBits>(settings.value("stopBits").toInt());
int numberOfRetries = settings.value("numberOfRetries").toInt();
int timeout = settings.value("timeout").toInt();
settings.endGroup(); // uuid
addModbusRtuMasterInternally(new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, this));
addModbusRtuMasterInternally(new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout, this));
}
settings.endGroup(); // ModbusRtuMasters
@ -233,6 +238,8 @@ void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster)
settings.setValue("parity", static_cast<int>(modbusRtuMaster->parity()));
settings.setValue("dataBits", static_cast<int>(modbusRtuMaster->dataBits()));
settings.setValue("stopBits", static_cast<int>(modbusRtuMaster->stopBits()));
settings.setValue("numberOfRetries", modbusRtuMaster->numberOfRetries());
settings.setValue("timeout", modbusRtuMaster->timeout());
settings.endGroup(); // uuid
settings.endGroup(); // ModbusRtuMasters
}

View File

@ -54,6 +54,7 @@ public:
ModbusRtuErrorHardwareNotFound,
ModbusRtuErrorResourceBusy,
ModbusRtuErrorNotSupported,
ModbusRtuErrorInvalidTimeoutValue,
ModbusRtuErrorConnectionFailed
};
Q_ENUM(ModbusRtuError)
@ -69,8 +70,8 @@ public:
bool hasModbusRtuMaster(const QUuid &modbusUuid) const;
ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid);
QPair<ModbusRtuError, QUuid> addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits);
ModbusRtuError reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits);
QPair<ModbusRtuError, QUuid> addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout);
ModbusRtuError reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout);
ModbusRtuError removeModbusRtuMaster(const QUuid &modbusUuid);
signals:

View File

@ -42,14 +42,16 @@ Q_DECLARE_LOGGING_CATEGORY(dcModbusRtu)
namespace nymeaserver {
ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent) :
ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout, QObject *parent) :
ModbusRtuMaster(parent),
m_modbusUuid(modbusUuid),
m_serialPort(serialPort),
m_baudrate(baudrate),
m_parity(parity),
m_dataBits(dataBits),
m_stopBits(stopBits)
m_stopBits(stopBits),
m_numberOfRetries(numberOfRetries),
m_timeout(timeout)
{
#ifdef WITH_QTSERIALBUS
m_modbus = new QModbusRtuSerialMaster(this);
@ -58,6 +60,8 @@ ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString
m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits);
m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits);
m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity);
m_modbus->setNumberOfRetries(m_numberOfRetries);
m_modbus->setTimeout(m_timeout);
connect(m_modbus, &QModbusTcpClient::stateChanged, this, [=](QModbusDevice::State state){
qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << m_serialPort << state;
@ -171,6 +175,8 @@ bool ModbusRtuMasterImpl::connectDevice()
m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits);
m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits);
m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity);
m_modbus->setNumberOfRetries(m_numberOfRetries);
m_modbus->setTimeout(m_timeout);
return m_modbus->connectDevice();
#else
qCWarning(dcModbusRtu()) << "Modbus is not available on this platform.";
@ -187,6 +193,37 @@ void ModbusRtuMasterImpl::disconnectDevice()
#endif
}
int ModbusRtuMasterImpl::numberOfRetries() const
{
return m_numberOfRetries;
}
void ModbusRtuMasterImpl::setNumberOfRetries(int numberOfRetries)
{
if (m_numberOfRetries == numberOfRetries)
return;
m_numberOfRetries = numberOfRetries;
emit numberOfRetriesChanged(m_numberOfRetries);
m_modbus->setNumberOfRetries(m_numberOfRetries);
}
int ModbusRtuMasterImpl::timeout() const
{
return m_timeout;
}
void ModbusRtuMasterImpl::setTimeout(int timeout)
{
if (m_timeout == timeout)
return;
m_timeout = timeout;
emit timeoutChanged(m_timeout);
m_modbus->setTimeout(m_timeout);
}
ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size)
{
#ifdef WITH_QTSERIALBUS

View File

@ -46,7 +46,7 @@ class ModbusRtuMasterImpl : public ModbusRtuMaster
{
Q_OBJECT
public:
explicit ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent = nullptr);
explicit ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout, QObject *parent = nullptr);
~ModbusRtuMasterImpl() override = default;
QUuid modbusUuid() const override;
@ -71,6 +71,12 @@ public:
bool connectDevice();
void disconnectDevice();
int numberOfRetries() const override;
void setNumberOfRetries(int numberOfRetries);
int timeout() const override;
void setTimeout(int timeout);
// Requests
ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) override;
ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) override;
@ -93,6 +99,8 @@ private:
QSerialPort::Parity m_parity;
QSerialPort::DataBits m_dataBits;
QSerialPort::StopBits m_stopBits;
int m_numberOfRetries = 3;
int m_timeout = 100;
};
}

View File

@ -49,6 +49,8 @@ public:
virtual QSerialPort::Parity parity() const = 0;
virtual QSerialPort::DataBits dataBits() const = 0;
virtual QSerialPort::StopBits stopBits() = 0;
virtual int numberOfRetries() const = 0;
virtual int timeout() const = 0;
virtual bool connected() const = 0;
@ -72,6 +74,8 @@ signals:
void parityChanged(QSerialPort::Parity parity);
void dataBitsChanged(QSerialPort::DataBits dataBits);
void stopBitsChanged(QSerialPort::StopBits stopBits);
void numberOfRetriesChanged(int numberOfRetries);
void timeoutChanged(int timeout);
};
@ -81,7 +85,9 @@ inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) {
debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate();
debug.nospace() << ", " << modbusRtuMaster->dataBits();
debug.nospace() << ", " << modbusRtuMaster->stopBits();
debug.nospace() << ", " << modbusRtuMaster->parity() << ") ";
debug.nospace() << ", " << modbusRtuMaster->parity();
debug.nospace() << ", Retries:" << modbusRtuMaster->numberOfRetries();
debug.nospace() << ", Timeout:" << modbusRtuMaster->numberOfRetries() << "ms)";
return debug.space();
};