Implement loading and saving of modbus hardware resources and finish the RTU master implementation

pull/390/head
Simon Stürz 2021-02-05 13:07:48 +01:00
parent 01262b43e9
commit d6e5347666
15 changed files with 431 additions and 138 deletions

View File

@ -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
{

View File

@ -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;

View File

@ -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.")
}

View File

@ -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
}
}

View File

@ -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);
};
}

View File

@ -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
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
};

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -53,7 +53,9 @@ public:
SettingsRoleMqttPolicies,
SettingsRoleIOConnections,
SettingsRoleZigbee,
SettingsRoleModbusRtu
};
Q_ENUM(SettingsRole)
explicit NymeaSettings(const SettingsRole &role = SettingsRoleNone, QObject *parent = nullptr);
~NymeaSettings();