OPCUA Java milo 结构在UAEExpert 中的结构错误

问题描述

我正在使用 milo 0.5.4 来设置我自己的 Opcua 服务器。

现在我尝试使用一个复杂的数据类型,它应该在一个结构中包含一个结构。

但是当连接到UAExpert客户端时,显示如下错误信息:

UaBsdReader::evaluateTypeName: 无法确定 TypeName ua: Structure 的数据类型

BsdReader 无法在字段状态中解释类型 ua:Structure

下面我添加了UAExpert结果的图片

我猜这个问题与 registerToxStructType() 中的 Identifiers.Structure 有关。但我不知道这里还应该使用什么。 我希望那里的任何人都可以给我提示

new StructureField("status",LocalizedText.NULL_VALUE,Identifiers.Structure,ValueRanks.Scalar,null,uint(0),false) };

这是我第一次注册结构:

    private void registerStatusstructType() throws Exception {
        // Get the NodeId for the DataType and encoding Nodes.

        NodeId dataTypeId = StatusstructType.TYPE_ID.toNodeIdOrThrow(getServer().getNamespaceTable());

        NodeId binaryEncodingId = StatusstructType.BINARY_ENCODING_ID.toNodeIdOrThrow(getServer().getNamespaceTable());
        
        dictionaryManager.registerStructureCodec(new StatusstructType.Codec(),"StatusstructType",dataTypeId,binaryEncodingId ); ///,parentTypeId);
        

        StructureField[] fields = new StructureField[] { new StructureField("type",Identifiers.String,false),new StructureField("text",new StructureField("source",false) };

        StructureDeFinition deFinition = new StructureDeFinition(binaryEncodingId,StructureType.Structure,fields);

        StructureDescription description = new StructureDescription(dataTypeId,new Qualifiedname(getNamespaceIndex(),"StatusstructType"),deFinition);

        dictionaryManager.registerStructureDescription(description,binaryEncodingId);

    }

这是我想包含第一个结构的注册

    private void registerToxStructType() throws Exception {
        // Get the NodeId for the DataType and encoding Nodes.

        NodeId dataTypeId = ToxStructType.TYPE_ID.toNodeIdOrThrow(getServer().getNamespaceTable());

        NodeId binaryEncodingId = ToxStructType.BINARY_ENCODING_ID.toNodeIdOrThrow(getServer().getNamespaceTable());

        dictionaryManager.registerStructureCodec(new ToxStructType.Codec(),"ToxStructType",binaryEncodingId);
        
        StructureField[] fields = new StructureField[] { 
                new StructureField("foo",getServer().getConfig().getLimits().getMaxStringLength(),new StructureField("bar",Identifiers.Int32,new StructureField("baz",Identifiers.Boolean,//};
                new StructureField("status","ToxStructType"),binaryEncodingId);
    }

这是添加ToxStructType的函数

    private void addToxStructTypeVariable(UaFolderNode rootFolder) throws Exception {
        NodeId dataTypeId = ToxStructType.TYPE_ID.toNodeIdOrThrow(getServer().getNamespaceTable());

        NodeId binaryEncodingId = ToxStructType.BINARY_ENCODING_ID.toNodeIdOrThrow(getServer().getNamespaceTable());

        UaVariableNode ToxStructTypeVariable = UaVariableNode.builder(getNodeContext())
                                                             .setNodeId(newNodeId("ThisIsMyPart/ToxStructTypeVariable"))
                                                             .setAccessLevel(AccessLevel.READ_WRITE)
                                                             .setUserAccessLevel(AccessLevel.READ_WRITE)
                                                             .setbrowseName(newQualifiedname("ToxStructTypeVariable"))
                                                             .setdisplayName(LocalizedText.english("ToxStructTypeVariable"))
                                                             .setDataType(dataTypeId)
                                                             .setTypeDeFinition(Identifiers.BaseDataVariableType)
                                                             .build();
        
        StatusstructType statestruct = new StatusstructType("Error 0010","Error 0010 occured! 0x0F","Device 0010?");

        ToxStructType value = new ToxStructType("foo",42,true,statestruct );

        ExtensionObject xo = ExtensionObject.encodeDefaultBinary(getServer().getSerializationContext(),value,binaryEncodingId);

        ToxStructTypeVariable.setValue(new DataValue(new Variant(xo)));

        getNodeManager().addNode(ToxStructTypeVariable);

        ToxStructTypeVariable.addReference(new Reference(ToxStructTypeVariable.getNodeId(),Identifiers.Organizes,rootFolder.getNodeId().expanded(),false));
    }   

结构 ToxStructType.java:

package com.toxware.export.opcua.communication.server.util;

import org.eclipse.milo.opcua.stack.core.UaSerializationException;
import org.eclipse.milo.opcua.stack.core.serialization.OpcuaBinaryStreamDecoder;
import org.eclipse.milo.opcua.stack.core.serialization.OpcuaBinaryStreamEncoder;
import org.eclipse.milo.opcua.stack.core.serialization.SerializationContext;
import org.eclipse.milo.opcua.stack.core.serialization.UaStructure;
import org.eclipse.milo.opcua.stack.core.serialization.codecs.OpcuaBinaryDataTypeCodec;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandednodeId;

import com.toxware.export.opcua.communication.server.ToxNamespaceDRX;

public class ToxStructType implements UaStructure {

    public static final ExpandednodeId TYPE_ID = ExpandednodeId.parse(String.format("nsu=%s;s=%s",ToxNamespaceDRX.NAMESPACE_URI,"DataType.ToxStructType"));

    public static final ExpandednodeId BINARY_ENCODING_ID = ExpandednodeId.parse(String.format("nsu=%s;s=%s","DataType.ToxStructType.BinaryEncoding"));

    private final String foo;
    private final Integer bar;
    private final boolean baz;
    private final StatusstructType status;

    @Override
    public ExpandednodeId getTypeId() {
        return TYPE_ID;
    }

    public ToxStructType(String foo,Integer bar,boolean baz,StatusstructType status) {
        this.foo = foo;
        this.bar = bar;
        this.baz = baz;
        this.status = status;
    }

    public ToxStructType() {
        this(null,false,new StatusstructType());
    }

    public static class Codec implements OpcuaBinaryDataTypeCodec<ToxStructType> {
        @Override
        public Class<ToxStructType> getType() {
            return ToxStructType.class;
        }

        @Override
        public ToxStructType decode(SerializationContext context,OpcuaBinaryStreamDecoder reader) throws UaSerializationException {
            String foo = reader.readString("foo");
            Integer bar = reader.readInt32("bar");
            boolean baz = reader.readBoolean("baz");
            Object statusstruct = reader.readStruct("status",new StatusstructType.Codec());
            StatusstructType statusstructure = new StatusstructType();
            if (statusstruct.getClass().isAssignableFrom(StatusstructType.class)) {
                statusstructure = (StatusstructType) statusstruct;
            }
            return new ToxStructType(foo,bar,baz,statusstructure);
        }

        @Override
        public void encode(SerializationContext context,OpcuaBinaryStreamEncoder writer,ToxStructType value) throws UaSerializationException {
            writer.writeString("foo",value.foo);
            writer.writeInt32("bar",value.bar);
            writer.writeBoolean("baz",value.baz);
            writer.writeStruct("status",value.status,StatusstructType.TYPE_ID);
        }
    }

}

StatusstructType.java:

package com.toxware.export.opcua.communication.server.util;

import org.eclipse.milo.opcua.stack.core.UaSerializationException;
import org.eclipse.milo.opcua.stack.core.serialization.OpcuaBinaryStreamDecoder;
import org.eclipse.milo.opcua.stack.core.serialization.OpcuaBinaryStreamEncoder;
import org.eclipse.milo.opcua.stack.core.serialization.SerializationContext;
import org.eclipse.milo.opcua.stack.core.serialization.UaStructure;
import org.eclipse.milo.opcua.stack.core.serialization.codecs.OpcuaBinaryDataTypeCodec;
import org.eclipse.milo.opcua.stack.core.types.builtin.ExpandednodeId;

import com.toxware.export.opcua.communication.server.ToxNamespaceDRX;

public class StatusstructType implements UaStructure {

    public static final ExpandednodeId TYPE_ID = ExpandednodeId.parse(String.format("nsu=%s;s=%s","DataType.StatusstructType"));

    public static final ExpandednodeId BINARY_ENCODING_ID = ExpandednodeId.parse(String.format("nsu=%s;s=%s","DataType.StatusstructType.BinaryEncoding"));

    String type = "txt_0";
    String text = "txt_1";
    String source = "txt_2";

    @Override
    public ExpandednodeId getTypeId() {
        return TYPE_ID;
    }

    public StatusstructType(String type,String text,String source) {
        this.type = type;
        this.text = text;
        this.source = source;

    }

    public StatusstructType() {
        this("","","");
    }

    public static class Codec implements OpcuaBinaryDataTypeCodec<StatusstructType> {
        @Override
        public Class<StatusstructType> getType() {
            return StatusstructType.class;
        }

        @Override
        public StatusstructType decode(SerializationContext context,OpcuaBinaryStreamDecoder reader) throws UaSerializationException {
            String type = reader.readString("type");
            String text = reader.readString("text");
            String source = reader.readString("source");
            return new StatusstructType(type,text,source);
        }

        @Override
        public void encode(SerializationContext context,StatusstructType value) throws UaSerializationException {
            writer.writeString("type",value.type);
            writer.writeString("text",value.text);
            writer.writeString("source",value.source);
        }
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

}

UAExpert Result / ErrorMessage

解决方法

我猜这个问题与 registerToxStructType() 中的 Identifiers.Structure 有关。但我不知道这里还应该使用什么。我希望那里的任何人都可以给我提示?

您应该使用标识 StatusStructType (StatusStructType.TYPE_ID) 的 NodeId。

我不知道这是否能完全解决您的问题,但这是一个很好的第一步。

,

现在可以了。解决方案是: 在 StructureField[] 字段定义中的函数 registerToxStructType() 中,我必须替换 标识符.结构 经过 StatusStructType.TYPE_ID.toNodeIdOrThrow(getServer().getNamespaceTable())