开源组态HmiFuncDesigner之如何在ProjectManager新增通讯设备插件

开源组态HmiFuncDesigner之如何在ProjectManager新增通讯设备插件

源码仓库地址:
码云源码地址
github源码地址

本文以ModbusRTU为例说明如何在ProjectManager新增通讯设备。本文仅供参考,具体请看实现源码。

1 新建ModbusRTU插件工程
1.1新建插件工程
在{文件HmiFuncDesigner.pro所在目录} \Devices新建ModbusRTU目录, 在ModbusRTU目录新建如下文件:
ModbusRTU.pro
ModbusRTU.cpp,
ModbusRTU.h
ModbusRTU.json
ModbusRTU_dependencies.pri

文件内容可能有改动,详细内容请阅读源码文件!!
1.2ModbusRTU_dependencies.pri文件说明
文件内容:
QTC_PLUGIN_NAME = ModbusRTU
QTC_LIB_DEPENDS +=
QTC_PLUGIN_DEPENDS +=

其中变量“QTC_PLUGIN_NAME”的值为生成的插件名称。最后生成的插件位于目录:HmiFuncDesignerBin\deviceplugins

1.3ModbusRTU.pro文件说明
文件内容:
include(…/…/HmiFuncDesignerDevicePlugin.pri)
SOURCES += ModbusRTU.cpp
HEADERS += ModbusRTU.h
DISTFILES += ModbusRTU.json

其中文件“HmiFuncDesignerDevicePlugin.pri”指定了工程模板,配置,依赖等。

1.4插件接口说明
插件接口{文件HmiFuncDesigner.pro所在目录} \Devices\IDevicePlugin\IDevicePlugin.h
文件内容:


#ifndef IDEVICEPLUGIN_H
#define IDEVICEPLUGIN_H

#include <QStringList>
#include <QPair>
#include <QVector>
#include <QMap>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QXmlStreamAttribute>

/*
* 注意本类不要派生自QObject
*/
class IDevicePlugin
{
public:
    virtual ~IDevicePlugin() {}

    // 获取设备默认属性
    virtual void getDefaultDeviceProperty(QVector<QPair<QString, QString>>& properties) = 0;
    // 获取设备默认属性数据类型
    virtual void getDefaultDevicePropertyDataType(QVector<QPair<QString, QString>>& properties_type) = 0;
    // 保存属性
    virtual void writeProperties(QString &szProperties, QVector<QPair<QString, QString>>& properties) = 0;
    // 加载属性
    virtual void readProperties(QString &szProperties, QVector<QPair<QString, QString>>& properties) = 0;
    // 设置设备属性
    virtual void setDeviceProperty(QVector<QPair<QString, QString>>& properties) = 0;
    // 生成块读变量
    virtual bool buildBlockReadTags(const QString &xmlDevTags, const QString &properties, QString &xmlDevBlockReadTags, QVector<QPair<QString, QString>>& idToBlockId) = 0;

    // 获取设备描述信息
    virtual QString getDeviceDescInfo() = 0;

    QString getValue2ByValue1(const QString &szVal1, QVector<QPair<QString, QString>>& properties) {
        for (int i = 0; i < properties.size(); ++i) {
            QPair<QString, QString> pair = properties[i];
            if (pair.first == szVal1 && pair.second != "")
                return pair.second;
        }
        // 获取默认属性值
        QVector<QPair<QString, QString>> defaultProperties;
        this->getDefaultDeviceProperty(defaultProperties);
        for (int i = 0; i < defaultProperties.size(); ++i) {
            QPair<QString, QString> pair = defaultProperties[i];
            if (pair.first == szVal1)
                return pair.second;
        }
        return "";
    }

    int tagLength(const QString &type) {
        if(type == "bool" || type == "int8" || type == "uint8" || type == "bcd8"){
            return 1;
        } else if(type == "int16" || type == "uint16" || type == "bcd16") {
            return 2;
        } else if(type == "int32" || type == "uint32" || type == "float32" || type == "bcd32") {
            return 4;
        } else if(type == "double" || type == "int64" || type == "uint64") {
            return 8;
        }
        return 0;
    }
};


QT_BEGIN_NAMESPACE

#define DevicePluginInterface_iid "HmiFuncDesigner.Device.PluginInterface"
Q_DECLARE_INTERFACE(IDevicePlugin, DevicePluginInterface_iid)

QT_END_NAMESPACE

#endif // IDEVICEPLUGIN_H

1.5实现ModbusRTU插件
新建ModbusRTU实现类,继承类QObject ,类IDevicePlugin实现插件接口。
文件ModbusRTU.h内容如下:

#ifndef MODBUSRTU_H
#define MODBUSRTU_H

#include <QObject>
#include "../IDevicePlugin/IDevicePlugin.h"

typedef struct tagTagInfo {
    int id;
    quint32 offset;
    quint32 length;
    bool use;
} TTagInfo;

class ModbusRTU : public QObject, IDevicePlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID DevicePluginInterface_iid FILE "ModbusRTU.json")
    Q_INTERFACES(IDevicePlugin)

public:
    ModbusRTU();

    // 获取设备默认属性
    void getDefaultDeviceProperty(QVector<QPair<QString, QString>>& properties) Q_DECL_OVERRIDE;
    // 获取设备默认属性数据类型
    void getDefaultDevicePropertyDataType(QVector<QPair<QString, QString>>& properties_type) Q_DECL_OVERRIDE;
    // 保存属性
    void writeProperties(QString &szProperties, QVector<QPair<QString, QString>>& properties) Q_DECL_OVERRIDE;
    // 加载属性
    void readProperties(QString &szProperties, QVector<QPair<QString, QString>>& properties) Q_DECL_OVERRIDE;
    // 设置设备属性
    void setDeviceProperty(QVector<QPair<QString, QString>>& properties) Q_DECL_OVERRIDE;
    // 生成块读变量
    bool buildBlockReadTags(const QString &xmlDevTags, const QString &properties, QString &xmlDevBlockReadTags, QVector<QPair<QString, QString>>& idToBlockId) Q_DECL_OVERRIDE;

    // 获取设备描述信息
    QString getDeviceDescInfo() Q_DECL_OVERRIDE;

