mirror of https://github.com/nymea/nymea.git
Implement loading and saving of modbus hardware resources and finish the RTU master implementation
parent
01262b43e9
commit
d6e5347666
|
|
@ -44,10 +44,20 @@ ModbusRtuHardwareResourceImplementation::ModbusRtuHardwareResourceImplementation
|
|||
|
||||
}
|
||||
|
||||
//QList<ModbusRtuMaster *> ModbusRtuHardwareResourceImplementation::modbusRtuMasters() const
|
||||
//{
|
||||
// return m_modbusRtuManager->modbusRtuMasters();
|
||||
//}
|
||||
QList<ModbusRtuMaster *> ModbusRtuHardwareResourceImplementation::modbusRtuMasters() const
|
||||
{
|
||||
return m_modbusRtuManager->modbusRtuMasters();
|
||||
}
|
||||
|
||||
bool ModbusRtuHardwareResourceImplementation::hasModbusRtuMaster(const QUuid &modbusUuid)
|
||||
{
|
||||
return m_modbusRtuManager->hasModbusRtuMaster(modbusUuid);
|
||||
}
|
||||
|
||||
ModbusRtuMaster *ModbusRtuHardwareResourceImplementation::getModbusRtuMaster(const QUuid &modbusUuid)
|
||||
{
|
||||
return m_modbusRtuManager->getModbusRtuMaster(modbusUuid);
|
||||
}
|
||||
|
||||
bool ModbusRtuHardwareResourceImplementation::available() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ class ModbusRtuHardwareResourceImplementation : public ModbusRtuHardwareResource
|
|||
public:
|
||||
explicit ModbusRtuHardwareResourceImplementation(ModbusRtuManager *modbusRtuManager, QObject *parent = nullptr);
|
||||
|
||||
//QList<ModbusRtuMaster *> modbusRtuMasters() const override;
|
||||
QList<ModbusRtuMaster *> modbusRtuMasters() const override;
|
||||
bool hasModbusRtuMaster(const QUuid &modbusUuid) override;
|
||||
ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) override;
|
||||
|
||||
bool available() const override;
|
||||
bool enabled() const override;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ TARGET = nymea-core
|
|||
|
||||
include(../nymea.pri)
|
||||
|
||||
QT += bluetooth dbus qml sql websockets
|
||||
QT += bluetooth dbus qml sql websockets serialport
|
||||
INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir
|
||||
LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto
|
||||
|
||||
|
|
@ -40,9 +40,9 @@ CONFIG(withoutpython) {
|
|||
# Let's check if the package exists, not the qt version
|
||||
packagesExist(Qt5SerialBus) {
|
||||
DEFINES += WITH_QTSERIALBUS
|
||||
Qt += serialbus serialport
|
||||
Qt += serialbus
|
||||
} else {
|
||||
message("Qt5SerialBus not available")
|
||||
message("Qt5SerialBus library is not available. Modbus resource disabled.")
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "modbusrtumanager.h"
|
||||
#include "nymeasettings.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "modbusrtumasterimpl.h"
|
||||
|
||||
NYMEA_LOGGING_CATEGORY(dcModbusRtu, "ModbusRtu")
|
||||
|
||||
|
|
@ -63,10 +64,46 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid)
|
|||
void ModbusRtuManager::init()
|
||||
{
|
||||
// Load uart configurations
|
||||
NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu);
|
||||
qCDebug(dcModbusRtu()) << "Loading modbus RTU resources from" << settings.fileName();
|
||||
|
||||
// Init modbus rtu masters
|
||||
settings.beginGroup("ModbusRtuMasters");
|
||||
foreach (const QString &uuidString, settings.childGroups()) {
|
||||
settings.beginGroup(uuidString);
|
||||
QString serialPort = settings.value("serialPort").toString();
|
||||
quint32 baudrate = settings.value("baudrate").toUInt();
|
||||
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());
|
||||
settings.endGroup(); // uuid
|
||||
|
||||
ModbusRtuMasterImpl *modbus = new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, this);
|
||||
ModbusRtuMaster *modbusRtuMaster = qobject_cast<ModbusRtuMaster *>(modbus);
|
||||
qCDebug(dcModbusRtu()) << "Loaded" << modbusRtuMaster;
|
||||
m_modbusRtuMasters.insert(modbusRtuMaster->modbusUuid(), modbusRtuMaster);
|
||||
emit modbusRtuMasterAdded(modbusRtuMaster->modbusUuid());
|
||||
}
|
||||
|
||||
settings.endGroup(); // ModbusRtuMasters
|
||||
|
||||
// Connect signals
|
||||
|
||||
// Enable autoconnect for each modbus rtu master
|
||||
|
||||
}
|
||||
|
||||
void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster)
|
||||
{
|
||||
NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu);
|
||||
settings.beginGroup("ModbusRtuMasters");
|
||||
settings.beginGroup(modbusRtuMaster->modbusUuid().toString());
|
||||
settings.setValue("serialPort", modbusRtuMaster->serialPort());
|
||||
settings.setValue("baudrate", modbusRtuMaster->baudrate());
|
||||
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.endGroup(); // uuid
|
||||
settings.endGroup(); // ModbusRtuMasters
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@
|
|||
#ifndef MODBUSRTUMANAGER_H
|
||||
#define MODBUSRTUMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QUuid>
|
||||
#include <QObject>
|
||||
|
||||
#include "hardware/modbus/modbusrtumaster.h"
|
||||
|
||||
|
|
@ -52,13 +53,15 @@ public:
|
|||
void init();
|
||||
|
||||
signals:
|
||||
void modbusRtuMasterAdded(ModbusRtuMaster *modbusRtuMaster);
|
||||
void modbusRtuMasterRemoved(ModbusRtuMaster *modbusRtuMaster);
|
||||
void modbusRtuMasterChanged(ModbusRtuMaster *modbusRtuMaster);
|
||||
void modbusRtuMasterAdded(const QUuid &modbusUuid);
|
||||
void modbusRtuMasterRemoved(const QUuid &modbusUuid);
|
||||
void modbusRtuMasterChanged(const QUuid &modbusUuid);
|
||||
|
||||
private:
|
||||
QHash<QUuid, ModbusRtuMaster *> m_modbusRtuMasters;
|
||||
|
||||
void saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,25 +42,36 @@ namespace nymeaserver {
|
|||
|
||||
ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent) :
|
||||
ModbusRtuMaster(parent),
|
||||
m_modbusUuid(modbusUuid)
|
||||
m_modbusUuid(modbusUuid),
|
||||
m_serialPort(serialPort),
|
||||
m_baudrate(baudrate),
|
||||
m_parity(parity),
|
||||
m_dataBits(dataBits),
|
||||
m_stopBits(stopBits)
|
||||
{
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
m_modbus = new QModbusRtuSerialMaster(this);
|
||||
m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, serialPort);
|
||||
m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudrate);
|
||||
m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits);
|
||||
m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits);
|
||||
m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, parity);
|
||||
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);
|
||||
|
||||
connect(m_modbus, &QModbusTcpClient::stateChanged, this, [=](QModbusDevice::State state){
|
||||
qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << serialPort << state;
|
||||
qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << m_serialPort << state;
|
||||
if (state == QModbusDevice::ConnectedState) {
|
||||
m_connected = true;
|
||||
emit connectedChanged(m_connected);
|
||||
} else {
|
||||
m_connected = false;
|
||||
emit connectedChanged(m_connected);
|
||||
}
|
||||
});
|
||||
//connect(m_modbus, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusRtuMaster::onModbusErrorOccurred);
|
||||
|
||||
// m_reconnectTimer = new QTimer(this);
|
||||
// m_reconnectTimer->setSingleShot(true);
|
||||
// connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer);
|
||||
|
||||
connect(m_modbus, &QModbusRtuSerialMaster::errorOccurred, this, [=](QModbusDevice::Error error){
|
||||
qCDebug(dcModbusRtu()) << "Error occured for modbus RTU master" << m_modbusUuid.toString() << m_serialPort << error << m_modbus->errorString();
|
||||
// TODO: check if disconnected...
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -74,143 +85,344 @@ QString ModbusRtuMasterImpl::serialPort() const
|
|||
return m_serialPort;
|
||||
}
|
||||
|
||||
qint32 ModbusRtuMasterImpl::baudrate() const
|
||||
{
|
||||
return m_baudrate;
|
||||
}
|
||||
|
||||
QSerialPort::Parity ModbusRtuMasterImpl::parity() const
|
||||
{
|
||||
return m_parity;
|
||||
}
|
||||
|
||||
QSerialPort::DataBits ModbusRtuMasterImpl::dataBits() const
|
||||
{
|
||||
return m_dataBits;
|
||||
}
|
||||
|
||||
QSerialPort::StopBits ModbusRtuMasterImpl::stopBits()
|
||||
{
|
||||
return m_stopBits;
|
||||
}
|
||||
|
||||
bool ModbusRtuMasterImpl::connected() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readCoil(uint slaveAddress, uint registerAddress, uint size)
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
return nullptr;
|
||||
#else
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
// Create the reply for the plugin
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater);
|
||||
|
||||
// Create the actual modbus lib reply
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, size);
|
||||
QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress);
|
||||
|
||||
// TODO: fill data and return reply
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){
|
||||
modbusReply->deleteLater();
|
||||
|
||||
// Fill common reply data
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
|
||||
// Check if the reply finished with an error
|
||||
if (modbusReply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString();
|
||||
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the data unit and set reply result
|
||||
const QModbusDataUnit unit = modbusReply->result();
|
||||
reply->setResult(unit.values());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){
|
||||
qCWarning(dcModbusRtu()) << "Read coil request finished with error" << error << modbusReply->errorString();
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
return qobject_cast<ModbusRtuReply *>(reply);
|
||||
#endif
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readDiscreteInput(uint slaveAddress, uint registerAddress, uint size)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
return nullptr;
|
||||
#else
|
||||
// TODO:
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readInputRegister(uint slaveAddress, uint registerAddress, uint size)
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readDiscreteInput(int slaveAddress, int registerAddress, quint16 size)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
return nullptr;
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
// Create the reply for the plugin
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater);
|
||||
|
||||
// Create the actual modbus lib reply
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, registerAddress, size);
|
||||
QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress);
|
||||
|
||||
connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){
|
||||
modbusReply->deleteLater();
|
||||
|
||||
// Fill common reply data
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
|
||||
// Check if the reply finished with an error
|
||||
if (modbusReply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcModbusRtu()) << "Read descrete inputs request finished with error" << modbusReply->error() << modbusReply->errorString();
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the data unit and set reply result
|
||||
const QModbusDataUnit unit = modbusReply->result();
|
||||
reply->setResult(unit.values());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){
|
||||
qCWarning(dcModbusRtu()) << "Read descrete inputs request finished with error" << error << modbusReply->errorString();
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
return qobject_cast<ModbusRtuReply *>(reply);
|
||||
#else
|
||||
// TODO:
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readHoldingRegister(uint slaveAddress, uint registerAddress, uint size)
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readInputRegister(int slaveAddress, int registerAddress, quint16 size)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
return nullptr;
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
// Create the reply for the plugin
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater);
|
||||
|
||||
// Create the actual modbus lib reply
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, registerAddress, size);
|
||||
QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress);
|
||||
|
||||
connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){
|
||||
modbusReply->deleteLater();
|
||||
|
||||
// Fill common reply data
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
|
||||
// Check if the reply finished with an error
|
||||
if (modbusReply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcModbusRtu()) << "Read input registers request finished with error" << modbusReply->error() << modbusReply->errorString();
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the data unit and set reply result
|
||||
const QModbusDataUnit unit = modbusReply->result();
|
||||
reply->setResult(unit.values());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){
|
||||
qCWarning(dcModbusRtu()) << "Read input registers request finished with error" << error << modbusReply->errorString();
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
return qobject_cast<ModbusRtuReply *>(reply);
|
||||
#else
|
||||
// TODO:
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::writeCoil(uint slaveAddress, uint registerAddress, bool status)
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::readHoldingRegister(int slaveAddress, int registerAddress, quint16 size)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(size)
|
||||
return nullptr;
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
// Create the reply for the plugin
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater);
|
||||
|
||||
// Create the actual modbus lib reply
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, size);
|
||||
QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress);
|
||||
|
||||
connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){
|
||||
modbusReply->deleteLater();
|
||||
|
||||
// Fill common reply data
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
|
||||
// Check if the reply finished with an error
|
||||
if (modbusReply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcModbusRtu()) << "Read holding registers request finished with error" << modbusReply->error() << modbusReply->errorString();
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the data unit and set reply result
|
||||
const QModbusDataUnit unit = modbusReply->result();
|
||||
reply->setResult(unit.values());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){
|
||||
qCWarning(dcModbusRtu()) << "Read holding registers request finished with error" << error << modbusReply->errorString();
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
return qobject_cast<ModbusRtuReply *>(reply);
|
||||
#else
|
||||
// TODO:
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(status)
|
||||
Q_UNUSED(size)
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::writeCoils(uint slaveAddress, uint registerAddress, const QVector<quint16> &values)
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::writeCoils(int slaveAddress, int registerAddress, const QVector<quint16> &values)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(values)
|
||||
return nullptr;
|
||||
#else
|
||||
// TODO:
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
// Create the reply for the plugin
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater);
|
||||
|
||||
// Create the actual modbus lib reply
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, values.length());
|
||||
request.setValues(values);
|
||||
|
||||
QModbusReply *modbusReply = m_modbus->sendWriteRequest(request, slaveAddress);
|
||||
|
||||
connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){
|
||||
modbusReply->deleteLater();
|
||||
|
||||
// Fill common reply data
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
|
||||
// Check if the reply finished with an error
|
||||
if (modbusReply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString();
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the data unit and set reply result
|
||||
const QModbusDataUnit unit = modbusReply->result();
|
||||
reply->setResult(unit.values());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){
|
||||
qCWarning(dcModbusRtu()) << "Read coil request finished with error" << error << modbusReply->errorString();
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
return qobject_cast<ModbusRtuReply *>(reply);
|
||||
#else
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(values)
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value)
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegisters(int slaveAddress, int registerAddress, const QVector<quint16> &values)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(value)
|
||||
return nullptr;
|
||||
#else
|
||||
// TODO:
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(value)
|
||||
return nullptr;
|
||||
#endif
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
// Create the reply for the plugin
|
||||
ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this);
|
||||
connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater);
|
||||
|
||||
// Create the actual modbus lib reply
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, values.length());
|
||||
request.setValues(values);
|
||||
|
||||
QModbusReply *modbusReply = m_modbus->sendWriteRequest(request, slaveAddress);
|
||||
|
||||
connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){
|
||||
modbusReply->deleteLater();
|
||||
|
||||
// Fill common reply data
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
|
||||
// Check if the reply finished with an error
|
||||
if (modbusReply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString();
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values)
|
||||
{
|
||||
#ifndef WITH_QTSERIALBUS
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(values)
|
||||
return nullptr;
|
||||
// Parse the data unit and set reply result
|
||||
const QModbusDataUnit unit = modbusReply->result();
|
||||
reply->setResult(unit.values());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){
|
||||
qCWarning(dcModbusRtu()) << "Read coil request finished with error" << error << modbusReply->errorString();
|
||||
reply->setFinished(true);
|
||||
reply->setError(static_cast<ModbusRtuReply::Error>(modbusReply->error()));
|
||||
reply->setErrorString(modbusReply->errorString());
|
||||
emit reply->errorOccurred(reply->error());
|
||||
emit reply->finished();
|
||||
});
|
||||
|
||||
return qobject_cast<ModbusRtuReply *>(reply);
|
||||
#else
|
||||
// TODO:
|
||||
Q_UNUSED(slaveAddress)
|
||||
Q_UNUSED(registerAddress)
|
||||
Q_UNUSED(values)
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@
|
|||
#define MODBUSRTUMASTERIMPL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSerialPort>
|
||||
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
#include <QtSerialBus/QtSerialBus>
|
||||
#include <QtSerialPort/QSerialPort>
|
||||
#endif
|
||||
|
||||
#include "hardware/modbus/modbusrtumaster.h"
|
||||
|
|
@ -50,32 +50,36 @@ public:
|
|||
~ModbusRtuMasterImpl() override = default;
|
||||
|
||||
QUuid modbusUuid() const override;
|
||||
|
||||
QString serialPort() const override;
|
||||
qint32 baudrate() const override;
|
||||
QSerialPort::Parity parity() const override;
|
||||
QSerialPort::DataBits dataBits() const override;
|
||||
QSerialPort::StopBits stopBits() override;
|
||||
|
||||
bool connected() const override;
|
||||
|
||||
// Requests
|
||||
ModbusRtuReply *readCoil(uint slaveAddress, uint registerAddress, uint size = 1) override;
|
||||
ModbusRtuReply *readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1) override;
|
||||
ModbusRtuReply *readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1) override;
|
||||
ModbusRtuReply *readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1) override;
|
||||
ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) override;
|
||||
ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) override;
|
||||
ModbusRtuReply *readInputRegister(int slaveAddress, int registerAddress, quint16 size = 1) override;
|
||||
ModbusRtuReply *readHoldingRegister(int slaveAddress, int registerAddress, quint16 size = 1) override;
|
||||
|
||||
ModbusRtuReply *writeCoil(uint slaveAddress, uint registerAddress, bool status) override;
|
||||
ModbusRtuReply *writeCoils(uint slaveAddress, uint registerAddress, const QVector<quint16> &values) override;
|
||||
|
||||
ModbusRtuReply *writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) override;
|
||||
ModbusRtuReply *writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values) override;
|
||||
ModbusRtuReply *writeCoils(int slaveAddress, int registerAddress, const QVector<quint16> &values) override;
|
||||
ModbusRtuReply *writeHoldingRegisters(int slaveAddress, int registerAddress, const QVector<quint16> &values) override;
|
||||
|
||||
private:
|
||||
QUuid m_modbusUuid;
|
||||
bool m_connected = false;
|
||||
|
||||
#ifdef WITH_QTSERIALBUS
|
||||
QModbusRtuSerialMaster *m_modbus = nullptr;
|
||||
#endif
|
||||
|
||||
QString m_serialPort;
|
||||
bool m_connected = false;
|
||||
qint32 m_baudrate;
|
||||
QSerialPort::Parity m_parity;
|
||||
QSerialPort::DataBits m_dataBits;
|
||||
QSerialPort::StopBits m_stopBits;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
namespace nymeaserver {
|
||||
|
||||
ModbusRtuReplyImpl::ModbusRtuReplyImpl(uint slaveAddress, uint registerAddress, QObject *parent) :
|
||||
ModbusRtuReplyImpl::ModbusRtuReplyImpl(int slaveAddress, int registerAddress, QObject *parent) :
|
||||
ModbusRtuReply(parent),
|
||||
m_slaveAddress(slaveAddress),
|
||||
m_registerAddress(registerAddress)
|
||||
|
|
@ -51,12 +51,12 @@ void ModbusRtuReplyImpl::setFinished(bool finished)
|
|||
m_finished = finished;
|
||||
}
|
||||
|
||||
uint ModbusRtuReplyImpl::slaveAddress() const
|
||||
int ModbusRtuReplyImpl::slaveAddress() const
|
||||
{
|
||||
return m_slaveAddress;
|
||||
}
|
||||
|
||||
uint ModbusRtuReplyImpl::registerAddress() const
|
||||
int ModbusRtuReplyImpl::registerAddress() const
|
||||
{
|
||||
return m_registerAddress;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ class ModbusRtuReplyImpl : public ModbusRtuReply
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ModbusRtuReplyImpl(uint slaveAddress, uint registerAddress, QObject *parent = nullptr);
|
||||
explicit ModbusRtuReplyImpl(int slaveAddress, int registerAddress, QObject *parent = nullptr);
|
||||
|
||||
bool isFinished() const override;
|
||||
void setFinished(bool finished);
|
||||
|
||||
uint slaveAddress() const override;
|
||||
uint registerAddress() const override;
|
||||
int slaveAddress() const override;
|
||||
int registerAddress() const override;
|
||||
|
||||
QString errorString() const override;
|
||||
void setErrorString(const QString &errorString);
|
||||
|
|
@ -60,8 +60,8 @@ public:
|
|||
|
||||
private:
|
||||
bool m_finished = false;
|
||||
uint m_slaveAddress;
|
||||
uint m_registerAddress;
|
||||
int m_slaveAddress;
|
||||
int m_registerAddress;
|
||||
Error m_error = UnknownError;
|
||||
QString m_errorString;
|
||||
QVector<quint16> m_result;
|
||||
|
|
|
|||
|
|
@ -41,13 +41,18 @@ class ModbusRtuHardwareResource : public HardwareResource
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ModbusRtuHardwareResource(QObject *parent = nullptr);
|
||||
virtual ~ModbusRtuHardwareResource() = default;
|
||||
//virtual QList<ModbusRtuMaster *> modbusRtuMasters() const = 0;
|
||||
virtual QList<ModbusRtuMaster *> modbusRtuMasters() const = 0;
|
||||
virtual bool hasModbusRtuMaster(const QUuid &modbusUuid) = 0;
|
||||
virtual ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) = 0;
|
||||
|
||||
protected:
|
||||
explicit ModbusRtuHardwareResource(QObject *parent = nullptr);
|
||||
virtual ~ModbusRtuHardwareResource() = default;
|
||||
|
||||
signals:
|
||||
void modbusRtuMasterAdded(const QUuid &modbusUuid);
|
||||
void modbusRtuMasterRemoved(const QUuid &modbusUuid);
|
||||
void modbusRtuMasterChanged(const QUuid &modbusUuid);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@
|
|||
#ifndef MODBUSRTUMASTER_H
|
||||
#define MODBUSRTUMASTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUuid>
|
||||
#include <QObject>
|
||||
#include <QSerialPort>
|
||||
#include <QDebug>
|
||||
|
||||
#include "modbusrtureply.h"
|
||||
|
||||
|
|
@ -43,20 +45,21 @@ public:
|
|||
// Properties
|
||||
virtual QUuid modbusUuid() const = 0;
|
||||
virtual QString serialPort() const = 0;
|
||||
virtual qint32 baudrate() const = 0;
|
||||
virtual QSerialPort::Parity parity() const = 0;
|
||||
virtual QSerialPort::DataBits dataBits() const = 0;
|
||||
virtual QSerialPort::StopBits stopBits() = 0;
|
||||
|
||||
virtual bool connected() const = 0;
|
||||
|
||||
// Requests
|
||||
virtual ModbusRtuReply *readCoil(uint slaveAddress, uint registerAddress, uint size = 1) = 0;
|
||||
virtual ModbusRtuReply *readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1) = 0;
|
||||
virtual ModbusRtuReply *readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1) = 0;
|
||||
virtual ModbusRtuReply *readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1) = 0;
|
||||
virtual ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) = 0;
|
||||
virtual ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) = 0;
|
||||
virtual ModbusRtuReply *readInputRegister(int slaveAddress, int registerAddress, quint16 size = 1) = 0;
|
||||
virtual ModbusRtuReply *readHoldingRegister(int slaveAddress, int registerAddress, quint16 size = 1) = 0;
|
||||
|
||||
virtual ModbusRtuReply *writeCoil(uint slaveAddress, uint registerAddress, bool status) = 0;
|
||||
virtual ModbusRtuReply *writeCoils(uint slaveAddress, uint registerAddress, const QVector<quint16> &values) = 0;
|
||||
|
||||
virtual ModbusRtuReply *writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) = 0;
|
||||
virtual ModbusRtuReply *writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values) = 0;
|
||||
virtual ModbusRtuReply *writeCoils(int slaveAddress, int registerAddress, const QVector<quint16> &values) = 0;
|
||||
virtual ModbusRtuReply *writeHoldingRegisters(int slaveAddress, int registerAddress, const QVector<quint16> &values) = 0;
|
||||
|
||||
protected:
|
||||
explicit ModbusRtuMaster(QObject *parent = nullptr) : QObject(parent) { };
|
||||
|
|
@ -67,4 +70,12 @@ signals:
|
|||
|
||||
};
|
||||
|
||||
inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) {
|
||||
debug.nospace() << "ModbusRtuMaster(" << modbusRtuMaster->modbusUuid().toString();
|
||||
debug.nospace() << ", " << modbusRtuMaster->serialPort();
|
||||
debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate() << ") ";
|
||||
return debug;
|
||||
};
|
||||
|
||||
|
||||
#endif // MODBUSRTUMASTER_H
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ public:
|
|||
|
||||
virtual bool isFinished() const = 0;
|
||||
|
||||
virtual uint slaveAddress() const = 0;
|
||||
virtual uint registerAddress() const = 0;
|
||||
virtual int slaveAddress() const = 0;
|
||||
virtual int registerAddress() const = 0;
|
||||
|
||||
virtual QString errorString() const = 0;
|
||||
virtual ModbusRtuReply::Error error() const = 0;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ include(../nymea.pri)
|
|||
TARGET = nymea
|
||||
TEMPLATE = lib
|
||||
|
||||
QT += network bluetooth dbus
|
||||
QT += network bluetooth dbus serialport
|
||||
QT -= gui
|
||||
DEFINES += LIBNYMEA_LIBRARY
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@
|
|||
This role will create the \b{mqttpolicies.conf} file and is used to store the \l{MqttPolicy}{MqttPolicies}.
|
||||
\value SettingsRoleIOConnections
|
||||
This role will create the \b{ioconnections.conf} file and is used to store the \l{IOConnection}{IOConnections}.
|
||||
\value SettingsRoleZigbee
|
||||
This role will create the \b{zigbee.conf} file and is used to store the Zigbee networks.
|
||||
\value SettingsRoleModbusRtu
|
||||
This role will create the \b{modbusrtu.conf} file and is used to store the modbus RTU resources.
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -83,7 +87,7 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent):
|
|||
QString settingsPrefix = QCoreApplication::instance()->organizationName() + "/";
|
||||
|
||||
QString basePath;
|
||||
if (!qgetenv("SNAP").isEmpty()) {
|
||||
if (!qEnvironmentVariableIsEmpty("SNAP")) {
|
||||
basePath = QString(qgetenv("SNAP_DATA")) + "/";
|
||||
settingsPrefix.clear(); // We don't want that in the snappy case...
|
||||
} else if (settingsPrefix == "nymea-test/") {
|
||||
|
|
@ -125,6 +129,9 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent):
|
|||
case SettingsRoleZigbee:
|
||||
fileName = "zigbee.conf";
|
||||
break;
|
||||
case SettingsRoleModbusRtu:
|
||||
fileName = "modbusrtu.conf";
|
||||
break;
|
||||
}
|
||||
m_settings = new QSettings(basePath + settingsPrefix + fileName, QSettings::IniFormat, this);
|
||||
}
|
||||
|
|
@ -157,7 +164,7 @@ QString NymeaSettings::settingsPath()
|
|||
QString path;
|
||||
QString organisationName = QCoreApplication::instance()->organizationName();
|
||||
|
||||
if (!qgetenv("SNAP").isEmpty()) {
|
||||
if (!qEnvironmentVariableIsEmpty("SNAP")) {
|
||||
path = QString(qgetenv("SNAP_DATA"));
|
||||
} else if (organisationName == "nymea-test") {
|
||||
path = "/tmp/" + organisationName;
|
||||
|
|
@ -174,7 +181,7 @@ QString NymeaSettings::translationsPath()
|
|||
{
|
||||
QString organisationName = QCoreApplication::instance()->organizationName();
|
||||
|
||||
if (!qgetenv("SNAP").isEmpty()) {
|
||||
if (!qEnvironmentVariableIsEmpty("SNAP")) {
|
||||
return QString(qgetenv("SNAP") + "/usr/share/nymea/translations");
|
||||
} else if (organisationName == "nymea-test") {
|
||||
return "/tmp/" + organisationName;
|
||||
|
|
@ -188,7 +195,7 @@ QString NymeaSettings::storagePath()
|
|||
{
|
||||
QString path;
|
||||
QString organisationName = QCoreApplication::instance()->organizationName();
|
||||
if (!qgetenv("SNAP").isEmpty()) {
|
||||
if (!qEnvironmentVariableIsEmpty("SNAP")) {
|
||||
path = QString(qgetenv("SNAP_DATA"));
|
||||
} else if (organisationName == "nymea-test") {
|
||||
path = "/tmp/" + organisationName;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ public:
|
|||
SettingsRoleMqttPolicies,
|
||||
SettingsRoleIOConnections,
|
||||
SettingsRoleZigbee,
|
||||
SettingsRoleModbusRtu
|
||||
};
|
||||
Q_ENUM(SettingsRole)
|
||||
|
||||
explicit NymeaSettings(const SettingsRole &role = SettingsRoleNone, QObject *parent = nullptr);
|
||||
~NymeaSettings();
|
||||
|
|
|
|||
Loading…
Reference in New Issue