modbus-tools: Add support for queued replies

This commit is contained in:
Simon Stürz 2024-03-25 15:12:45 +01:00
parent 25671f284b
commit cc92df2d74
9 changed files with 532 additions and 242 deletions

View File

@ -17,11 +17,13 @@ gcc {
HEADERS += \
modbusdatautils.h \
modbustcpmaster.h
modbustcpmaster.h \
queuedmodbusreply.h
SOURCES += \
modbusdatautils.cpp \
modbustcpmaster.cpp
modbustcpmaster.cpp \
queuedmodbusreply.cpp
# define install target

View File

@ -322,3 +322,27 @@ QString ModbusDataUtils::exceptionCodeToString(QModbusPdu::ExceptionCode excepti
return exceptionString;
}
QString ModbusDataUtils::registerTypeToString(QModbusDataUnit::RegisterType registerType)
{
QString registerTypeString;
switch (registerType) {
case QModbusDataUnit::DiscreteInputs:
registerTypeString = "DiscreteInputs";
break;
case QModbusDataUnit::Coils:
registerTypeString = "Coils";
break;
case QModbusDataUnit::InputRegisters:
registerTypeString = "InputRegisters";
break;
case QModbusDataUnit::HoldingRegisters:
registerTypeString = "HoldingRegisters";
break;
default:
registerTypeString = "Invalid";
break;
}
return registerTypeString;
}

View File

@ -34,6 +34,7 @@
#include <QVector>
#include <QObject>
#include <QModbusPdu>
#include <QModbusDataUnit>
class ModbusDataUtils
{
@ -106,6 +107,7 @@ public:
static QVector<quint16> convertFromFloat64(double value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QString exceptionCodeToString(QModbusPdu::ExceptionCode exception);
static QString registerTypeToString(QModbusDataUnit::RegisterType registerType);
};
#endif // MODBUSDATAUTILS_H

View File

@ -0,0 +1,107 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2024, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "queuedmodbusreply.h"
QueuedModbusReply::QueuedModbusReply(QObject *parent)
: QObject{parent}
{
}
QueuedModbusReply::QueuedModbusReply(RequestType requestType, QModbusDataUnit dataUnit, QObject *parent)
: QObject{parent},
m_requestType{requestType},
m_dataUnit{dataUnit}
{
}
QueuedModbusReply::~QueuedModbusReply()
{
if (m_reply)
m_reply->deleteLater();
}
QueuedModbusReply::RequestType QueuedModbusReply::requestType() const
{
return m_requestType;
}
void QueuedModbusReply::setRequestType(RequestType requestType)
{
Q_ASSERT_X(m_reply == nullptr, "QueuedModbusReply", "Changing the request type after the modbus reply has already been sent has no effect.");
m_requestType = requestType;
}
QModbusDataUnit QueuedModbusReply::dataUnit() const
{
return m_dataUnit;
}
void QueuedModbusReply::setQMOdbusDataUnit(const QModbusDataUnit &dataUnit)
{
Q_ASSERT_X(m_reply == nullptr, "QueuedModbusReply", "Changing the data unit after the modbus reply has already been sent has no effect.");
m_dataUnit = dataUnit;
}
QModbusReply *QueuedModbusReply::reply() const
{
return m_reply;
}
void QueuedModbusReply::setReply(QModbusReply *reply)
{
m_reply = reply;
if (!m_reply)
return;
// Note: do not change the parent of the QModbusReply,
// otherwise the modbus device looses track about it and stops working
connect(m_reply, &QModbusReply::finished, this, &QueuedModbusReply::finished);
connect(m_reply, &QModbusReply::errorOccurred, this, &QueuedModbusReply::errorOccurred);
}
QModbusDevice::Error QueuedModbusReply::error() const
{
if (!m_reply)
return QModbusDevice::UnknownError;
return m_reply->error();
}
QString QueuedModbusReply::errorString() const
{
if (!m_reply)
return QString();
return m_reply->errorString();
}

View File

@ -0,0 +1,77 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2024, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef QUEUEDMODBUSREPLY_H
#define QUEUEDMODBUSREPLY_H
#include <QObject>
#include <QModbusReply>
#include <QModbusDataUnit>
class QueuedModbusReply : public QObject
{
Q_OBJECT
public:
enum RequestType {
RequestTypeRead,
RequestTypeWrite
};
Q_ENUM(RequestType)
explicit QueuedModbusReply(QObject *parent = nullptr);
explicit QueuedModbusReply(RequestType requestType, QModbusDataUnit dataUnit, QObject *parent = nullptr);
~QueuedModbusReply();
RequestType requestType() const;
void setRequestType(RequestType requestType);
QModbusDataUnit dataUnit() const;
void setQMOdbusDataUnit(const QModbusDataUnit &dataUnit);
// Available once the request will be sent to the modbus slave
QModbusReply *reply() const;
void setReply(QModbusReply *reply);
QModbusDevice::Error error() const;
QString errorString() const;
signals:
void finished();
void errorOccurred(QModbusDevice::Error error);
private:
RequestType m_requestType = RequestTypeRead;
QModbusDataUnit m_dataUnit;
QModbusReply *m_reply = nullptr;
};
#endif // QUEUEDMODBUSREPLY_H

View File

@ -99,12 +99,7 @@ def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, regis
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {')
writeLine(fileDescriptor, ' QVector<quint16> values = reply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (values.size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -384,12 +379,7 @@ def writeInitMethodImplementationRtu(fileDescriptor, className, registerDefiniti
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' QVector<quint16> values = reply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" init register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (values.size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' verifyInitFinished();')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -541,12 +531,7 @@ def writeUpdateMethodRtu(fileDescriptor, className, registerDefinitions, blockDe
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' QVector<quint16> values = reply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (values.size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' verifyUpdateFinished();')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)

View File

@ -1,4 +1,4 @@
# Copyright (C) 2021 - 2023 nymea GmbH <developer@nymea.io>
# Copyright (C) 2021 - 2024 nymea GmbH <developer@nymea.io>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -16,6 +16,74 @@
from .toolcommon import *
##############################################################
def writePropertyGetSetDataUnitDeclarationsTcp(fileDescriptor, registerDefinitions):
for registerDefinition in registerDefinitions:
propertyName = registerDefinition['id']
propertyTyp = getCppDataType(registerDefinition)
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
else:
writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
# Check if we require a read method
if 'R' in registerDefinition['access']:
writeLine(fileDescriptor, ' QModbusDataUnit %sDataUnit() const;' % (propertyName))
# Check if we require a write method
if 'W' in registerDefinition['access']:
writeLine(fileDescriptor, ' QModbusDataUnit set%sDataUnit(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
writeLine(fileDescriptor)
def writePropertyGetSetDataUnitImplementationsTcp(fileDescriptor, className, registerDefinitions):
for registerDefinition in registerDefinitions:
propertyName = registerDefinition['id']
propertyTyp = getCppDataType(registerDefinition)
# Check if we require a read method
if 'R' in registerDefinition['access']:
writeLine(fileDescriptor, 'QModbusDataUnit %s::%sDataUnit() const' % (className, propertyName))
writeLine(fileDescriptor, '{')
# Build request depending on the register type
if registerDefinition['registerType'] == 'inputRegister':
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
elif registerDefinition['registerType'] == 'discreteInputs':
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
elif registerDefinition['registerType'] == 'coils':
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
else:
#Default to holdingRegister
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
# Check if we require a write method
if 'W' in registerDefinition['access']:
writeLine(fileDescriptor, 'QModbusDataUnit %s::set%sDataUnit(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
writeLine(fileDescriptor, '{')
writeLine(fileDescriptor, ' QVector<quint16> values = %s;' % getConversionToValueMethod(registerDefinition))
if registerDefinition['registerType'] == 'holdingRegister':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, values.count());' % (registerDefinition['address']))
elif registerDefinition['registerType'] == 'coils':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address']))
else:
logger.warning('Error: invalid register type for writing.')
exit(1)
writeLine(fileDescriptor, ' request.setValues(values);')
writeLine(fileDescriptor, ' return request;')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writePropertyGetSetMethodDeclarationsTcp(fileDescriptor, registerDefinitions):
@ -59,22 +127,138 @@ def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, regis
if 'W' in registerDefinition['access']:
writeLine(fileDescriptor, 'QModbusReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
writeLine(fileDescriptor, '{')
writeLine(fileDescriptor, ' QVector<quint16> values = %s;' % getConversionToValueMethod(registerDefinition))
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
if registerDefinition['registerType'] == 'holdingRegister':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, values.count());' % (registerDefinition['address']))
elif registerDefinition['registerType'] == 'coils':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address']))
else:
logger.warning('Error: invalid register type for writing.')
exit(1)
writeLine(fileDescriptor, ' request.setValues(values);')
writeLine(fileDescriptor, ' return m_modbusTcpMaster->sendWriteRequest(request, m_slaveId);')
writeLine(fileDescriptor, ' return m_modbusTcpMaster->sendWriteRequest(set%sDataUnit(%s), m_slaveId);' % (propertyName[0].upper() + propertyName[1:], propertyName))
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeInternalPropertyReadMethodDeclarationsTcp(fileDescriptor, registerDefinitions):
for registerDefinition in registerDefinitions:
if 'R' in registerDefinition['access']:
propertyName = registerDefinition['id']
writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:]))
##############################################################
def writeInternalPropertyReadMethodImplementationsTcp(fileDescriptor, className, registerDefinitions):
for registerDefinition in registerDefinitions:
if 'R' in registerDefinition['access']:
propertyName = registerDefinition['id']
writeLine(fileDescriptor, 'QModbusReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, '{')
writeLine(fileDescriptor, ' return m_modbusTcpMaster->sendReadRequest(%sDataUnit(), m_slaveId);' % propertyName)
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeInternalBlockReadDataUnitDeclarationsTcp(fileDescriptor, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
registerCount = 0
blockSize = 0
for i, blockRegister in enumerate(blockRegisters):
if i == 0:
blockStartAddress = blockRegister['address']
registerCount += 1
blockSize += blockRegister['size']
writeLine(fileDescriptor, ' /* Data unit describing read block request from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
for i, registerDefinition in enumerate(blockRegisters):
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
else:
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' */' )
writeLine(fileDescriptor, ' QModbusDataUnit readBlock%sDataUnit() const;' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor)
##############################################################
def writeInternalBlockReadDataUnitImplementationsTcp(fileDescriptor, className, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
registerCount = 0
blockSize = 0
registerType = ""
for i, blockRegister in enumerate(blockRegisters):
if i == 0:
blockStartAddress = blockRegister['address']
registerType = blockRegister['registerType']
registerCount += 1
blockSize += blockRegister['size']
writeLine(fileDescriptor, 'QModbusDataUnit %s::readBlock%sDataUnit() const' % (className, blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, '{')
# Build request depending on the register type
if registerType == 'inputRegister':
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (blockStartAddress, blockSize))
elif registerType == 'discreteInputs':
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (blockStartAddress, blockSize))
elif registerType == 'coils':
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (blockStartAddress, blockSize))
else:
#Default to holdingRegister
writeLine(fileDescriptor, ' return QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (blockStartAddress, blockSize))
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
registerCount = 0
blockSize = 0
for i, blockRegister in enumerate(blockRegisters):
if i == 0:
blockStartAddress = blockRegister['address']
registerType = blockRegister['registerType']
registerCount += 1
blockSize += blockRegister['size']
writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
for i, registerDefinition in enumerate(blockRegisters):
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
else:
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' */' )
writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor)
##############################################################
def writeInternalBlockReadMethodImplementationsTcp(fileDescriptor, className, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
writeLine(fileDescriptor, 'QModbusReply *%s::readBlock%s()' % (className, blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, '{')
writeLine(fileDescriptor, ' return m_modbusTcpMaster->sendReadRequest(readBlock%sDataUnit(), m_slaveId);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, registerDefinitions, queuedRequests, queuedRequestsDelay):
@ -131,12 +315,7 @@ def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, regis
writeLine(fileDescriptor, ' const QModbusDataUnit unit = m_currentInitReply->result();')
writeLine(fileDescriptor, ' m_currentInitReply = nullptr;')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (unit.values().size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" init registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' if (!verifyInitFinished())')
writeLine(fileDescriptor, ' QTimer::singleShot(%s, this, &%s::sendNextQueuedInitRequest);' % (queuedRequestsDelay, className))
@ -170,11 +349,7 @@ def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, regis
writeLine(fileDescriptor, ' if (m_currentUpdateReply->error() == QModbusDevice::NoError) {')
writeLine(fileDescriptor, ' const QModbusDataUnit unit = m_currentUpdateReply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (unit.values().size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' m_currentUpdateReply->deleteLater();')
@ -209,12 +384,7 @@ def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, regis
writeLine(fileDescriptor, ' handleModbusError(reply->error());')
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (unit.values().size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -292,19 +462,7 @@ def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDef
writeLine(fileDescriptor, ' m_currentInitReply = nullptr;')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading init block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' if (blockValues.size() == %s) {' % (blockSize))
# Start parsing the registers using offsets
offset = 0
for i, blockRegister in enumerate(blockRegisters):
propertyName = blockRegister['id']
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
offset += blockRegister['size']
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" block registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' processBlock%sRegisterValues(blockValues);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' if (!verifyInitFinished())')
writeLine(fileDescriptor, ' QTimer::singleShot(%s, this, &%s::sendNextQueuedInitRequest);' % (queuedRequestsDelay, className))
@ -335,23 +493,11 @@ def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDef
writeLine(fileDescriptor, ' if (m_currentUpdateReply->error() == QModbusDevice::NoError) {')
writeLine(fileDescriptor, ' const QModbusDataUnit unit = m_currentUpdateReply->result();')
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' if (blockValues.size() == %s) {' % (blockSize))
# Start parsing the registers using offsets
offset = 0
for i, blockRegister in enumerate(blockRegisters):
propertyName = blockRegister['id']
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
offset += blockRegister['size']
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" block registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' m_currentUpdateReply->deleteLater(); // Broadcast reply returns immediatly')
writeLine(fileDescriptor, ' m_currentUpdateReply = nullptr;')
writeLine(fileDescriptor, ' if (!verifyUpdateFinished())')
writeLine(fileDescriptor, ' QTimer::singleShot(%s, this, &%s::sendNextQueuedRequest);' % (queuedRequestsDelay, className))
writeLine(fileDescriptor, ' processBlock%sRegisterValues(blockValues);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, ' m_currentUpdateReply->deleteLater(); // Broadcast reply returns immediatly')
writeLine(fileDescriptor, ' m_currentUpdateReply = nullptr;')
writeLine(fileDescriptor, ' if (!verifyUpdateFinished())')
writeLine(fileDescriptor, ' QTimer::singleShot(%s, this, &%s::sendNextQueuedRequest);' % (queuedRequestsDelay, className))
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
@ -382,19 +528,7 @@ def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDef
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' if (blockValues.size() == %s) {' % (blockSize))
# Start parsing the registers using offsets
offset = 0
for i, blockRegister in enumerate(blockRegisters):
propertyName = blockRegister['id']
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
offset += blockRegister['size']
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" block registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' processBlock%sRegisterValues(blockValues);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -412,105 +546,6 @@ def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDef
##############################################################
def writeInternalPropertyReadMethodDeclarationsTcp(fileDescriptor, registerDefinitions):
for registerDefinition in registerDefinitions:
propertyName = registerDefinition['id']
writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:]))
##############################################################
def writeInternalPropertyReadMethodImplementationsTcp(fileDescriptor, className, registerDefinitions):
for registerDefinition in registerDefinitions:
propertyName = registerDefinition['id']
writeLine(fileDescriptor, 'QModbusReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, '{')
# Build request depending on the register type
if registerDefinition['registerType'] == 'inputRegister':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
elif registerDefinition['registerType'] == 'discreteInputs':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
elif registerDefinition['registerType'] == 'coils':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
else:
#Default to holdingRegister
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' return m_modbusTcpMaster->sendReadRequest(request, m_slaveId);')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
registerCount = 0
blockSize = 0
registerType = ""
for i, blockRegister in enumerate(blockRegisters):
if i == 0:
blockStartAddress = blockRegister['address']
registerType = blockRegister['registerType']
registerCount += 1
blockSize += blockRegister['size']
writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
for i, registerDefinition in enumerate(blockRegisters):
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
else:
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' */' )
writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor)
##############################################################
def writeInternalBlockReadMethodImplementationsTcp(fileDescriptor, className, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
registerCount = 0
blockSize = 0
registerType = ""
for i, blockRegister in enumerate(blockRegisters):
if i == 0:
blockStartAddress = blockRegister['address']
registerType = blockRegister['registerType']
registerCount += 1
blockSize += blockRegister['size']
writeLine(fileDescriptor, 'QModbusReply *%s::readBlock%s()' % (className, blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, '{')
# Build request depending on the register type
if registerType == 'inputRegister':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (blockStartAddress, blockSize))
elif registerType == 'discreteInputs':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (blockStartAddress, blockSize))
elif registerType == 'coils':
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (blockStartAddress, blockSize))
else:
#Default to holdingRegister
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (blockStartAddress, blockSize))
writeLine(fileDescriptor, ' return m_modbusTcpMaster->sendReadRequest(request, m_slaveId);')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeTestReachabilityImplementationsTcp(fileDescriptor, className, registerDefinitions, checkReachableRegister):
propertyName = checkReachableRegister['id']
@ -655,12 +690,7 @@ def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefiniti
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from init \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (unit.values().size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' verifyInitFinished();')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -719,20 +749,7 @@ def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefiniti
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading init block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' if (blockValues.size() == %s) {' % (blockSize))
# Start parsing the registers using offsets
offset = 0
for i, blockRegister in enumerate(blockRegisters):
propertyName = blockRegister['id']
propertyTyp = getCppDataType(blockRegister)
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
offset += blockRegister['size']
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" block registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' processBlock%sRegisterValues(blockValues);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, ' verifyInitFinished();')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -764,7 +781,7 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
# First check if there are any update registers
updateRequired = False
for registerDefinition in registerDefinitions:
if registerDefinition['readSchedule'] == 'update':
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'update':
updateRequired = True
break
@ -845,12 +862,7 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (unit.values().size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' verifyUpdateFinished();')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)
@ -908,21 +920,7 @@ def writeUpdateMethodTcp(fileDescriptor, className, registerDefinitions, blockDe
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' if (blockValues.size() == %s) {' % (blockSize))
# Start parsing the registers using offsets
offset = 0
for i, blockRegister in enumerate(blockRegisters):
propertyName = blockRegister['id']
propertyTyp = getCppDataType(blockRegister)
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
offset += blockRegister['size']
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" block registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' processBlock%sRegisterValues(blockValues);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, ' verifyUpdateFinished();')
writeLine(fileDescriptor, ' });')
writeLine(fileDescriptor)