private:
    void loadInfos(QXmlStreamReader *r, QMap<QString, QVector<TTagInfo>> &infos, QString &dev);

private:
    QVector<QPair<QString, QString>> m_properties; // 插件私有属性
    bool m_bStartAddrBit0 = true; // 内存地址起始位为0
};

#endif // MODBUSRTU_H

文件ModbusRTU.cpp内容如下:

#include "ModbusRTU.h"
#include <QDebug>

#define COIL_STATUS    tr("线圈状态")
#define DISCRETE_STATUS    tr("离散量状态")
#define INPUT_REGISTER    tr("输入寄存器")
#define HOLDING_REGISTER    tr("保持寄存器")


ModbusRTU::ModbusRTU() {

}

///
/// \brief ModbusRTU::getDefaultDeviceProperty
/// \details 获取设备默认属性
/// \param properties
///
void ModbusRTU::getDefaultDeviceProperty(QVector<QPair<QString, QString>>& properties) {
    properties.clear();
    properties.append(qMakePair(tr("设备ID"), QString("1")));
    properties.append(qMakePair(tr("位组包最大寄存器个数"), QString("100")));
    properties.append(qMakePair(tr("字组包最大寄存器个数"), QString("20")));
    properties.append(qMakePair(tr("失败重试次数"), QString("2")));
    properties.append(qMakePair(tr("通讯超时时间(s)"), QString("1")));
    properties.append(qMakePair(tr("通讯间隔时间(ms)"), QString("200")));
    properties.append(qMakePair(tr("尝试恢复间隔(s)"), QString("2")));
    properties.append(qMakePair(tr("内存地址起始位为0"), QString("true")));
    properties.append(qMakePair(tr("写线圈功能码为15"), QString("false")));
    properties.append(qMakePair(tr("写寄存器功能码为16"), QString("false")));
    properties.append(qMakePair(tr("8位逆序"), QString("false")));
    properties.append(qMakePair(tr("16位低字节在前高字节在后"), QString("false")));
    properties.append(qMakePair(tr("32位低字节在前高字节在后"), QString("false")));
    properties.append(qMakePair(tr("64位低字节在前高字节在后"), QString("false")));
}


///
/// \brief ModbusRTU::getDefaultDevicePropertyDataType
/// \details 获取设备默认属性数据类型
/// \param properties_type
///
void ModbusRTU::getDefaultDevicePropertyDataType(QVector<QPair<QString, QString>>& properties_type) {
    properties_type.clear();
    properties_type.append(qMakePair(tr("设备ID"), QString("int")));
    properties_type.append(qMakePair(tr("位组包最大寄存器个数"), QString("int")));
    properties_type.append(qMakePair(tr("字组包最大寄存器个数"), QString("int")));
    properties_type.append(qMakePair(tr("失败重试次数"), QString("int")));
    properties_type.append(qMakePair(tr("通讯超时时间(s)"), QString("int")));
    properties_type.append(qMakePair(tr("通讯间隔时间(ms)"), QString("int")));
    properties_type.append(qMakePair(tr("尝试恢复间隔(s)"), QString("int")));
    properties_type.append(qMakePair(tr("内存地址起始位为0"), QString("bool")));
    properties_type.append(qMakePair(tr("写线圈功能码为15"), QString("bool")));
    properties_type.append(qMakePair(tr("写寄存器功能码为16"), QString("bool")));
    properties_type.append(qMakePair(tr("8位逆序"), QString("bool")));
    properties_type.append(qMakePair(tr("16位低字节在前高字节在后"), QString("bool")));
    properties_type.append(qMakePair(tr("32位低字节在前高字节在后"), QString("bool")));
    properties_type.append(qMakePair(tr("64位低字节在前高字节在后"), QString("bool")));
}

///
/// \brief ModbusRTU::writeProperties
/// \details 保存属性
/// \param szProperties 属性字符串
/// \param properties 属性
///
void ModbusRTU::writeProperties(QString &szProperties, QVector<QPair<QString, QString>>& properties) {
    QStringList szListProperties;
    szListProperties << QString("%1=%2").arg("id").arg(getValue2ByValue1(tr("设备ID"), properties)); 
    szListProperties << QString("%1=%2").arg("bitMaxRegPacket").arg(getValue2ByValue1(tr("位组包最大寄存器个数"), properties));
    szListProperties << QString("%1=%2").arg("wordMaxRegPacket").arg(getValue2ByValue1(tr("字组包最大寄存器个数"), properties));
    szListProperties << QString("%1=%2").arg("commFailRetryTimes").arg(getValue2ByValue1(tr("失败重试次数"), properties));
    szListProperties << QString("%1=%2").arg("commTimeout").arg(getValue2ByValue1(tr("通讯超时时间(s)"), properties));
    szListProperties << QString("%1=%2").arg("commIntervalTime").arg(getValue2ByValue1(tr("通讯间隔时间(ms)"), properties));
    szListProperties << QString("%1=%2").arg("commResumeTime").arg(getValue2ByValue1(tr("尝试恢复间隔(s)"), properties));
    szListProperties << QString("%1=%2").arg("startAddrBit").arg(getValue2ByValue1(tr("内存地址起始位为0"), properties));
    szListProperties << QString("%1=%2").arg("writeCoilFn").arg(getValue2ByValue1(tr("写线圈功能码为15"), properties));
    szListProperties << QString("%1=%2").arg("writeRegFn").arg(getValue2ByValue1(tr("写寄存器功能码为16"), properties));
    szListProperties << QString("%1=%2").arg("addr8").arg(getValue2ByValue1(tr("8位逆序"), properties));
    szListProperties << QString("%1=%2").arg("addr16").arg(getValue2ByValue1(tr("16位低字节在前高字节在后"), properties));
    szListProperties << QString("%1=%2").arg("addr32").arg(getValue2ByValue1(tr("32位低字节在前高字节在后"), properties));
    szListProperties << QString("%1=%2").arg("addr64").arg(getValue2ByValue1(tr("64位低字节在前高字节在后"), properties));
    szProperties = szListProperties.join("|");
}

