diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index f6101364..241f2e3c 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -40,13 +40,35 @@ namespace nymeaserver { ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) { + // Load available serial ports + updateSerialPorts(); + // Load uart configurations loadRtuMasters(); - // Connect signals - // Enable autoconnect for each modbus rtu master + m_timer = new QTimer(this); + m_timer->setInterval(5000); + m_timer->setSingleShot(false); + connect(m_timer, &QTimer::timeout, this, [=](){ + // Update serial port list + updateSerialPorts(); + // Check if we have to reconnect a device + foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuMasters.values()) { + ModbusRtuMasterImpl *modbusMasterImpl = qobject_cast(modbusMaster); + + if (!modbusMasterImpl->connected()) { + if (!modbusMasterImpl->connectDevice()) { + qCDebug(dcModbusRtu()) << "Reconnect" << modbusMaster << "failed."; + } else { + qCDebug(dcModbusRtu()) << "Reconnected" << modbusMaster << "sucessfully."; + } + } + } + }); + + m_timer->start(); } QList ModbusRtuManager::modbusRtuMasters() const @@ -68,6 +90,79 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) return nullptr; } +QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +{ + // Check if the serial port exists + + // Check if the serial port is not occupied + + QUuid modbusUuid = QUuid::createUuid(); + ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, this); + ModbusRtuMaster *modbus = qobject_cast(modbusMaster); + qCDebug(dcModbusRtu()) << "Adding new" << qobject_cast(modbusMaster) << parity << dataBits << stopBits; + + // Connect the modbus master bus; + m_modbusRtuMasters.insert(modbusUuid, modbus); + emit modbusRtuMasterAdded(modbus); + saveModbusRtuMaster(modbus); + + return QPair(ErrorNoError, modbusUuid); +} + +ModbusRtuManager::Error ModbusRtuManager::reconfigureRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +{ + if (!m_modbusRtuMasters.contains(modbusUuid)) { + qCWarning(dcModbusRtu()) << "Could not reconfigure modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); + return ErrorNotFound; + } + + ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); + + // Disconnect + modbusMaster->disconnectDevice(); + + // Reconfigure + modbusMaster->setSerialPort(serialPort); + modbusMaster->setBaudrate(baudrate); + modbusMaster->setParity(parity); + modbusMaster->setDataBits(dataBits); + modbusMaster->setStopBits(stopBits); + + // Connect again + if (!modbusMaster->connectDevice()) { + qCWarning(dcModbusRtu()) << "Failed to connect to" << m_modbusRtuMasters.value(modbusUuid); + return ErrorConnectionFailed; + } + + emit modbusRtuMasterChanged(m_modbusRtuMasters.value(modbusUuid)); + + qCDebug(dcModbusRtu()) << "Reconfigured successfully" << m_modbusRtuMasters.value(modbusUuid); + return ErrorNoError; +} + + +ModbusRtuManager::Error ModbusRtuManager::removeModbusRtuMaster(const QUuid &modbusUuid) +{ + ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); + if (!modbusMaster) { + qCWarning(dcModbusRtu()) << "Could not remove modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); + return ErrorNotFound; + } + + qCDebug(dcModbusRtu()) << "Removing modbus RTU master" << qobject_cast(modbusMaster); + emit modbusRtuMasterRemoved(modbusMaster); + + modbusMaster->deleteLater(); + return ErrorNoError; +} + +void ModbusRtuManager::updateSerialPorts() +{ + // Check if serial port added or removed + +} + + void ModbusRtuManager::loadRtuMasters() { NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); @@ -87,7 +182,7 @@ void ModbusRtuManager::loadRtuMasters() ModbusRtuMaster *modbusRtuMaster = qobject_cast(modbus); qCDebug(dcModbusRtu()) << "Loaded" << modbusRtuMaster; m_modbusRtuMasters.insert(modbusRtuMaster->modbusUuid(), modbusRtuMaster); - emit modbusRtuMasterAdded(modbusRtuMaster->modbusUuid()); + emit modbusRtuMasterAdded(modbusRtuMaster); } settings.endGroup(); // ModbusRtuMasters diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index 0ee8ca82..fc01aa32 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "hardware/modbus/modbusrtumaster.h" @@ -43,6 +44,13 @@ class ModbusRtuManager : public QObject { Q_OBJECT public: + enum Error { + ErrorNoError, + ErrorNotFound, + ErrorConnectionFailed + }; + Q_ENUM(Error) + explicit ModbusRtuManager(QObject *parent = nullptr); ~ModbusRtuManager() = default; @@ -50,10 +58,14 @@ public: bool hasModbusRtuMaster(const QUuid &modbusUuid) const; ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); + QPair addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + Error reconfigureRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + Error removeModbusRtuMaster(const QUuid &modbusUuid); + signals: - void modbusRtuMasterAdded(const QUuid &modbusUuid); - void modbusRtuMasterRemoved(const QUuid &modbusUuid); - void modbusRtuMasterChanged(const QUuid &modbusUuid); + void modbusRtuMasterAdded(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterRemoved(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterChanged(ModbusRtuMaster *modbusRtuMaster); private: QHash m_modbusRtuMasters; diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index 14be6556..de13800b 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -85,31 +85,91 @@ QString ModbusRtuMasterImpl::serialPort() const return m_serialPort; } +void ModbusRtuMasterImpl::setSerialPort(const QString &serialPort) +{ + if (m_serialPort == serialPort) + return; + + m_serialPort = serialPort; + emit serialPortChanged(m_serialPort); +} + qint32 ModbusRtuMasterImpl::baudrate() const { return m_baudrate; } +void ModbusRtuMasterImpl::setBaudrate(qint32 baudrate) +{ + if (m_baudrate == baudrate) + return; + + m_baudrate = baudrate; + emit baudrateChanged(m_baudrate); +} + QSerialPort::Parity ModbusRtuMasterImpl::parity() const { return m_parity; } +void ModbusRtuMasterImpl::setParity(QSerialPort::Parity parity) +{ + if (m_parity == parity) + return; + + m_parity = parity; + emit parityChanged(m_parity); +} + QSerialPort::DataBits ModbusRtuMasterImpl::dataBits() const { return m_dataBits; } +void ModbusRtuMasterImpl::setDataBits(QSerialPort::DataBits dataBits) +{ + if (m_dataBits == dataBits) + return; + + m_dataBits = dataBits; + emit dataBitsChanged(m_dataBits); +} + QSerialPort::StopBits ModbusRtuMasterImpl::stopBits() { return m_stopBits; } +void ModbusRtuMasterImpl::setStopBits(QSerialPort::StopBits stopBits) +{ + if (m_stopBits == stopBits) + return; + + m_stopBits = stopBits; + emit stopBitsChanged(m_stopBits); +} + bool ModbusRtuMasterImpl::connected() const { return m_connected; } +bool ModbusRtuMasterImpl::connectDevice() +{ + m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, m_serialPort); + m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, m_baudrate); + m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity); + return m_modbus->connectDevice(); +} + +void ModbusRtuMasterImpl::disconnectDevice() +{ + m_modbus->disconnectDevice(); +} + ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size) { #ifdef WITH_QTSERIALBUS diff --git a/libnymea-core/modbus/modbusrtumasterimpl.h b/libnymea-core/modbus/modbusrtumasterimpl.h index 15a99f52..d9eadd8c 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.h +++ b/libnymea-core/modbus/modbusrtumasterimpl.h @@ -50,14 +50,27 @@ public: ~ModbusRtuMasterImpl() override = default; QUuid modbusUuid() const override; + QString serialPort() const override; + void setSerialPort(const QString &serialPort); + qint32 baudrate() const override; + void setBaudrate(qint32 baudrate); + QSerialPort::Parity parity() const override; + void setParity(QSerialPort::Parity parity); + QSerialPort::DataBits dataBits() const override; + void setDataBits(QSerialPort::DataBits dataBits); + QSerialPort::StopBits stopBits() override; + void setStopBits(QSerialPort::StopBits stopBits); bool connected() const override; + bool connectDevice(); + void disconnectDevice(); + // Requests ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) override; ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) override; diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index a8caf09c..4d6740a5 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -67,6 +67,11 @@ protected: signals: void connectedChanged(bool connected); + void serialPortChanged(const QString &serialPort); + void baudrateChanged(quint32 baudrate); + void parityChanged(QSerialPort::Parity parity); + void dataBitsChanged(QSerialPort::DataBits dataBits); + void stopBitsChanged(QSerialPort::StopBits stopBits); };