View File

@ -1,4 +1,4 @@
# Copyright (C) 2021 - 2023 nymea GmbH <developer@nymea.io>
# Copyright (C) 2021 - 2024 nymea GmbH <developer@nymea.io>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -488,6 +488,7 @@ def writeProtectedPropertyMembers(fileDescriptor, registerDefinitions):
else:
writeLine(fileDescriptor, ' %s m_%s;' % (propertyTyp, propertyName))
##############################################################
def writePropertyProcessMethodDeclaration(fileDescriptor, registerDefinitions):
for registerDefinition in registerDefinitions:
@ -512,16 +513,78 @@ def writePropertyProcessMethodImplementations(fileDescriptor, className, registe
writeLine(fileDescriptor, 'void %s::process%sRegisterValues(const QVector<quint16> &values)' % (className, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, '{')
writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition)))
writeLine(fileDescriptor, ' emit %sReadFinished(received%s);' % (propertyName, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' if (values.size() == %s) {' % (registerDefinition['size']))
writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition)))
writeLine(fileDescriptor, ' emit %sReadFinished(received%s);' % (propertyName, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor)
writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName))
writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:]))
writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeBlockPropertiesProcessMethodDeclaration(fileDescriptor, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
blockSize = 0
registerCount = 0
writeLine(fileDescriptor, ' /* Process block data from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
for i, registerDefinition in enumerate(blockRegisters):
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
else:
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
writeLine(fileDescriptor, ' */' )
writeLine(fileDescriptor, ' void processBlock%sRegisterValues(const QVector<quint16> &blockValues);' % (blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor)
def writeBlockPropertiesProcessMethodImplementations(fileDescriptor, className, blockDefinitions):
for blockDefinition in blockDefinitions:
blockName = blockDefinition['id']
blockRegisters = blockDefinition['registers']
blockStartAddress = 0
blockSize = 0
registerCount = 0
for i, blockRegister in enumerate(blockRegisters):
if i == 0:
blockStartAddress = blockRegister['address']
registerCount += 1
blockSize += blockRegister['size']
writeLine(fileDescriptor, 'void %s::processBlock%sRegisterValues(const QVector<quint16> &blockValues)' % (className, blockName[0].upper() + blockName[1:]))
writeLine(fileDescriptor, '{')
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' if (blockValues.size() == %s) {' % (blockSize))
# Start parsing the registers using offsets
offset = 0
for i, blockRegister in enumerate(blockRegisters):
propertyName = blockRegister['id']
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
offset += blockRegister['size']
writeLine(fileDescriptor, ' } else {')
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Reading from \\"%s\\" block registers" << %s << "size:" << %s << "returned different size than requested. Ignoring incomplete data" << blockValues;' % (className, blockName, blockStartAddress, blockSize))
writeLine(fileDescriptor, ' }')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
##############################################################
def writeSendNextQueuedInitRequestMethodImplementation(fileDescriptor, className):
writeLine(fileDescriptor, 'void %s::sendNextQueuedInitRequest()' % (className))

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
# Copyright (C) 2021 - 2023 nymea GmbH <developer@nymea.io>
# Copyright (C) 2021 - 2024 nymea GmbH <developer@nymea.io>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -102,6 +102,17 @@ def writeTcpHeaderFile():
# Write block get/set method declarations
writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks'])
# Write registers get/set data unit declarations
writePropertyGetSetDataUnitDeclarationsTcp(headerFile, registerJson['registers'])
if 'blocks' in registerJson:
for blockDefinition in registerJson['blocks']:
writePropertyGetSetDataUnitDeclarationsTcp(headerFile, blockDefinition['registers'])
if 'blocks' in registerJson:
writeInternalBlockReadDataUnitDeclarationsTcp(headerFile, registerJson['blocks'])
# Update methods
writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers'])
writeLine(headerFile)
if 'blocks' in registerJson:
@ -110,6 +121,11 @@ def writeTcpHeaderFile():
writeLine(headerFile)
if 'blocks' in registerJson:
writePropertyUpdateMethodDeclarations(headerFile, registerJson['blocks'])
writeLine(headerFile)
writeInternalPropertyReadMethodDeclarationsTcp(headerFile, registerJson['registers'])
if 'blocks' in registerJson:
for blockDefinition in registerJson['blocks']:
@ -161,6 +177,8 @@ def writeTcpHeaderFile():
for blockDefinition in registerJson['blocks']:
writePropertyProcessMethodDeclaration(headerFile, blockDefinition['registers'])
writeBlockPropertiesProcessMethodDeclaration(headerFile, registerJson['blocks'])
writeLine(headerFile, ' void handleModbusError(QModbusDevice::Error error);')
writeLine(headerFile, ' void testReachability();')
writeLine(headerFile)
@ -334,6 +352,18 @@ def writeTcpSourceFile():
for blockDefinition in registerJson['blocks']:
writePropertyGetSetMethodImplementationsTcp(sourceFile, className, blockDefinition['registers'])
# Property get/set data unit methods
writePropertyGetSetDataUnitImplementationsTcp(sourceFile, className, registerJson['registers'])
if 'blocks' in registerJson:
for blockDefinition in registerJson['blocks']:
writePropertyGetSetDataUnitImplementationsTcp(sourceFile, className, blockDefinition['registers'])
# Get block data unit method
if 'blocks' in registerJson:
writeInternalBlockReadDataUnitImplementationsTcp(sourceFile, className, registerJson['blocks'])
# Write init and update method implementation
blocks = []
if 'blocks' in registerJson:
@ -383,6 +413,8 @@ def writeTcpSourceFile():
for blockDefinition in registerJson['blocks']:
writePropertyProcessMethodImplementations(sourceFile, className, blockDefinition['registers'])
writeBlockPropertiesProcessMethodImplementations(sourceFile, className, registerJson['blocks'])
writeLine(sourceFile, 'void %s::handleModbusError(QModbusDevice::Error error)' % (className))
writeLine(sourceFile, '{')
writeLine(sourceFile, ' if (error == QModbusDevice::NoError) {')