///
/// \brief ModbusRTU::readProperties
/// \details 加载属性
/// \param szProperties 属性字符串
/// \param properties 属性
///
void ModbusRTU::readProperties(QString &szProperties, QVector<QPair<QString, QString>>& properties) {
    properties.clear();
    QStringList szListProperties = szProperties.split("|");
    foreach(QString szKeyValue, szListProperties) {
        if (szKeyValue.startsWith("id=")) {
            QString val = szKeyValue.replace("id=", "");
            if(val == "") val = "1";
            properties.append(qMakePair(tr("设备ID"), val));
        }
        if (szKeyValue.startsWith("bitMaxRegPacket=")) {
            QString val = szKeyValue.replace("bitMaxRegPacket=", "");
            if(val == "") val = "100";
            properties.append(qMakePair(tr("位组包最大寄存器个数"), val));
        }
        if (szKeyValue.startsWith("wordMaxRegPacket=")) {
            QString val = szKeyValue.replace("wordMaxRegPacket=", "");
            if(val == "") val = "20";
            properties.append(qMakePair(tr("字组包最大寄存器个数"), val));
        }
        if (szKeyValue.startsWith("commFailRetryTimes=")) {
            QString val = szKeyValue.replace("commFailRetryTimes=", "");
            if(val == "") val = "2";
            properties.append(qMakePair(tr("失败重试次数"), val));
        }
        if (szKeyValue.startsWith("commTimeout=")) {
            QString val = szKeyValue.replace("commTimeout=", "");
            if(val == "") val = "1";
            properties.append(qMakePair(tr("通讯超时时间(s)"), val));
        }
        if (szKeyValue.startsWith("commIntervalTime=")) {
            QString val = szKeyValue.replace("commIntervalTime=", "");
            if(val == "") val = "200";
            properties.append(qMakePair(tr("通讯间隔时间(ms)"), val));
        }
        if (szKeyValue.startsWith("commResumeTime=")) {
            QString val = szKeyValue.replace("commResumeTime=", "");
            if(val == "") val = "2";
            properties.append(qMakePair(tr("尝试恢复间隔(s)"), val));
        }
        if (szKeyValue.startsWith("startAddrBit=")) {
            QString val = szKeyValue.replace("startAddrBit=", "");
            if(val == "") val = "true";
            properties.append(qMakePair(tr("内存地址起始位为0"), val));
        }
        if (szKeyValue.startsWith("writeCoilFn=")) {
            QString val = szKeyValue.replace("writeCoilFn=", "");
            if(val == "") val = "false";
            properties.append(qMakePair(tr("写线圈功能码为15"), val));
        }
        if (szKeyValue.startsWith("writeRegFn=")) {
            QString val = szKeyValue.replace("writeRegFn=", "");
            if(val == "") val = "false";
            properties.append(qMakePair(tr("写寄存器功能码为16"), val));
        }
        if (szKeyValue.startsWith("addr8=")) {
            QString val = szKeyValue.replace("addr8=", "");
            if(val == "") val = "false";
            properties.append(qMakePair(tr("8位逆序"), val));
        }
        if (szKeyValue.startsWith("addr16=")) {
            QString val = szKeyValue.replace("addr16=", "");
            if(val == "") val = "false";
            properties.append(qMakePair(tr("16位低字节在前高字节在后"), val));
        }
        if (szKeyValue.startsWith("addr32=")) {
            QString val = szKeyValue.replace("addr32=", "");
            if(val == "") val = "false";
            properties.append(qMakePair(tr("32位低字节在前高字节在后"), val));
        }
        if (szKeyValue.startsWith("addr64=")) {
            QString val = szKeyValue.replace("addr64=", "");
            if(val == "") val = "false";
            properties.append(qMakePair(tr("64位低字节在前高字节在后"), val));
        }
    }
}


///
/// \brief ModbusRTU::setDeviceProperty
/// \details 设置设备属性
/// \param properties
///
void ModbusRTU::setDeviceProperty(QVector<QPair<QString, QString>>& properties) {
    m_properties.clear();
    m_properties.append(properties);
    QString szVal = getValue2ByValue1(tr("内存地址起始位为0"), m_properties);
    m_bStartAddrBit0 = (szVal.toLower() == "true") ? true : false;
}

