diff --git a/libnymea-modbus/libnymea-modbus.pro b/libnymea-modbus/libnymea-modbus.pro index 61d8b3b..a1b787c 100644 --- a/libnymea-modbus/libnymea-modbus.pro +++ b/libnymea-modbus/libnymea-modbus.pro @@ -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 diff --git a/libnymea-modbus/modbusdatautils.cpp b/libnymea-modbus/modbusdatautils.cpp index ddfbb93..236f1b1 100644 --- a/libnymea-modbus/modbusdatautils.cpp +++ b/libnymea-modbus/modbusdatautils.cpp @@ -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; +} diff --git a/libnymea-modbus/modbusdatautils.h b/libnymea-modbus/modbusdatautils.h index 7bd4e00..616539c 100644 --- a/libnymea-modbus/modbusdatautils.h +++ b/libnymea-modbus/modbusdatautils.h @@ -34,6 +34,7 @@ #include #include #include +#include class ModbusDataUtils { @@ -106,6 +107,7 @@ public: static QVector convertFromFloat64(double value, ByteOrder byteOrder = ByteOrderLittleEndian); static QString exceptionCodeToString(QModbusPdu::ExceptionCode exception); + static QString registerTypeToString(QModbusDataUnit::RegisterType registerType); }; #endif // MODBUSDATAUTILS_H diff --git a/libnymea-modbus/queuedmodbusreply.cpp b/libnymea-modbus/queuedmodbusreply.cpp new file mode 100644 index 0000000..bb3b44e --- /dev/null +++ b/libnymea-modbus/queuedmodbusreply.cpp @@ -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 . +* +* 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(); +} diff --git a/libnymea-modbus/queuedmodbusreply.h b/libnymea-modbus/queuedmodbusreply.h new file mode 100644 index 0000000..aff508a --- /dev/null +++ b/libnymea-modbus/queuedmodbusreply.h @@ -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 . +* +* 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 +#include +#include + +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 diff --git a/libnymea-modbus/tools/connectiontool/modbusrtu.py b/libnymea-modbus/tools/connectiontool/modbusrtu.py index bf5f06c..0ba5fb2 100644 --- a/libnymea-modbus/tools/connectiontool/modbusrtu.py +++ b/libnymea-modbus/tools/connectiontool/modbusrtu.py @@ -99,12 +99,7 @@ def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, regis writeLine(fileDescriptor, ' handleModbusError(reply->error());') writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') writeLine(fileDescriptor, ' QVector 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 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 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) diff --git a/libnymea-modbus/tools/connectiontool/modbustcp.py b/libnymea-modbus/tools/connectiontool/modbustcp.py index 4ea9afe..1245ec5 100644 --- a/libnymea-modbus/tools/connectiontool/modbustcp.py +++ b/libnymea-modbus/tools/connectiontool/modbustcp.py @@ -1,4 +1,4 @@ -# Copyright (C) 2021 - 2023 nymea GmbH +# Copyright (C) 2021 - 2024 nymea GmbH # # 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 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 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 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 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 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 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 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) diff --git a/libnymea-modbus/tools/connectiontool/toolcommon.py b/libnymea-modbus/tools/connectiontool/toolcommon.py index b6a4c16..e6c4f7a 100644 --- a/libnymea-modbus/tools/connectiontool/toolcommon.py +++ b/libnymea-modbus/tools/connectiontool/toolcommon.py @@ -1,4 +1,4 @@ -# Copyright (C) 2021 - 2023 nymea GmbH +# Copyright (C) 2021 - 2024 nymea GmbH # # 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 &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 &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 &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)) diff --git a/libnymea-modbus/tools/generate-connection.py b/libnymea-modbus/tools/generate-connection.py index eba18ae..af9604f 100644 --- a/libnymea-modbus/tools/generate-connection.py +++ b/libnymea-modbus/tools/generate-connection.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright (C) 2021 - 2023 nymea GmbH +# Copyright (C) 2021 - 2024 nymea GmbH # # 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) {')