Introduce libnymea-modbus
Improve tool and prepare autogeneration of connection classes
This commit is contained in:
parent
03c77ef3a3
commit
62f78f5e90
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
builddir
|
builddir
|
||||||
doc/html
|
doc/html
|
||||||
*.qm
|
*.qm
|
||||||
|
__pycache__
|
||||||
|
|||||||
30
debian/control
vendored
30
debian/control
vendored
@ -2,6 +2,7 @@ Source: nymea-plugins-modbus
|
|||||||
Section: utils
|
Section: utils
|
||||||
Priority: options
|
Priority: options
|
||||||
Maintainer: nymea GmbH <developer@nymea.io>
|
Maintainer: nymea GmbH <developer@nymea.io>
|
||||||
|
Standards-Version: 3.9.3
|
||||||
Build-depends: debhelper (>= 9.0.0),
|
Build-depends: debhelper (>= 9.0.0),
|
||||||
libnymea-dev (>= 0.17),
|
libnymea-dev (>= 0.17),
|
||||||
libnymea-gpio-dev,
|
libnymea-gpio-dev,
|
||||||
@ -10,8 +11,8 @@ Build-depends: debhelper (>= 9.0.0),
|
|||||||
nymea-dev-tools:native,
|
nymea-dev-tools:native,
|
||||||
pkg-config,
|
pkg-config,
|
||||||
qtbase5-dev,
|
qtbase5-dev,
|
||||||
libi2c-dev
|
libi2c-dev,
|
||||||
Standards-Version: 3.9.3
|
python3:native
|
||||||
|
|
||||||
|
|
||||||
Package: libnymea-sunspec1
|
Package: libnymea-sunspec1
|
||||||
@ -22,6 +23,7 @@ Depends: ${shlibs:Depends},
|
|||||||
Description: nymea.io sunspec library
|
Description: nymea.io sunspec library
|
||||||
This package contains the nymea sunspec library.
|
This package contains the nymea sunspec library.
|
||||||
|
|
||||||
|
|
||||||
Package: libnymea-sunspec-dev
|
Package: libnymea-sunspec-dev
|
||||||
Section: libdevel
|
Section: libdevel
|
||||||
Architecture: any
|
Architecture: any
|
||||||
@ -34,6 +36,30 @@ Depends: ${shlibs:Depends},
|
|||||||
Description: The main libraries and header files for developing with nymea sunspec.
|
Description: The main libraries and header files for developing with nymea sunspec.
|
||||||
This package contains the nymea sunspec library - development files.
|
This package contains the nymea sunspec library - development files.
|
||||||
|
|
||||||
|
|
||||||
|
Package: libnymea-modbus
|
||||||
|
Architecture: any
|
||||||
|
Section: libs
|
||||||
|
Depends: ${shlibs:Depends},
|
||||||
|
${misc:Depends}
|
||||||
|
Description: nymea modbus integration plugins library
|
||||||
|
This package contains the nymea modbus library for integration plugins.
|
||||||
|
|
||||||
|
|
||||||
|
Package: libnymea-modbus-dev
|
||||||
|
Section: libdevel
|
||||||
|
Architecture: any
|
||||||
|
Multi-Arch: same
|
||||||
|
Depends: ${shlibs:Depends},
|
||||||
|
${misc:Depends},
|
||||||
|
libnymea-modbus (= ${binary:Version}),
|
||||||
|
pkg-config,
|
||||||
|
qtbase5-dev,
|
||||||
|
python3,
|
||||||
|
Description: The main libraries and header files for developing with modbus based nymea integration plugins.
|
||||||
|
This package contains the nymea modbus integration plugin library - development files.
|
||||||
|
|
||||||
|
|
||||||
Package: nymea-plugin-alphainnotec
|
Package: nymea-plugin-alphainnotec
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Section: libs
|
Section: libs
|
||||||
|
|||||||
4
debian/libnymea-modbus-dev.install.in
vendored
Normal file
4
debian/libnymea-modbus-dev.install.in
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so
|
||||||
|
usr/include/nymea-modbus/
|
||||||
|
usr/lib/@DEB_HOST_MULTIARCH@/pkgconfig/nymea-modbus.pc
|
||||||
|
|
||||||
4
debian/libnymea-modbus.install.in
vendored
Normal file
4
debian/libnymea-modbus.install.in
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1
|
||||||
|
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1.0
|
||||||
|
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1.0.0
|
||||||
|
|
||||||
1
debian/rules
vendored
1
debian/rules
vendored
@ -21,5 +21,6 @@ override_dh_auto_clean:
|
|||||||
dh_auto_clean
|
dh_auto_clean
|
||||||
find -name *plugininfo.h -exec rm {} \;
|
find -name *plugininfo.h -exec rm {} \;
|
||||||
find -name *.qm -exec rm {} \;
|
find -name *.qm -exec rm {} \;
|
||||||
|
find -name "autogenerated" -type d -exec rm -rvf {} +
|
||||||
rm -rf $(PREPROCESS_FILES:.in=)
|
rm -rf $(PREPROCESS_FILES:.in=)
|
||||||
|
|
||||||
|
|||||||
57
libnymea-modbus/libnymea-modbus.pro
Normal file
57
libnymea-modbus/libnymea-modbus.pro
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
QMAKE_CXXFLAGS += -Werror -std=c++11 -z defs
|
||||||
|
QMAKE_LFLAGS += -std=c++11 -z defs
|
||||||
|
|
||||||
|
QT += network serialbus
|
||||||
|
|
||||||
|
CONFIG += link_pkgconfig
|
||||||
|
PKGCONFIG += nymea
|
||||||
|
|
||||||
|
TARGET = nymea-modbus
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
gcc {
|
||||||
|
COMPILER_VERSION = $$system($$QMAKE_CXX " -dumpversion")
|
||||||
|
COMPILER_MAJOR_VERSION = $$str_member($$COMPILER_VERSION)
|
||||||
|
greaterThan(COMPILER_MAJOR_VERSION, 7): QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||||
|
}
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
modbusdatautils.h \
|
||||||
|
modbustcpmaster.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
modbusdatautils.cpp \
|
||||||
|
modbustcpmaster.cpp
|
||||||
|
|
||||||
|
|
||||||
|
# define install target
|
||||||
|
target.path = $$[QT_INSTALL_LIBS]
|
||||||
|
INSTALLS += target
|
||||||
|
|
||||||
|
# install modbustool for external plugins
|
||||||
|
modbustoolpri.files = modbus-tool.pri
|
||||||
|
modbustoolpri.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/
|
||||||
|
modbustool.files = tools/generate-connection.py
|
||||||
|
modbustool.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/tools/
|
||||||
|
modbustoolmodules.files = tools/connectiontool/*.py
|
||||||
|
modbustoolmodules.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/tools/connectiontool/
|
||||||
|
INSTALLS += modbustoolpri modbustool modbustoolmodules
|
||||||
|
|
||||||
|
# install header file with relative subdirectory
|
||||||
|
for (header, HEADERS) {
|
||||||
|
path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/$${dirname(header)}
|
||||||
|
eval(headers_$${path}.files += $${header})
|
||||||
|
eval(headers_$${path}.path = $${path})
|
||||||
|
eval(INSTALLS *= headers_$${path})
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create pkgconfig file
|
||||||
|
CONFIG += create_pc create_prl no_install_prl
|
||||||
|
QMAKE_PKGCONFIG_NAME = libnymea-modbus
|
||||||
|
QMAKE_PKGCONFIG_DESCRIPTION = nymea modbus integrations development library
|
||||||
|
QMAKE_PKGCONFIG_PREFIX = $$[QT_INSTALL_PREFIX]
|
||||||
|
QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/
|
||||||
|
QMAKE_PKGCONFIG_LIBDIR = $$target.path
|
||||||
|
QMAKE_PKGCONFIG_VERSION = 1.0.0
|
||||||
|
QMAKE_PKGCONFIG_FILE = nymea-modbus
|
||||||
|
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
|
||||||
56
libnymea-modbus/modbus-tool.pri
Normal file
56
libnymea-modbus/modbus-tool.pri
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# Copyright 2013 - 2021, 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
|
||||||
|
|
||||||
|
# This project include file is meant to be used by nymea modbus integration plugins.
|
||||||
|
# For external plugins you can generate connection by including this project like following:
|
||||||
|
|
||||||
|
# # Generate modbus connection
|
||||||
|
# MODBUS_CONNECTIONS += modbus-registers.json
|
||||||
|
# MODBUS_TOOLS_CONFIG += VERBOSE
|
||||||
|
# include($$[QT_INSTALL_PREFIX]/include/nymea-modbus/modbus-tool.pri)
|
||||||
|
|
||||||
|
# On each qmake run the classes will be generated in the build directory.
|
||||||
|
|
||||||
|
GENERATE_MODBUS_CONNECTION_BINARY=$${PWD}/tools/generate-connection.py
|
||||||
|
|
||||||
|
for(registerDefinition, MODBUS_CONNECTIONS) {
|
||||||
|
contains(MODBUS_TOOLS_CONFIG, VERBOSE) {
|
||||||
|
message("Generating modbus connection class for $${registerDefinition} (verbose)")
|
||||||
|
system(python3 $${GENERATE_MODBUS_CONNECTION_BINARY} -j $${_PRO_FILE_PWD_}/$${registerDefinition} -o $${OUT_PWD}/autogenerated -v)
|
||||||
|
} else {
|
||||||
|
message("Generating class for $${registerDefinition}")
|
||||||
|
system(python3 $${GENERATE_MODBUS_CONNECTION_BINARY} -j $${_PRO_FILE_PWD_}/$${registerDefinition} -o $${OUT_PWD}/autogenerated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add all generated pri files to the project
|
||||||
|
MODBUS_CONNECTIONS_INCLUDES = $$files($${OUT_PWD}/autogenerated/*.pri)
|
||||||
|
for(MODBUS_CONNECTION, MODBUS_CONNECTIONS_INCLUDES) {
|
||||||
|
message("Adding generated connection to project $${MODBUS_CONNECTION}")
|
||||||
|
include($${MODBUS_CONNECTION})
|
||||||
|
INCLUDEPATH += $${OUT_PWD}/autogenerated
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2021, nymea GmbH
|
* Copyright 2013 - 2022, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -30,8 +30,7 @@
|
|||||||
|
|
||||||
#include "modbustcpmaster.h"
|
#include "modbustcpmaster.h"
|
||||||
|
|
||||||
#include <loggingcategories.h>
|
Q_LOGGING_CATEGORY(dcModbusTcpMaster, "ModbusTcpMaster")
|
||||||
NYMEA_LOGGING_CATEGORY(dcModbusTCP, "ModbusTCP")
|
|
||||||
|
|
||||||
ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent) :
|
ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
@ -91,7 +90,7 @@ bool ModbusTCPMaster::connectDevice() {
|
|||||||
|
|
||||||
// Only connect if we are in the unconnected state
|
// Only connect if we are in the unconnected state
|
||||||
if (m_modbusTcpClient->state() == QModbusDevice::UnconnectedState) {
|
if (m_modbusTcpClient->state() == QModbusDevice::UnconnectedState) {
|
||||||
qCDebug(dcModbusTCP()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
qCDebug(dcModbusTcpMaster()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||||
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port);
|
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port);
|
||||||
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString());
|
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString());
|
||||||
m_modbusTcpClient->setTimeout(m_timeout);
|
m_modbusTcpClient->setTimeout(m_timeout);
|
||||||
@ -101,7 +100,7 @@ bool ModbusTCPMaster::connectDevice() {
|
|||||||
// Restart the timer in case of connecting not finished yet or closing
|
// Restart the timer in case of connecting not finished yet or closing
|
||||||
m_reconnectTimer->start();
|
m_reconnectTimer->start();
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state();
|
qCWarning(dcModbusTcpMaster()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -119,7 +118,7 @@ void ModbusTCPMaster::disconnectDevice()
|
|||||||
|
|
||||||
bool ModbusTCPMaster::reconnectDevice()
|
bool ModbusTCPMaster::reconnectDevice()
|
||||||
{
|
{
|
||||||
qCWarning(dcModbusTCP()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
qCWarning(dcModbusTcpMaster()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||||
if (!m_modbusTcpClient)
|
if (!m_modbusTcpClient)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -184,12 +183,12 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si
|
|||||||
emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values());
|
emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values());
|
||||||
} else {
|
} else {
|
||||||
emit readRequestExecuted(requestId, false);
|
emit readRequestExecuted(requestId, false);
|
||||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||||
emit readRequestError(requestId, reply->errorString());
|
emit readRequestError(requestId, reply->errorString());
|
||||||
emit reply->finished(); // To make sure it will be deleted
|
emit reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
@ -200,7 +199,7 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si
|
|||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
@ -226,13 +225,13 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd
|
|||||||
emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values());
|
emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values());
|
||||||
} else {
|
} else {
|
||||||
emit writeRequestExecuted(requestId, false);
|
emit writeRequestExecuted(requestId, false);
|
||||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||||
qCWarning(dcModbusTCP()) << "Modbus replay error:" << error;
|
qCWarning(dcModbusTcpMaster()) << "Modbus replay error:" << error;
|
||||||
emit writeRequestError(requestId, reply->errorString());
|
emit writeRequestError(requestId, reply->errorString());
|
||||||
emit reply->finished(); // To make sure it will be deleted
|
emit reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
@ -243,7 +242,7 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd
|
|||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
@ -289,12 +288,12 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress
|
|||||||
emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.values());
|
emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.values());
|
||||||
} else {
|
} else {
|
||||||
emit readRequestExecuted(requestId, false);
|
emit readRequestExecuted(requestId, false);
|
||||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){
|
connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){
|
||||||
qCWarning(dcModbusTCP()) << "Modbus replay error:" << error;
|
qCWarning(dcModbusTcpMaster()) << "Modbus replay error:" << error;
|
||||||
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
|
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
|
||||||
emit readRequestError(requestId, reply->errorString());
|
emit readRequestError(requestId, reply->errorString());
|
||||||
emit reply->finished(); // To make sure it will be deleted
|
emit reply->finished(); // To make sure it will be deleted
|
||||||
@ -306,7 +305,7 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress
|
|||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
@ -333,12 +332,12 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress
|
|||||||
emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.values());
|
emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.values());
|
||||||
} else {
|
} else {
|
||||||
emit readRequestExecuted(requestId, false);
|
emit readRequestExecuted(requestId, false);
|
||||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||||
emit readRequestError(requestId, reply->errorString());
|
emit readRequestError(requestId, reply->errorString());
|
||||||
emit reply->finished(); // To make sure it will be deleted
|
emit reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
@ -350,7 +349,7 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress
|
|||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
@ -378,7 +377,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
emit writeRequestExecuted(requestId, false);
|
emit writeRequestExecuted(requestId, false);
|
||||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||||
emit readRequestError(requestId, reply->errorString());
|
emit readRequestError(requestId, reply->errorString());
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
@ -386,7 +385,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
|
|||||||
|
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||||
|
|
||||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||||
emit readRequestError(requestId, reply->errorString());
|
emit readRequestError(requestId, reply->errorString());
|
||||||
emit reply->finished(); // To make sure it will be deleted
|
emit reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
@ -397,7 +396,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
|
|||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
@ -431,13 +430,13 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
emit writeRequestExecuted(requestId, false);
|
emit writeRequestExecuted(requestId, false);
|
||||||
qCWarning(dcModbusTCP()) << "Write response error:" << reply->error();
|
qCWarning(dcModbusTcpMaster()) << "Write response error:" << reply->error();
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||||
emit writeRequestError(requestId, reply->errorString());
|
emit writeRequestError(requestId, reply->errorString());
|
||||||
emit reply->finished(); // To make sure it will be deleted
|
emit reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
@ -448,7 +447,7 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const
|
|||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||||
return QUuid();
|
return QUuid();
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
@ -461,12 +460,12 @@ QUuid ModbusTCPMaster::writeHoldingRegister(uint slaveAddress, uint registerAddr
|
|||||||
|
|
||||||
void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error)
|
void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error)
|
||||||
{
|
{
|
||||||
qCWarning(dcModbusTCP()) << "An error occured" << error;
|
qCWarning(dcModbusTcpMaster()) << "An error occured" << error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state)
|
void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state)
|
||||||
{
|
{
|
||||||
qCDebug(dcModbusTCP()) << "Connection state changed for" << m_hostAddress << state;
|
qCDebug(dcModbusTcpMaster()) << "Connection state changed for" << m_hostAddress << state;
|
||||||
bool connected = (state == QModbusDevice::ConnectedState);
|
bool connected = (state == QModbusDevice::ConnectedState);
|
||||||
if (m_connected != connected) {
|
if (m_connected != connected) {
|
||||||
m_connected = connected;
|
m_connected = connected;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2021, nymea GmbH
|
* Copyright 2013 - 2022, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -31,11 +31,14 @@
|
|||||||
#ifndef MODBUSTCPMASTER_H
|
#ifndef MODBUSTCPMASTER_H
|
||||||
#define MODBUSTCPMASTER_H
|
#define MODBUSTCPMASTER_H
|
||||||
|
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QTimer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QtSerialBus>
|
#include <QtSerialBus>
|
||||||
#include <QTimer>
|
#include <QLoggingCategory>
|
||||||
#include <QUuid>
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcModbusTcpMaster)
|
||||||
|
|
||||||
class ModbusTCPMaster : public QObject
|
class ModbusTCPMaster : public QObject
|
||||||
{
|
{
|
||||||
@ -112,6 +115,7 @@ signals:
|
|||||||
void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
||||||
void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
||||||
void receivedInputRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
void receivedInputRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MODBUSTCPMASTER_H
|
#endif // MODBUSTCPMASTER_H
|
||||||
@ -14,7 +14,7 @@ The class will provide 2 main methods for fetching information from the modbus d
|
|||||||
* `initialize()` will read all registers with `"readSchedule": "init"` and emits the signal `initializationFinished()` once all replies returned.
|
* `initialize()` will read all registers with `"readSchedule": "init"` and emits the signal `initializationFinished()` once all replies returned.
|
||||||
* `update()` can be used to update all registers with `"readSchedule": "update"`. The class will then fetch each register and update the specified value internally. If the value has changed, the `<propertyName>Changed()` signal will be emitted.
|
* `update()` can be used to update all registers with `"readSchedule": "update"`. The class will then fetch each register and update the specified value internally. If the value has changed, the `<propertyName>Changed()` signal will be emitted.
|
||||||
|
|
||||||
The reulting class will inhert from the `ModbusTCPMaster` class, providing easy access to all possible modbus operations and inform about the connected state.
|
The resulting class will inhert from the `ModbusTCPMaster` class, providing easy access to all possible modbus operations and inform about the connected state.
|
||||||
|
|
||||||
|
|
||||||
# JSON format
|
# JSON format
|
||||||
@ -23,7 +23,8 @@ The basic structure of the modbus register JSON looks like following example:
|
|||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"protocol": "TCP",
|
"className": "MyConnection",
|
||||||
|
"protocols": [ "TCP" ],
|
||||||
"endianness": "BigEndian",
|
"endianness": "BigEndian",
|
||||||
"enums": [
|
"enums": [
|
||||||
{
|
{
|
||||||
@ -65,11 +66,65 @@ The basic structure of the modbus register JSON looks like following example:
|
|||||||
"access": "RO"
|
"access": "RO"
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
|
],
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"id": "blockName",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"registers": [
|
||||||
|
{
|
||||||
|
"id": "registerOne",
|
||||||
|
"address": 0,
|
||||||
|
"size": 2,
|
||||||
|
...
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "registerOne",
|
||||||
|
"address": 0,
|
||||||
|
"size": 2,
|
||||||
|
...
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Class name
|
||||||
|
|
||||||
|
If no name class name has been passed to the generator script, the classname defined in the JSON file will be used.
|
||||||
|
|
||||||
|
The naming convention for the classname and the resulting source code files looks like this:
|
||||||
|
|
||||||
|
The class will be defined as
|
||||||
|
|
||||||
|
* `<ClassName><Protocol>Connection`.
|
||||||
|
|
||||||
|
The source code files will be calld:
|
||||||
|
|
||||||
|
* `classnameprotocolconnection.h`
|
||||||
|
* `classnameprotocolconnection.cpp`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Protocol
|
||||||
|
|
||||||
|
Depending on the communication protocol, a different base class will be used for the resulting output class.
|
||||||
|
|
||||||
|
There are 2 protocol types:
|
||||||
|
|
||||||
|
* `RTU`: a communication based on the RS485 serial RTU transport protocol
|
||||||
|
* `TCP`: a communication based on the TCP transport protocol
|
||||||
|
|
||||||
|
If the modbus device supports both protocols and you want to generate a class for each protocol you can set the protocol to `BOTH` and a class for `RTU` and one for `TCP` will be generated.
|
||||||
|
|
||||||
|
...
|
||||||
|
"protocol": "TCP",
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
## Endianness
|
## Endianness
|
||||||
|
|
||||||
When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endianness of the data receiving.
|
When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endianness of the data receiving.
|
||||||
@ -79,15 +134,6 @@ There are 2 possibilities:
|
|||||||
* `BigEndian`: default if not specified: register bytes come in following order `[0, 1, 2, 3]`: `ABCD`
|
* `BigEndian`: default if not specified: register bytes come in following order `[0, 1, 2, 3]`: `ABCD`
|
||||||
* `LittleEndian`: register bytes come in following order `[0, 1, 2, 3]`: `CDAB`
|
* `LittleEndian`: register bytes come in following order `[0, 1, 2, 3]`: `CDAB`
|
||||||
|
|
||||||
## Protocol
|
|
||||||
|
|
||||||
Depending on the communication protocol, a different base class will be used for the resulting output class.
|
|
||||||
|
|
||||||
There are 2 possibilities:
|
|
||||||
|
|
||||||
* `RTU`: a communication based on the RS485 serial RTU transport protocol
|
|
||||||
* `TCP`: a communication based on the TCP transport protocol
|
|
||||||
|
|
||||||
## Enums
|
## Enums
|
||||||
|
|
||||||
Many modbus devices provide inforation using `Enums`, indicating a special state trough a defined list of values. If a register implements an enum, you can define it in the `enums` section. The `name` property defines the name of the enum, and the script will generate a c++ enum definition from this section. Each enum value will then be generated using `<EnumName><EnumValueName> = <value>`.
|
Many modbus devices provide inforation using `Enums`, indicating a special state trough a defined list of values. If a register implements an enum, you can define it in the `enums` section. The `name` property defines the name of the enum, and the script will generate a c++ enum definition from this section. Each enum value will then be generated using `<EnumName><EnumValueName> = <value>`.
|
||||||
@ -179,12 +225,12 @@ Example block:
|
|||||||
Change into your plugin sub directory.
|
Change into your plugin sub directory.
|
||||||
Assuming you wrote the registers.json file you can run now following command to generate your modbus class:
|
Assuming you wrote the registers.json file you can run now following command to generate your modbus class:
|
||||||
|
|
||||||
`$ python3 ../modbus/tools/generate-connection.py -j registers.json -o . -c MyModbusConnection`
|
`$ python3 ../modbus/tools/generate-connection.py -j registers.json -o . -c MyModbus`
|
||||||
|
|
||||||
You the result will be a header and a source file called:
|
You the result will be a header and a source file called:
|
||||||
|
|
||||||
* `mymodbusconnection.h`
|
* `mymodbustcpconnection.h`
|
||||||
* `mymodbusconnection.cpp`
|
* `mymodbustcpconnection.cpp`
|
||||||
|
|
||||||
You can include this class in your project and provide one connection per thing.
|
You can include this class in your project and provide one connection per thing.
|
||||||
|
|
||||||
@ -14,6 +14,8 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from .toolcommon import *
|
from .toolcommon import *
|
||||||
|
|
||||||
##############################################################
|
##############################################################
|
||||||
@ -63,7 +65,7 @@ def writePropertyGetSetMethodImplementationsRtu(fileDescriptor, className, regis
|
|||||||
elif registerDefinition['registerType'] == 'coils':
|
elif registerDefinition['registerType'] == 'coils':
|
||||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address']))
|
writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address']))
|
||||||
else:
|
else:
|
||||||
print('Error: invalid register type for writing.')
|
logger.warning('Error: invalid register type for writing.')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
writeLine(fileDescriptor, '}')
|
writeLine(fileDescriptor, '}')
|
||||||
@ -222,7 +224,7 @@ def writeInternalBlockReadMethodDeclarationsRtu(fileDescriptor, blockDefinitions
|
|||||||
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||||
else:
|
else:
|
||||||
writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||||
writeLine(fileDescriptor, ' */ ' )
|
writeLine(fileDescriptor, ' */' )
|
||||||
writeLine(fileDescriptor, ' ModbusRtuReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
writeLine(fileDescriptor, ' ModbusRtuReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||||
writeLine(fileDescriptor)
|
writeLine(fileDescriptor)
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, regis
|
|||||||
elif registerDefinition['registerType'] == 'coils':
|
elif registerDefinition['registerType'] == 'coils':
|
||||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address']))
|
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address']))
|
||||||
else:
|
else:
|
||||||
print('Error: invalid register type for writing.')
|
logger.warning('Error: invalid register type for writing.')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
writeLine(fileDescriptor, ' request.setValues(values);')
|
writeLine(fileDescriptor, ' request.setValues(values);')
|
||||||
@ -218,7 +218,7 @@ def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions
|
|||||||
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||||
else:
|
else:
|
||||||
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||||
writeLine(fileDescriptor, ' */ ' )
|
writeLine(fileDescriptor, ' */' )
|
||||||
writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||||
writeLine(fileDescriptor)
|
writeLine(fileDescriptor)
|
||||||
|
|
||||||
@ -19,8 +19,10 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import argparse
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger('modbus-tools')
|
||||||
|
|
||||||
def convertToAlphaNumeric(text):
|
def convertToAlphaNumeric(text):
|
||||||
finalText = ''
|
finalText = ''
|
||||||
@ -40,7 +42,7 @@ def convertToCamelCase(text, capitalize = False):
|
|||||||
s = convertToAlphaNumeric(text)
|
s = convertToAlphaNumeric(text)
|
||||||
s = s.replace("-", " ").replace("_", " ")
|
s = s.replace("-", " ").replace("_", " ")
|
||||||
words = s.split()
|
words = s.split()
|
||||||
#print('--> words', words)
|
logger.debug('--> words', words)
|
||||||
finalWords = []
|
finalWords = []
|
||||||
|
|
||||||
for i in range(len(words)):
|
for i in range(len(words)):
|
||||||
@ -48,7 +50,7 @@ def convertToCamelCase(text, capitalize = False):
|
|||||||
if len(camelCaseSplit) == 0:
|
if len(camelCaseSplit) == 0:
|
||||||
finalWords.append(words[i])
|
finalWords.append(words[i])
|
||||||
else:
|
else:
|
||||||
#print('--> camel split words', camelCaseSplit)
|
logging.debug('Camel calse split words', camelCaseSplit)
|
||||||
for j in range(len(camelCaseSplit)):
|
for j in range(len(camelCaseSplit)):
|
||||||
finalWords.append(camelCaseSplit[j])
|
finalWords.append(camelCaseSplit[j])
|
||||||
|
|
||||||
@ -60,12 +62,12 @@ def convertToCamelCase(text, capitalize = False):
|
|||||||
finalText = finalWords[0].capitalize() + ''.join(i.capitalize() for i in finalWords[1:])
|
finalText = finalWords[0].capitalize() + ''.join(i.capitalize() for i in finalWords[1:])
|
||||||
else:
|
else:
|
||||||
finalText = finalWords[0].lower() + ''.join(i.capitalize() for i in finalWords[1:])
|
finalText = finalWords[0].lower() + ''.join(i.capitalize() for i in finalWords[1:])
|
||||||
#print('Convert camel case:', text, '-->', finalText)
|
logging.debug('Convert camel case:', text, '-->', finalText)
|
||||||
return finalText
|
return finalText
|
||||||
|
|
||||||
|
|
||||||
def loadJsonFile(filePath):
|
def loadJsonFile(filePath):
|
||||||
print('--> Loading JSON file', filePath)
|
logger.info('Loading JSON file %s', filePath)
|
||||||
jsonFile = open(filePath, 'r')
|
jsonFile = open(filePath, 'r')
|
||||||
return json.load(jsonFile)
|
return json.load(jsonFile)
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ def writeLicenseHeader(fileDescriptor):
|
|||||||
|
|
||||||
|
|
||||||
def writeRegistersEnum(fileDescriptor, registerJson):
|
def writeRegistersEnum(fileDescriptor, registerJson):
|
||||||
print('Writing enum for all registers')
|
logger.debug('Writing enum for all registers')
|
||||||
|
|
||||||
registerEnums = {}
|
registerEnums = {}
|
||||||
|
|
||||||
@ -141,9 +143,9 @@ def writeRegistersEnum(fileDescriptor, registerJson):
|
|||||||
sortedRegistersKeys = sorted(registersKeys)
|
sortedRegistersKeys = sorted(registersKeys)
|
||||||
sortedRegisterEnumList = []
|
sortedRegisterEnumList = []
|
||||||
|
|
||||||
print('Sorted registers')
|
logger.debug('Sorted registers')
|
||||||
for registerAddress in sortedRegistersKeys:
|
for registerAddress in sortedRegistersKeys:
|
||||||
print('--> %s : %s' % (registerAddress, registerEnums[registerAddress]))
|
logger.debug('--> %s : %s' % (registerAddress, registerEnums[registerAddress]))
|
||||||
enumData = {}
|
enumData = {}
|
||||||
enumData['key'] = registerEnums[registerAddress]
|
enumData['key'] = registerEnums[registerAddress]
|
||||||
enumData['value'] = registerAddress
|
enumData['value'] = registerAddress
|
||||||
@ -165,7 +167,7 @@ def writeRegistersEnum(fileDescriptor, registerJson):
|
|||||||
|
|
||||||
|
|
||||||
def writeEnumDefinition(fileDescriptor, enumDefinition):
|
def writeEnumDefinition(fileDescriptor, enumDefinition):
|
||||||
print('Writing enum', enumDefinition)
|
logger.debug('Writing enum %s', enumDefinition)
|
||||||
enumName = enumDefinition['name']
|
enumName = enumDefinition['name']
|
||||||
enumValues = enumDefinition['values']
|
enumValues = enumDefinition['values']
|
||||||
writeLine(fileDescriptor, ' enum %s {' % enumName)
|
writeLine(fileDescriptor, ' enum %s {' % enumName)
|
||||||
@ -379,21 +381,21 @@ def validateBlocks(blockDefinitions):
|
|||||||
previouseRegisterSize = blockRegisters[i - 1]['size']
|
previouseRegisterSize = blockRegisters[i - 1]['size']
|
||||||
previouseRegisterType = blockRegisters[i - 1]['registerType']
|
previouseRegisterType = blockRegisters[i - 1]['registerType']
|
||||||
if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']:
|
if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']:
|
||||||
print('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id']))
|
logger.warning('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id']))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if blockRegister['access'] != registerAccess:
|
if blockRegister['access'] != registerAccess:
|
||||||
print('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id']))
|
logger.warning('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id']))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if blockRegister['registerType'] != registerType:
|
if blockRegister['registerType'] != registerType:
|
||||||
print('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id']))
|
logger.warning('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id']))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
registerCount += 1
|
registerCount += 1
|
||||||
blockSize += blockRegister['size']
|
blockSize += blockRegister['size']
|
||||||
|
|
||||||
print('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount))
|
logger.debug('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount))
|
||||||
|
|
||||||
|
|
||||||
def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions):
|
def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions):
|
||||||
@ -418,7 +420,7 @@ def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions):
|
|||||||
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||||
else:
|
else:
|
||||||
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||||
writeLine(fileDescriptor, ' */ ' )
|
writeLine(fileDescriptor, ' */' )
|
||||||
writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:]))
|
writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:]))
|
||||||
writeLine(fileDescriptor)
|
writeLine(fileDescriptor)
|
||||||
|
|
||||||
114
libnymea-modbus/tools/examples/example-registers.json
Normal file
114
libnymea-modbus/tools/examples/example-registers.json
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
"className": "Example",
|
||||||
|
"protocol": "BOTH",
|
||||||
|
"endianness": "BigEndian",
|
||||||
|
"enums": [
|
||||||
|
{
|
||||||
|
"name": "NameOfEnum",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"key": "EnumValue1",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "EnumValue2",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registers": [
|
||||||
|
{
|
||||||
|
"id": "foo",
|
||||||
|
"address": 10,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "Foo register",
|
||||||
|
"unit": "ValueUnit",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bar",
|
||||||
|
"address": 20,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "Bar register",
|
||||||
|
"unit": "ValueUnit",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"id": "testBlock",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"registers": [
|
||||||
|
{
|
||||||
|
"id": "A",
|
||||||
|
"address": 0,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "A register",
|
||||||
|
"unit": "X",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B",
|
||||||
|
"address": 2,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "B register",
|
||||||
|
"unit": "X",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "C",
|
||||||
|
"address": 4,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "C register",
|
||||||
|
"unit": "X",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "D",
|
||||||
|
"address": 6,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "D register",
|
||||||
|
"unit": "X",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "E",
|
||||||
|
"address": 8,
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"registerType": "inputRegister",
|
||||||
|
"readSchedule": "update",
|
||||||
|
"description": "E register",
|
||||||
|
"unit": "X",
|
||||||
|
"defaultValue": "0",
|
||||||
|
"access": "RO"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -25,13 +25,14 @@ import json
|
|||||||
import shutil
|
import shutil
|
||||||
import argparse
|
import argparse
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
from connectiontool.toolcommon import *
|
from connectiontool.toolcommon import *
|
||||||
from connectiontool.modbusrtu import *
|
from connectiontool.modbusrtu import *
|
||||||
from connectiontool.modbustcp import *
|
from connectiontool.modbustcp import *
|
||||||
|
|
||||||
def writeTcpHeaderFile():
|
def writeTcpHeaderFile():
|
||||||
print('Writing modbus TCP hader file %s' % headerFilePath)
|
logger.info('Writing modbus TCP header file %s' % headerFilePath)
|
||||||
headerFile = open(headerFilePath, 'w')
|
headerFile = open(headerFilePath, 'w')
|
||||||
|
|
||||||
writeLicenseHeader(headerFile)
|
writeLicenseHeader(headerFile)
|
||||||
@ -40,8 +41,8 @@ def writeTcpHeaderFile():
|
|||||||
writeLine(headerFile)
|
writeLine(headerFile)
|
||||||
writeLine(headerFile, '#include <QObject>')
|
writeLine(headerFile, '#include <QObject>')
|
||||||
writeLine(headerFile)
|
writeLine(headerFile)
|
||||||
writeLine(headerFile, '#include "../modbus/modbusdatautils.h"')
|
writeLine(headerFile, '#include <modbusdatautils.h>')
|
||||||
writeLine(headerFile, '#include "../modbus/modbustcpmaster.h"')
|
writeLine(headerFile, '#include <modbustcpmaster.h>')
|
||||||
|
|
||||||
writeLine(headerFile)
|
writeLine(headerFile)
|
||||||
|
|
||||||
@ -153,12 +154,12 @@ def writeTcpHeaderFile():
|
|||||||
|
|
||||||
|
|
||||||
def writeTcpSourceFile():
|
def writeTcpSourceFile():
|
||||||
print('Writing modbus TCP source file %s' % sourceFilePath)
|
logger.info('Writing modbus TCP source file %s' % sourceFilePath)
|
||||||
sourceFile = open(sourceFilePath, 'w')
|
sourceFile = open(sourceFilePath, 'w')
|
||||||
writeLicenseHeader(sourceFile)
|
writeLicenseHeader(sourceFile)
|
||||||
writeLine(sourceFile)
|
writeLine(sourceFile)
|
||||||
writeLine(sourceFile, '#include "%s"' % headerFileName)
|
writeLine(sourceFile, '#include "%s"' % headerFileName)
|
||||||
writeLine(sourceFile, '#include "loggingcategories.h"')
|
writeLine(sourceFile, '#include <loggingcategories.h>')
|
||||||
writeLine(sourceFile)
|
writeLine(sourceFile)
|
||||||
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
|
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
|
||||||
writeLine(sourceFile)
|
writeLine(sourceFile)
|
||||||
@ -249,7 +250,7 @@ def writeTcpSourceFile():
|
|||||||
|
|
||||||
##########################################################################################################
|
##########################################################################################################
|
||||||
def writeRtuHeaderFile():
|
def writeRtuHeaderFile():
|
||||||
print('Writing modbus TCP hader file %s' % headerFilePath)
|
logger.info('Writing modbus RTU header file %s' % headerFilePath)
|
||||||
headerFile = open(headerFilePath, 'w')
|
headerFile = open(headerFilePath, 'w')
|
||||||
|
|
||||||
writeLicenseHeader(headerFile)
|
writeLicenseHeader(headerFile)
|
||||||
@ -258,7 +259,7 @@ def writeRtuHeaderFile():
|
|||||||
writeLine(headerFile)
|
writeLine(headerFile)
|
||||||
writeLine(headerFile, '#include <QObject>')
|
writeLine(headerFile, '#include <QObject>')
|
||||||
writeLine(headerFile)
|
writeLine(headerFile)
|
||||||
writeLine(headerFile, '#include "../modbus/modbusdatautils.h"')
|
writeLine(headerFile, '#include <modbusdatautils.h>')
|
||||||
writeLine(headerFile, '#include <hardware/modbus/modbusrtumaster.h>')
|
writeLine(headerFile, '#include <hardware/modbus/modbusrtumaster.h>')
|
||||||
|
|
||||||
writeLine(headerFile)
|
writeLine(headerFile)
|
||||||
@ -373,12 +374,12 @@ def writeRtuHeaderFile():
|
|||||||
|
|
||||||
|
|
||||||
def writeRtuSourceFile():
|
def writeRtuSourceFile():
|
||||||
print('Writing modbus RTU source file %s' % sourceFilePath)
|
logger.info('Writing modbus RTU source file %s' % sourceFilePath)
|
||||||
sourceFile = open(sourceFilePath, 'w')
|
sourceFile = open(sourceFilePath, 'w')
|
||||||
writeLicenseHeader(sourceFile)
|
writeLicenseHeader(sourceFile)
|
||||||
|
|
||||||
writeLine(sourceFile, '#include "%s"' % headerFileName)
|
writeLine(sourceFile, '#include "%s"' % headerFileName)
|
||||||
writeLine(sourceFile, '#include "loggingcategories.h"')
|
writeLine(sourceFile, '#include <loggingcategories.h>')
|
||||||
writeLine(sourceFile, '#include <math.h>')
|
writeLine(sourceFile, '#include <math.h>')
|
||||||
writeLine(sourceFile)
|
writeLine(sourceFile)
|
||||||
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
|
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
|
||||||
@ -466,7 +467,6 @@ def writeRtuSourceFile():
|
|||||||
writeLine(sourceFile, '{')
|
writeLine(sourceFile, '{')
|
||||||
writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->modbusRtuMaster()->modbusUuid().toString() << ", " << %s->modbusRtuMaster()->serialPort() << ", slave ID:" << %s->slaveId() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName, debugObjectParamName))
|
writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->modbusRtuMaster()->modbusUuid().toString() << ", " << %s->modbusRtuMaster()->serialPort() << ", slave ID:" << %s->slaveId() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName, debugObjectParamName))
|
||||||
writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers'])
|
writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers'])
|
||||||
|
|
||||||
if 'blocks' in registerJson:
|
if 'blocks' in registerJson:
|
||||||
for blockDefinition in registerJson['blocks']:
|
for blockDefinition in registerJson['blocks']:
|
||||||
writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers'])
|
writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers'])
|
||||||
@ -482,35 +482,49 @@ def writeRtuSourceFile():
|
|||||||
# Main
|
# Main
|
||||||
############################################################################################
|
############################################################################################
|
||||||
|
|
||||||
|
logger = logging.getLogger('modbus-tools')
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
ch = logging.StreamHandler(sys.stdout)
|
||||||
|
ch.setLevel(logging.INFO)
|
||||||
|
formatter = logging.Formatter('%(name)s: %(message)s')
|
||||||
|
ch.setFormatter(formatter)
|
||||||
|
logger.addHandler(ch)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Generate modbus tcp connection class from JSON register definitions file.')
|
parser = argparse.ArgumentParser(description='Generate modbus tcp connection class from JSON register definitions file.')
|
||||||
parser.add_argument('-j', '--json', metavar='<file>', help='The JSON file containing the register definitions.')
|
parser.add_argument('-j', '--json', metavar='<file>', help='The JSON file containing the register definitions.')
|
||||||
parser.add_argument('-o', '--output-directory', metavar='<directory>', help='The output directory for the resulting class.')
|
parser.add_argument('-o', '--output-directory', metavar='<directory>', help='The output directory for the resulting class.')
|
||||||
parser.add_argument('-c', '--class-name', metavar='<name>', help='The name of the resulting class.')
|
parser.add_argument('-v', '--verbose', dest='verboseOutput', action='store_true', help='More verbose output.')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
registerJson = loadJsonFile(args.json)
|
registerJson = loadJsonFile(args.json)
|
||||||
scriptPath = os.path.dirname(os.path.realpath(sys.argv[0]))
|
scriptPath = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||||
outputDirectory = os.path.realpath(args.output_directory)
|
outputDirectory = os.path.realpath(args.output_directory)
|
||||||
className = args.class_name
|
|
||||||
|
|
||||||
headerFileName = className.lower() + '.h'
|
if not os.path.exists(outputDirectory):
|
||||||
sourceFileName = className.lower() + '.cpp'
|
logger.debug("Output directory does not exist. Creating directory %s", outputDirectory)
|
||||||
|
os.makedirs(outputDirectory)
|
||||||
|
|
||||||
headerFilePath = os.path.join(outputDirectory, headerFileName)
|
if args.verboseOutput:
|
||||||
sourceFilePath = os.path.join(outputDirectory, sourceFileName)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
ch.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
print('Scrip path: %s' % scriptPath)
|
logger.debug("Verbose output enabled")
|
||||||
print('Output directory: %s' % outputDirectory)
|
|
||||||
print('Class name: %s' % className)
|
if not 'className' in registerJson:
|
||||||
print('Header file: %s' % headerFileName)
|
logger.warning('Classname missing. Please specify the classname in the json file or pass it to the generatori using -c .')
|
||||||
print('Source file: %s' % sourceFileName)
|
exit(1)
|
||||||
print('Header file path: %s' % headerFilePath)
|
|
||||||
print('Source file path: %s' % sourceFilePath)
|
classNamePrefix = registerJson['className']
|
||||||
|
|
||||||
endianness = 'BigEndian'
|
endianness = 'BigEndian'
|
||||||
if 'endianness' in registerJson:
|
if 'endianness' in registerJson:
|
||||||
endianness = registerJson['endianness']
|
endianness = registerJson['endianness']
|
||||||
|
|
||||||
|
logger.debug('Scrip path: %s' % scriptPath)
|
||||||
|
logger.debug('Output directory: %s' % outputDirectory)
|
||||||
|
logger.debug('Class name prefix: %s' % classNamePrefix)
|
||||||
|
logger.debug('Endianness: %s' % endianness)
|
||||||
|
|
||||||
protocol = 'TCP'
|
protocol = 'TCP'
|
||||||
if 'protocol' in registerJson:
|
if 'protocol' in registerJson:
|
||||||
protocol = registerJson['protocol']
|
protocol = registerJson['protocol']
|
||||||
@ -518,12 +532,77 @@ if 'protocol' in registerJson:
|
|||||||
if 'blocks' in registerJson:
|
if 'blocks' in registerJson:
|
||||||
validateBlocks(registerJson['blocks'])
|
validateBlocks(registerJson['blocks'])
|
||||||
|
|
||||||
|
# Create classes depending on the protocol
|
||||||
|
writeTcp = True
|
||||||
|
writeRtu = False
|
||||||
|
|
||||||
if protocol == 'TCP':
|
if protocol == 'TCP':
|
||||||
|
writeTcp = True
|
||||||
|
writeRtu = False
|
||||||
|
elif protocol == 'RTU':
|
||||||
|
writeTcp = False
|
||||||
|
writeRtu = True
|
||||||
|
else:
|
||||||
|
# Any other value generates both classes
|
||||||
|
writeTcp = True
|
||||||
|
writeRtu = True
|
||||||
|
|
||||||
|
headerFiles = []
|
||||||
|
sourceFiles = []
|
||||||
|
|
||||||
|
if writeTcp:
|
||||||
|
className = classNamePrefix + 'ModbusTcpConnection'
|
||||||
|
headerFileName = className.lower() + '.h'
|
||||||
|
headerFiles.append(headerFileName)
|
||||||
|
sourceFileName = className.lower() + '.cpp'
|
||||||
|
sourceFiles.append(sourceFileName)
|
||||||
|
|
||||||
|
headerFilePath = os.path.join(outputDirectory, headerFileName)
|
||||||
|
sourceFilePath = os.path.join(outputDirectory, sourceFileName)
|
||||||
|
logger.debug('=======================================================')
|
||||||
|
logger.debug('Class name: %s' % className)
|
||||||
|
logger.debug('Header file: %s' % headerFileName)
|
||||||
|
logger.debug('Source file: %s' % sourceFileName)
|
||||||
|
logger.debug('Header file path: %s' % headerFilePath)
|
||||||
|
logger.debug('Source file path: %s' % sourceFilePath)
|
||||||
writeTcpHeaderFile()
|
writeTcpHeaderFile()
|
||||||
writeTcpSourceFile()
|
writeTcpSourceFile()
|
||||||
else:
|
|
||||||
|
if writeRtu:
|
||||||
|
className = classNamePrefix + 'ModbusRtuConnection'
|
||||||
|
headerFileName = className.lower() + '.h'
|
||||||
|
headerFiles.append(headerFileName)
|
||||||
|
sourceFileName = className.lower() + '.cpp'
|
||||||
|
sourceFiles.append(sourceFileName)
|
||||||
|
headerFilePath = os.path.join(outputDirectory, headerFileName)
|
||||||
|
sourceFilePath = os.path.join(outputDirectory, sourceFileName)
|
||||||
|
logger.debug('=======================================================')
|
||||||
|
logger.debug('Class name: %s' % className)
|
||||||
|
logger.debug('Header file: %s' % headerFileName)
|
||||||
|
logger.debug('Source file: %s' % sourceFileName)
|
||||||
|
logger.debug('Header file path: %s' % headerFilePath)
|
||||||
|
logger.debug('Source file path: %s' % sourceFilePath)
|
||||||
writeRtuHeaderFile()
|
writeRtuHeaderFile()
|
||||||
writeRtuSourceFile()
|
writeRtuSourceFile()
|
||||||
|
|
||||||
|
# Write pri file
|
||||||
|
projectIncludeFileName = classNamePrefix.lower() + '.pri'
|
||||||
|
projectIncludeFilePath = os.path.join(outputDirectory, projectIncludeFileName)
|
||||||
|
|
||||||
|
logger.info('Writing connection project include file %s' % projectIncludeFileName)
|
||||||
|
projectIncludeFile = open(projectIncludeFilePath, 'w')
|
||||||
|
writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #')
|
||||||
|
writeLine(projectIncludeFile, '#')
|
||||||
|
writeLine(projectIncludeFile, '# This file has been autogenerated.')
|
||||||
|
writeLine(projectIncludeFile, '# Any changes in this file may be overwritten from qmake.')
|
||||||
|
writeLine(projectIncludeFile, '#')
|
||||||
|
writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #')
|
||||||
|
writeLine(projectIncludeFile)
|
||||||
|
writeLine(projectIncludeFile, 'HEADERS = \\')
|
||||||
|
for generatedHeaderFileName in headerFiles:
|
||||||
|
writeLine(projectIncludeFile, ' $${PWD}/%s \\' % generatedHeaderFileName)
|
||||||
|
|
||||||
|
writeLine(projectIncludeFile)
|
||||||
|
writeLine(projectIncludeFile, "SOURCES = \\")
|
||||||
|
for generatedSourceFileName in sourceFiles:
|
||||||
|
writeLine(projectIncludeFile, ' $${PWD}/%s \\' % generatedSourceFileName)
|
||||||
12
modbus.pri
Normal file
12
modbus.pri
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
QT += network serialport serialbus
|
||||||
|
|
||||||
|
top_srcdir=$$PWD
|
||||||
|
top_builddir=$$shadowed($$PWD)
|
||||||
|
|
||||||
|
INCLUDEPATH += $$top_srcdir/libnymea-modbus
|
||||||
|
LIBS += -L$$top_builddir/libnymea-modbus/ -lnymea-modbus
|
||||||
|
|
||||||
|
OTHER_FILES += $${MODBUS_CONNECTIONS}
|
||||||
|
|
||||||
|
include(libnymea-modbus/modbus-tool.pri)
|
||||||
|
|
||||||
@ -2,7 +2,7 @@ TEMPLATE = subdirs
|
|||||||
|
|
||||||
# Note keep it ordered so the lib will be built first
|
# Note keep it ordered so the lib will be built first
|
||||||
CONFIG += ordered
|
CONFIG += ordered
|
||||||
SUBDIRS += libnymea-sunspec
|
SUBDIRS += libnymea-modbus libnymea-sunspec
|
||||||
|
|
||||||
PLUGIN_DIRS = \
|
PLUGIN_DIRS = \
|
||||||
alphainnotec \
|
alphainnotec \
|
||||||
|
|||||||
Reference in New Issue
Block a user