///
/// \brief ModbusRTU::getDeviceDescInfo
/// @details 获取设备描述信息
/// \return 设备描述信息
///
QString ModbusRTU::getDeviceDescInfo() {
#if 0
    <?xml version="1.0"/>
    <Device Name="ModbusRTU" AllDataType="bool|int16|uint16|int32|uint32|float32|double|bcd16|bcd32" SupportProtocol="ModbusRTU">
        <RegAreas>
            <RegArea Name="线圈状态" Alias="0x" Min="0x0000" Max="0xFFFF" DataType="bool" SubArea=""/>
            <RegArea Name="离散量状态" Alias="1x" Min="0x0000" Max="0xFFFF" DataType="bool" SubArea=""/>
            <RegArea Name="输入寄存器" Alias="3x" Min="0x0000" Max="0xFFFF" DataType="int16|uint16|int32|uint32|float32|double|bcd16|bcd32" SubArea=""/>
            <RegArea Name="保持寄存器" Alias="4x" Min="0x0000" Max="0xFFFF" DataType="int16|uint16|int32|uint32|float32|double|bcd16|bcd32" SubArea=""/>
        </RegAreas>
    </Device>
#endif
    QString szDeviceDescInfo;
    QStringList szListDataType;
    QStringList szListSubArea;

    QXmlStreamWriter writer(&szDeviceDescInfo);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeStartElement("Device"); // <Device>
    writer.writeAttribute("Name", "ModbusRTU");

    szListDataType.clear();
    szListDataType << tr("bool")
                   << tr("int16")
                   << tr("uint16")
                   << tr("int32")
                   << tr("uint32")
                   << tr("float32")
                   << tr("double")
                   << tr("bcd16")
                   << tr("bcd32");
    writer.writeAttribute("AllDataType", szListDataType.join("|"));

    // 设备支持的所有协议
    QStringList szListSupportProtocol;
    szListSupportProtocol << "ModbusRTU";
    writer.writeAttribute("SupportProtocol", szListSupportProtocol.join("|"));

    // 设备支持的所有寄存器区
    writer.writeStartElement("RegAreas"); // <RegAreas>

    writer.writeStartElement("RegArea"); // <RegArea>
    writer.writeAttribute("Name", COIL_STATUS);
    writer.writeAttribute("Alias", "0x");
    writer.writeAttribute("Min", "0x0000");
    writer.writeAttribute("Max", "0xFFFF");
    szListDataType.clear();
    szListDataType << tr("bool");
    writer.writeAttribute("DataType", szListDataType.join("|"));
    szListSubArea.clear();
    writer.writeAttribute("SubArea", szListSubArea.join("|"));
    writer.writeEndElement(); // <RegArea/>

    writer.writeStartElement("RegArea"); // <RegArea>
    writer.writeAttribute("Name", DISCRETE_STATUS);
    writer.writeAttribute("Alias", "1x");
    writer.writeAttribute("Min", "0x0000");
    writer.writeAttribute("Max", "0xFFFF");
    szListDataType.clear();
    szListDataType << tr("bool");
    writer.writeAttribute("DataType", szListDataType.join("|"));
    szListSubArea.clear();
    writer.writeAttribute("SubArea", szListSubArea.join("|"));
    writer.writeEndElement(); // <RegArea/>

    writer.writeStartElement("RegArea"); // <RegArea>
    writer.writeAttribute("Name", INPUT_REGISTER);
    writer.writeAttribute("Alias", "3x");
    writer.writeAttribute("Min", "0x0000");
    writer.writeAttribute("Max", "0xFFFF");
    szListDataType.clear();
    szListDataType << tr("int16")
                   << tr("uint16")
                   << tr("int32")
                   << tr("uint32")
                   << tr("float32")
                   << tr("double")
                   << tr("bcd16")
                   << tr("bcd32");
    writer.writeAttribute("DataType", szListDataType.join("|"));
    szListSubArea.clear();
    writer.writeAttribute("SubArea", szListSubArea.join("|"));
    writer.writeEndElement(); // <RegArea/>

    writer.writeStartElement("RegArea"); // <RegArea>
    writer.writeAttribute("Name", HOLDING_REGISTER);
    writer.writeAttribute("Alias", "4x");
    writer.writeAttribute("Min", "0x0000");
    writer.writeAttribute("Max", "0xFFFF");
    szListDataType.clear();
    szListDataType << tr("int16")
                   << tr("uint16")
                   << tr("int32")
                   << tr("uint32")
                   << tr("float32")
                   << tr("double")
                   << tr("bcd16")
                   << tr("bcd32");
    writer.writeAttribute("DataType", szListDataType.join("|"));
    szListSubArea.clear();
    writer.writeAttribute("SubArea", szListSubArea.join("|"));

    writer.writeEndElement(); // <RegArea/>
    writer.writeEndElement(); // <RegAreas/>
    writer.writeEndElement(); // <Device/>
    writer.writeEndDocument();

    return szDeviceDescInfo;
}


void ModbusRTU::loadInfos(QXmlStreamReader *r, QMap<QString, QVector<TTagInfo>> &infos, QString &dev)
{
    QString addr;
    TTagInfo info;
    if(r->name().toString() == "tag") {
        foreach(QXmlStreamAttribute attr, r->attributes()) {
            QString attrName = attr.name().toString();
            if(attrName == "addr"){
                addr = attr.value().toString();
            } else if(attrName == "id"){
                info.id = attr.value().toInt();
            } else if(attrName == "dev"){
                dev = attr.value().toString();
            } else if(attrName == "offset"){
                info.offset = attr.value().toInt();
            } else if(attrName == "type"){
                info.length = tagLength(attr.value().toString());
            }
        }

        if(infos.count(addr) > 0) {
            QVector<TTagInfo> &vecInfo = infos[addr];
            vecInfo.append(info);
        } else {
            QVector<TTagInfo> vecInfo;
            vecInfo.append(info);
            infos[addr] = vecInfo;
        }
    }
}

/**
 * @brief ModbusRTU::buildBlockReadTags 生成块读变量
 * @param xmlDevTags 同一设备的所有寄存器变量
 * @param xmlDevBlockReadTags 同一设备的所有块读变量
 * @param idToBlockId 变量ID对应的块读变量ID
 * @return true-成功, false-失败
 */
bool ModbusRTU::buildBlockReadTags(const QString &xmlDevTags, const QString &properties, QString &xmlDevBlockReadTags, QVector<QPair<QString, QString>>& idToBlockId)
{
#if 0
    xmlDevTags -->
    <tags>
        <tag addr="4x" addr2="" dev="ModbusRTU" group="" id="7" name="4x1" offset="0" offset2="0" remark="" type="uint16" unit="" writeable="1" blockReadId="60001"/>
        <tag addr="4x" addr2="" dev="ModbusRTU" group="" id="8" name="4x2" offset="1" offset2="0" remark="" type="uint16" unit="" writeable="1" blockReadId="60001"/>
        <tag addr="0x" addr2="" dev="ModbusRTU" group="" id="2" name="0x00" offset="0" offset2="0" remark="" type="bool" unit="" writeable="1" blockReadId="60002"/>
    </tags>

    xmlDevBlockReadTags -->
    <block_tags>
        <tag addr="4x" addr2="" dev="ModbusRTU" group="" id="60001" name="4x1" offset="0" offset2="0" remark="" type="4:reg" unit="" writeable="0" blockReadId=""/>
        <tag addr="0x" addr2="" dev="ModbusRTU" group="" id="60002" name="0x00" offset="0" offset2="0" remark="" type="1:reg" unit="" writeable="0" blockReadId=""/>
    </block_tags>
#endif

    int bitMaxRegPacket = 0;
    int wordMaxRegPacket = 0;

    QStringList szListProperties = properties.split("|");
    foreach(QString szKeyValue, szListProperties) {
        if (szKeyValue.startsWith("bitMaxRegPacket=")) {
            QString val = szKeyValue.replace("bitMaxRegPacket=", "").trimmed();
            if(!val.isEmpty()) {
                bitMaxRegPacket = val.toInt();
            }
        }
        if (szKeyValue.startsWith("wordMaxRegPacket=")) {
            QString val = szKeyValue.replace("wordMaxRegPacket=", "").trimmed();
            if(!val.isEmpty()) {
                wordMaxRegPacket = val.toInt();
            }
        }
    }

    // 不需要块读
    if(bitMaxRegPacket <= 0 && wordMaxRegPacket <= 0) {
        return false;
    }

    QString dev = "";
    QMap<QString, QVector<TTagInfo>> mapInfos;

    // 解析设备变量节点
    QXmlStreamReader r(xmlDevTags);
    while(!r.atEnd() && !r.hasError()) {
        if(r.readNext() == QXmlStreamReader::StartElement) {
            if(r.name() == "tag") {
                loadInfos(&r, mapInfos, dev);
            }
        }
    }
#if 0
    {
        qDebug() << "dev: " << dev;
        QList<QString> memInfo = mapInfos.keys();
        qDebug() << "memInfo: " << memInfo;
        foreach (QString info, memInfo) {
            QVector<TTagInfo> &vecInfo = mapInfos[info];
            foreach(TTagInfo tagInfo, vecInfo) {
                qDebug() << "tagInfo: " << tagInfo.id << tagInfo.offset << tagInfo.length;
            }
        }
    }
#endif
    ///
    /// 生成打包变量
    ///
    quint16 min0xAddr = 0xffff;
    quint16 max0xAddr = 0;
    quint16 var0xCnt = 0;

    quint16 min1xAddr = 0xffff;
    quint16 max1xAddr = 0;
    quint16 var1xCnt = 0;

    quint16 min3xAddr = 0xffff;
    quint16 max3xAddr = 0;
    quint16 var3xCnt = 0;

    quint16 min4xAddr = 0xffff;
    quint16 max4xAddr = 0;
    quint16 var4xCnt = 0;

    QList<QString> memInfo = mapInfos.keys();
    foreach (QString info, memInfo) {
        QVector<TTagInfo> &vecInfo = mapInfos[info];
        foreach(TTagInfo tagInfo, vecInfo) {
            if(info == "0x") {
                if(min0xAddr > tagInfo.offset) {
                    min0xAddr = tagInfo.offset;
                }
                if(max0xAddr <= tagInfo.offset + tagInfo.length) {
                    max0xAddr = tagInfo.offset + tagInfo.length;
                }
                var0xCnt++;
            } else if(info == "1x") {
                if(min1xAddr > tagInfo.offset) {
                    min1xAddr = tagInfo.offset;
                }
                if(max1xAddr <= tagInfo.offset + tagInfo.length) {
                    max1xAddr = tagInfo.offset + tagInfo.length;
                }
                var1xCnt++;
            } else if(info == "3x") {
                if(min3xAddr > tagInfo.offset) {
                    min3xAddr = tagInfo.offset;
                }
                if(max3xAddr <= tagInfo.offset + tagInfo.length / 2 - 1) {
                    max3xAddr = tagInfo.offset + tagInfo.length / 2 - 1;
                }
                var3xCnt++;
            } else if(info == "4x") {
                if(min4xAddr > tagInfo.offset) {
                    min4xAddr = tagInfo.offset;
                }
                if(max4xAddr <= tagInfo.offset + tagInfo.length / 2 - 1) {
                    max4xAddr = tagInfo.offset + tagInfo.length / 2 - 1;
                }
                var4xCnt++;
            }
        }
    }
#if 0
    qDebug() << "0x number: " << var0xCnt << ", min addr: " << min0xAddr << ", max addr: " << max0xAddr;
    qDebug() << "1x number: " << var1xCnt << ", min addr: " << min1xAddr << ", max addr: " << max1xAddr;
    qDebug() << "3x number: " << var3xCnt << ", min addr: " << min3xAddr << ", max addr: " << max3xAddr;
    qDebug() << "4x number: " << var4xCnt << ", min addr: " << min4xAddr << ", max addr: " << max4xAddr;
#endif
    QMap<QString, QVector<TTagInfo *>> mapBlockInfos;
    QVector<TTagInfo *> vecInfo0x;
    mapBlockInfos["0x"] = vecInfo0x;

    QVector<TTagInfo *> vecInfo1x;
    mapBlockInfos["1x"] = vecInfo1x;

    QVector<TTagInfo *> vecInfo3x;
    mapBlockInfos["3x"] = vecInfo3x;

    QVector<TTagInfo *> vecInfo4x;
    mapBlockInfos["4x"] = vecInfo4x;

    int iNextPackageVarID = 60001;

    // 创建0x组包变量
    if(var0xCnt > 1) {
        int num = (max0xAddr - min0xAddr + 1) / bitMaxRegPacket;
        if(((max0xAddr - min0xAddr + 1) % bitMaxRegPacket) > 0) {
            num++;
        }

        //qDebug() << "0x pack variable number: " << num;

        for(int j=0; j<num; j++) {
            TTagInfo *pInfoObj = new TTagInfo;
            pInfoObj->id = iNextPackageVarID;
            pInfoObj->offset = min0xAddr + j * bitMaxRegPacket;
            pInfoObj->length = bitMaxRegPacket;
            pInfoObj->use = false;
            iNextPackageVarID++;
            mapBlockInfos["0x"].append(pInfoObj);
        }
    }

    // 创建1x组包变量
    if(var1xCnt > 1) {
        int num = (max1xAddr - min1xAddr + 1) / bitMaxRegPacket;
        if(((max1xAddr - min1xAddr + 1) % bitMaxRegPacket) > 0) {
            num++;
        }

        //qDebug() << "1x pack variable number: " << num;

        for(int j=0; j<num; j++) {
            TTagInfo *pInfoObj = new TTagInfo;
            pInfoObj->id = iNextPackageVarID;
            pInfoObj->offset = min1xAddr + j * bitMaxRegPacket;
            pInfoObj->length = bitMaxRegPacket;
            pInfoObj->use = false;
            iNextPackageVarID++;
            mapBlockInfos["1x"].append(pInfoObj);
        }
    }

    // 创建3x组包变量
    if(var3xCnt > 1) {
        int num = (max3xAddr - min3xAddr + 1) / wordMaxRegPacket;
        if(((max3xAddr - min3xAddr + 1) % wordMaxRegPacket) > 0) {
            num++;
        }

        //qDebug() << "3x pack variable number: " << num;

        for(int j=0; j<num; j++) {
            TTagInfo *pInfoObj = new TTagInfo;
            pInfoObj->id = iNextPackageVarID;
            pInfoObj->offset = min3xAddr + j * wordMaxRegPacket;
            pInfoObj->length = wordMaxRegPacket;
            pInfoObj->use = false;
            iNextPackageVarID++;
            mapBlockInfos["3x"].append(pInfoObj);
        }
    }

    // 创建4x组包变量
    if(var4xCnt > 1) {
        int num = (max4xAddr - min4xAddr + 1) / wordMaxRegPacket;
        if(((max4xAddr - min4xAddr + 1) % wordMaxRegPacket) > 0) {
            num++;
        }

        //qDebug() << "4x pack variable number: " << num;

        for(int j=0; j<num; j++) {
            TTagInfo *pInfoObj = new TTagInfo;
            pInfoObj->id = iNextPackageVarID;
            pInfoObj->offset = min4xAddr + j * wordMaxRegPacket;
            pInfoObj->length = wordMaxRegPacket;
            pInfoObj->use = false;
            iNextPackageVarID++;
            mapBlockInfos["4x"].append(pInfoObj);
        }
    }
    ///
    /// 变量关联组包变量
    ///
    QXmlStreamWriter writer(&xmlDevBlockReadTags);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeStartElement("block_tags"); // <block_tags>

    QVector<TTagInfo *> &vecTagInfo0x = mapBlockInfos["0x"];
    quint32 dwFindMax0xAddr = 0; // 包内的最大地址
    quint32 dwFindMin0xAddr = 0xffff; // 包内的最小地址
    foreach(TTagInfo *pObj, vecTagInfo0x) {
        quint32 iMinAddrOffset = pObj->offset;
        quint32 iMaxAddrOffset = pObj->length;
        dwFindMax0xAddr = iMinAddrOffset;
        dwFindMin0xAddr = iMaxAddrOffset;
        QList<QString> memInfo = mapInfos.keys();
        foreach (QString info, memInfo) {
            if(info != "0x") {
                continue;
            }
            QVector<TTagInfo> &vecInfo = mapInfos[info];
            foreach(TTagInfo tagInfo, vecInfo) {
                if(tagInfo.offset >= iMinAddrOffset && (tagInfo.offset + tagInfo.length) <= iMaxAddrOffset) {
                    pObj->use = true;
                    QPair<QString, QString> idPair;
                    idPair.first = QString::number(tagInfo.id);
                    idPair.second = QString::number(pObj->id);
                    idToBlockId.append(idPair);
                    if((tagInfo.offset + tagInfo.length) > dwFindMax0xAddr) {
                        dwFindMax0xAddr = tagInfo.offset + tagInfo.length;
                    }
                    if(dwFindMin0xAddr > tagInfo.offset) {
                        dwFindMin0xAddr = tagInfo.offset;
                    }
                }
            }
        }
        writer.writeStartElement("tag"); // <tag>
        writer.writeAttribute("addr", "0x");
        writer.writeAttribute("addr2", "");
        writer.writeAttribute("dev", dev);
        writer.writeAttribute("group", "");
        writer.writeAttribute("id", QString::number(pObj->id));
        writer.writeAttribute("name", QString("0x_%1").arg(QString::number(pObj->id)));
        writer.writeAttribute("offset", QString::number(pObj->offset));
        writer.writeAttribute("offset2", "");
        writer.writeAttribute("remark", "");
        writer.writeAttribute("type", QString("%1:reg").arg(QString::number(dwFindMax0xAddr - dwFindMin0xAddr)));
        writer.writeAttribute("unit", "");
        writer.writeAttribute("writeable", "0");
        writer.writeAttribute("blockReadId", "");
        writer.writeEndElement(); // <tag/>
    }

    QVector<TTagInfo *> &vecTagInfo1x = mapBlockInfos["1x"];
    quint32 dwFindMax1xAddr = 0; // 包内的最大地址
    quint32 dwFindMin1xAddr = 0xffff; // 包内的最小地址
    foreach(TTagInfo *pObj, vecTagInfo1x) {
        quint32 iMinAddrOffset = pObj->offset;
        quint32 iMaxAddrOffset = pObj->length;
        dwFindMax1xAddr = iMinAddrOffset;
        dwFindMin1xAddr = iMaxAddrOffset;
        QList<QString> memInfo = mapInfos.keys();
        foreach (QString info, memInfo) {
            if(info != "1x") {
                continue;
            }
            QVector<TTagInfo> &vecInfo = mapInfos[info];
            foreach(TTagInfo tagInfo, vecInfo) {
                if(tagInfo.offset >= iMinAddrOffset && (tagInfo.offset + tagInfo.length) <= iMaxAddrOffset) {
                    pObj->use = true;
                    QPair<QString, QString> idPair;
                    idPair.first = QString::number(tagInfo.id);
                    idPair.second = QString::number(pObj->id);
                    idToBlockId.append(idPair);
                    if((tagInfo.offset + tagInfo.length) > dwFindMax1xAddr) {
                        dwFindMax1xAddr = tagInfo.offset + tagInfo.length;
                    }
                    if(dwFindMin1xAddr > tagInfo.offset) {
                        dwFindMin1xAddr = tagInfo.offset;
                    }
                }
            }
        }
        writer.writeStartElement("tag"); // <tag>
        writer.writeAttribute("addr", "1x");
        writer.writeAttribute("addr2", "");
        writer.writeAttribute("dev", dev);
        writer.writeAttribute("group", "");
        writer.writeAttribute("id", QString::number(pObj->id));
        writer.writeAttribute("name", QString("1x_%1").arg(QString::number(pObj->id)));
        writer.writeAttribute("offset", QString::number(pObj->offset));
        writer.writeAttribute("offset2", "");
        writer.writeAttribute("remark", "");
        writer.writeAttribute("type", QString("%1:reg").arg(QString::number(dwFindMax1xAddr - dwFindMin1xAddr)));
        writer.writeAttribute("unit", "");
        writer.writeAttribute("writeable", "0");
        writer.writeAttribute("blockReadId", "");
        writer.writeEndElement(); // <tag/>
    }

    QVector<TTagInfo *> &vecTagInfo3x = mapBlockInfos["3x"];
    quint32 dwFindMax3xAddr = 0; // 包内的最大地址
    quint32 dwFindMin3xAddr = 0xffff; // 包内的最小地址
    foreach(TTagInfo *pObj, vecTagInfo3x) {
        quint32 iMinAddrOffset = pObj->offset;
        quint32 iMaxAddrOffset = pObj->length;
        dwFindMax3xAddr = iMinAddrOffset;
        dwFindMin3xAddr = iMaxAddrOffset;
        QList<QString> memInfo = mapInfos.keys();
        foreach (QString info, memInfo) {
            if(info != "3x") {
                continue;
            }
            QVector<TTagInfo> &vecInfo = mapInfos[info];
            foreach(TTagInfo tagInfo, vecInfo) {
                if(tagInfo.offset >= iMinAddrOffset && (tagInfo.offset + tagInfo.length) <= iMaxAddrOffset) {
                    pObj->use = true;
                    QPair<QString, QString> idPair;
                    idPair.first = QString::number(tagInfo.id);
                    idPair.second = QString::number(pObj->id);
                    idToBlockId.append(idPair);
                    if((tagInfo.offset + tagInfo.length) > dwFindMax3xAddr) {
                        dwFindMax3xAddr = tagInfo.offset + tagInfo.length / 2;
                    }
                    if(dwFindMin3xAddr > tagInfo.offset) {
                        dwFindMin3xAddr = tagInfo.offset;
                    }
                }
            }
        }
        writer.writeStartElement("tag"); // <tag>
        writer.writeAttribute("addr", "3x");
        writer.writeAttribute("addr2", "");
        writer.writeAttribute("dev", dev);
        writer.writeAttribute("group", "");
        writer.writeAttribute("id", QString::number(pObj->id));
        writer.writeAttribute("name", QString("3x_%1").arg(QString::number(pObj->id)));
        writer.writeAttribute("offset", QString::number(pObj->offset));
        writer.writeAttribute("offset2", "");
        writer.writeAttribute("remark", "");
        writer.writeAttribute("type", QString("%1:reg").arg(QString::number(dwFindMax3xAddr - dwFindMin3xAddr)));
        writer.writeAttribute("unit", "");
        writer.writeAttribute("writeable", "0");
        writer.writeAttribute("blockReadId", "");
        writer.writeEndElement(); // <tag/>
    }

    QVector<TTagInfo *> &vecTagInfo4x = mapBlockInfos["4x"];
    quint32 dwFindMax4xAddr = 0; // 包内的最大地址
    quint32 dwFindMin4xAddr = 0xffff; // 包内的最小地址
    foreach(TTagInfo *pObj, vecTagInfo4x) {
        quint32 iMinAddrOffset = pObj->offset;
        quint32 iMaxAddrOffset = pObj->length;
        dwFindMax4xAddr = iMinAddrOffset;
        dwFindMin4xAddr = iMaxAddrOffset;
        QList<QString> memInfo = mapInfos.keys();
        foreach (QString info, memInfo) {
            if(info != "4x") {
                continue;
            }
            QVector<TTagInfo> &vecInfo = mapInfos[info];
            foreach(TTagInfo tagInfo, vecInfo) {
                if(tagInfo.offset >= iMinAddrOffset && (tagInfo.offset + tagInfo.length) <= iMaxAddrOffset) {
                    pObj->use = true;
                    QPair<QString, QString> idPair;
                    idPair.first = QString::number(tagInfo.id);
                    idPair.second = QString::number(pObj->id);
                    idToBlockId.append(idPair);
                    if((tagInfo.offset + tagInfo.length) > dwFindMax4xAddr) {
                        dwFindMax4xAddr = tagInfo.offset + tagInfo.length / 2;
                    }
                    if(dwFindMin4xAddr > tagInfo.offset) {
                        dwFindMin4xAddr = tagInfo.offset;
                    }
                }
            }
        }
        writer.writeStartElement("tag"); // <tag>
        writer.writeAttribute("addr", "4x");
        writer.writeAttribute("addr2", "");
        writer.writeAttribute("dev", dev);
        writer.writeAttribute("group", "");
        writer.writeAttribute("id", QString::number(pObj->id));
        writer.writeAttribute("name", QString("4x_%1").arg(QString::number(pObj->id)));
        writer.writeAttribute("offset", QString::number(pObj->offset));
        writer.writeAttribute("offset2", "");
        writer.writeAttribute("remark", "");
        writer.writeAttribute("type", QString("%1:reg").arg(QString::number(dwFindMax4xAddr - dwFindMin4xAddr)));
        writer.writeAttribute("unit", "");
        writer.writeAttribute("writeable", "0");
        writer.writeAttribute("blockReadId", "");
        writer.writeEndElement(); // <tag/>
    }

    writer.writeEndElement(); // <block_tags/>
    writer.writeEndDocument();

    qDeleteAll(vecTagInfo0x);
    qDeleteAll(vecTagInfo1x);
    qDeleteAll(vecTagInfo3x);
    qDeleteAll(vecTagInfo4x);
    mapBlockInfos.clear();

    return true;
}

1.6编译插件工程
编译ModbusRTU插件工程,生成的ModbusRTU.dll文件位于目录HmiFuncDesignerBin\deviceplugins\ModbusRTU.dll

2 ProjectManager相关配置
2.1 配置文件
修改配置文件HmiFuncDesignerBin\bin\Config\communication_device.ini
配置文件内容如下:

####################################
## 设备列表
[DeviceSupportList]
list-count=6 #设备个数
list-1=GenDataProgram-模拟数据程序
list-2=IOModule-IO模块
list-3=PlcDevice-PLC
list-4=ModbusDevice-Modbus设备
list-5=GaugeDevice-仪表设备
list-6=CustomDevice-用户自定义设备

####################################
# 模拟数据程序
[GenDataProgram]
list-count=0
list-1=


######################################
# IO模块
[IOModule]
list-count=0
list-1=


######################################
# PLC设备
[PlcDevice]
list-count=0
list-1=Mitsubishi
list-2=SIEMENS


# SIEMENS-PLC设备
[SIEMENS]
list-count=0
list-1=S7_200-COM

# Mitsubishi-PLC设备
[Mitsubishi]
list-count=0
list-1=FX2N-COM


######################################

# Modbus设备
[ModbusDevice]
list-count=2
list-1=SerialModbus
list-2=TCPIPModbus

# Serial_Modbus设备
# COM, NET, BUS, OPC
[SerialModbus]
list-count=1
list-1=ModbusRTU-COM #COM-串口设备
list-2=ModbusASCII-COM

#list-count=4
#list-1=ModbusRTU_slave-COM
#list-2=ModbusRTU-COM
#list-3=ModbusASCII_slave-COM
#list-4=ModbusASCII-COM

# TcpIP_Modbus设备
[TCPIPModbus]
list-count=1
list-1=TCPIPModbus-NET #NET-网络设备
#list-count=2
#list-1=TCPIPModbus_slave-NET
#list-2=TCPIPModbus-NET

######################################

# 仪表设备
[GaugeDevice]
list-count=0
list-1=


######################################

# 用户自定义设备
[CustomDevice]
list-count=0
list-1=

2.2 ModbusRTU配置

ModbusRTU属于“ModbusDevice-Modbus设备”设备类中的“ModbusDevice”类别中的“SerialModbus”类,在“SerialModbus”类中ModbusRTU属于串口通信类别的,顾取值为“ModbusRTU-COM”。

####################################

## 设备列表
[DeviceSupportList]
list-count=配置项数量
list-第几项=ModbusDevice-Modbus设备

######################################

# Modbus设备
[ModbusDevice]
list-count=配置项数量
list-第几项=SerialModbus

######################################

# Serial_Modbus设备
# COM, NET, BUS, OPC
[SerialModbus]
list-count=配置项数量
list-第几项=ModbusRTU-COM

3 ProjectManager插件相关源码和UI
请阅读文件:NewComDeviceDialog.cpp,VariableEditDialog.cpp

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于Java开源物联网组态,可以实现一个可靠、高效的物联网系统。首先,使用Java开发物联网组态可以充分利用Java语言的优势,它是一种高性能、面向对象的编程语言,具有可移植性强、跨平台、易学易用等特点。 在物联网组态的开发中,我们可以使用Java开源框架如Spring Boot、Spring MVC等来进行应用的快速搭建和开发,实现物联网设备的接入、数据采集和存储、数据的可视化展示等功能。同时,Java提供了丰富的API和库,如JavaFX图形库可以实现可视化界面的设计和开发,Apache Kafka可以实现物联网数据流的高效处理和传输,MySQL、MongoDB等数据库可以用来存储和管理物联网设备产生的数据。 此外,Java还提供了大量的开源物联网平台,如Eclipse IoT、ThingsBoard等,这些平台基于Java开发,提供了一整套的物联网解决方案和工具链,可以帮助开发者快速部署和管理物联网应用。 总之,基于Java开源物联网组态,可以快速、高效地开发出功能强大的物联网系统。无论是从物联网设备的接入到数据的处理和展示,还是从物联网平台的部署和管理,Java都提供了丰富的工具和技术来支持。使用Java开发物联网组态,可以满足不同应用场景的需求,实现物联网的智能化、自动化和可视化,助力推动物联网技术的发展和应用。 ### 回答2: 基于Java开源物联网组态是一种用于构建物联网系统的开源工具。它提供了一套丰富的功能和工具,帮助开发人员快速构建和管理物联网设备和应用程序。 首先,基于Java开源物联网组态提供了一套强大的设备管理功能。它可以自动发现和注册物联网设备,监控设备的状态和性能,并提供设备管理接口,使开发人员可以方便地管理设备的配置和属性。 其次,该开源工具提供了丰富的数据收集和处理功能。它可以采集来自不同设备的数据,支持各种传输协议,并提供数据存储和处理的功能。开发人员可以使用该工具来存储、查询和分析物联网设备生成的数据,从而实现更高级的数据分析和应用。 此外,基于Java开源物联网组态还提供了一套易用的应用程序开发框架。开发人员可以使用该框架构建各种类型的物联网应用程序,如远程监控、智能家居等。该框架提供了丰富的API和工具,使开发人员可以方便地开发和部署应用程序,并提供了完善的安全机制,保护物联网系统的安全性。 总之,基于Java开源物联网组态是一种功能强大的开源工具,它提供了丰富的设备管理、数据收集和处理以及应用程序开发功能。它可以帮助开发人员快速构建和管理物联网系统,并实现更高级的物联网应用。同时,它的开源特性使得开发人员可以根据自己的需求进行定制和扩展,实现更多的功能和应用场景。 ### 回答3: 基于Java的开源物联网组态平台是一种使用Java作为主要开发语言并且以开源形式提供的物联网设备管理和控制平台。这种平台提供了一系列功能强大的工具和框架,用于连接和管理各种物联网设备,实现数据采集、监控和控制等功能。 使用基于Java的开源物联网组态平台,用户可以方便地搭建一个物联网系统。首先,该平台提供了各种支持多种物联网通信协议的接口和驱动程序,例如MQTT、CoAP、Modbus等,可以直接与各种物联网设备进行通信。其次,该平台具备数据采集和存储功能,可以实时地从设备中采集数据,并将数据存储到数据库中。用户可以通过图形化界面来配置数据采集参数,方便地进行数据监控和分析。 除了数据采集功能,该平台还提供了设备管理和控制的功能。用户可以通过平台对设备进行远程管理,包括设备的注册、绑定、配置等操作。同时,用户也可以通过平台对设备进行控制,例如发送命令、设置参数等。该平台还支持多用户和权限管理,可以根据用户的角色和权限对设备和数据进行访问控制。 基于Java的开源物联网组态平台还具备良好的可扩展性和定制性。用户可以根据自己的需求,对平台进行二次开发和定制,以适应特定的物联网应用场景。此外,该平台还提供了丰富的开发文档和社区支持,用户可以在开发过程中获取帮助和交流经验。 总而言之,基于Java的开源物联网组态平台是一种功能强大、灵活可定制的物联网设备管理和控制平台。它通过提供丰富的工具和框架,帮助用户快速搭建和管理物联网系统,实现数据采集、监控和控制等功能。同时,该平台还具备良好的可扩展性和定制性,用户可以根据需要进行二次开发和定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值