Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read complex structure #198

Open
friko16 opened this issue Jan 19, 2020 · 2 comments
Open

Read complex structure #198

friko16 opened this issue Jan 19, 2020 · 2 comments

Comments

@friko16
Copy link

friko16 commented Jan 19, 2020

Can someone help ? I am sitting on this for days and can't figure out how to read a non-leaf, complex data structure:


 ReadValueId[] nodesToRead = new ReadValueId[1];
 NodeId nodeId = new NodeId(3, "\"Trace\".\"DataRead\".\"TP\"[0]");
 nodesToRead[i] = new ReadValueId(nodeId, Attributes.Value, null,null);
 ReadRequest req = new ReadRequest(null, maxAge, TimestampsToReturn.Both, nodesToRead);
 ReadResponse res = connection.getSession().Read(req);

this data structure when viewed in UAExpert expands into multiple leaf nodes with String and boolean leafs.

and I am getting and exception:

Exception in thread "main" org.opcfoundation.ua.common.ServiceResultException: Bad_InternalError (code=0x80020000, description="2147614720, namespaceUri; value=TE_"Trace"."DataRead"."TP"")
	at org.opcfoundation.ua.transport.tcp.io.TcpConnection$ReadThread.run(TcpConnection.java:1193)
Caused by: java.lang.NullPointerException: namespaceUri; value=TE_"Trace"."DataRead"."TP"
	at org.opcfoundation.ua.builtintypes.ExpandedNodeId.<init>(ExpandedNodeId.java:204)
	at org.opcfoundation.ua.common.NamespaceTable.toExpandedNodeId(NamespaceTable.java:106)
	at org.opcfoundation.ua.encoding.binary.BinaryDecoder.getExtensionObject(BinaryDecoder.java:970)
	at org.opcfoundation.ua.encoding.binary.BinaryDecoder.getScalarObject(BinaryDecoder.java:1436)
	at org.opcfoundation.ua.encoding.binary.BinaryDecoder.getVariant(BinaryDecoder.java:1659)
	at org.opcfoundation.ua.encoding.binary.BinaryDecoder.getDataValue(BinaryDecoder.java:651)
	at org.opcfoundation.ua.encoding.binary.BinaryDecoder.getDataValueArray(BinaryDecoder.java:674)
	at org.opcfoundation.ua.core.EncodeableSerializer$171.getEncodeable(EncodeableSerializer.java:4491)
	at org.opcfoundation.ua.encoding.utils.AbstractSerializer.getEncodeable(AbstractSerializer.java:197)
	at org.opcfoundation.ua.encoding.utils.SerializerComposition.getEncodeable(SerializerComposition.java:104)
	at org.opcfoundation.ua.encoding.binary.BinaryDecoder.getMessage(BinaryDecoder.java:1255)
	at org.opcfoundation.ua.transport.tcp.io.TcpConnection$ReadThread.run(TcpConnection.java:1115)

with UAExpert tool, I can read that node with no problems and all it's leafs.
opcua.1.4.1.jar

I have read in other issue that I need to read namespaceArray and set is as context, but have no idea how to set it, neither are there examples for that.
please help.

@jouniaro
Copy link
Contributor

Decoding custom structure types is not supported by default by the stack. You will need to register your own serialiser for the type, which requires that you know the structure a priori. See the existing implementations for the standard structure types generated inside the EncodeableSerializer class for examples.

In order to support any previously unknown structure in the client, you will need to parse the TypeDictionary provided by the server. That functionality is out of the scope of the stack and you will need an SDK for that or build it yourself.

@friko16
Copy link
Author

friko16 commented Aug 9, 2020

Thanks for response, @jouniaro . It's been a long time, I gave up on this problem, but now it came back and trying to solve it again.
The reason I am trying to read the whole structure at once is that now I am passing a list of ~30 ReadValueIds to sessionChannel.Read() and the read takes around 200-300ms. The 30 values is a list of primitive opc types being part of a larger structure. To give you a glimpse of it, I am attaching print screen from UaExpert tool for browsing plc:
Screenshot from 2020-08-09 07-31-45.
Why does the read take so long ?
this is how I do it:

String[] nodePaths = ...// initialized list of string nodeId's e.g. "DB_601_Trace_OPC.Read.TP[0].Value"    
int namespaceIdx = 3;
for (int i = 0; i < nodePaths.length; i++) {
    NodeId nodeId = new NodeId(namespaceIdx, nodePaths[i]);
    nodesToRead[i] = new ReadValueId(nodeId, Attributes.Value, null,null);
 }
ReadRequest req = new ReadRequest(null, maxAge, TimestampsToReturn.Neither, nodesToRead);
ReadResponse res = connection.getSession().Read(req);

This is unbearable for my requirements, I thought reading the whole structure's root will help. I have tested reading a whole structure with node's opcua parallel project (https://node-opcua.github.io/) and the read takes 20-30 ms for whole structure, and no serializaers/desarializers registration is needed, just pure JSON returned.

I have tried a bit with those structure serializers:

    private static class MachineType extends AbstractStructure {

        public static final ExpandedNodeId ID = new ExpandedNodeId(new NodeId(3, NodePath.dataMachine(0)));
        public static final ExpandedNodeId BINARY = new ExpandedNodeId(new NodeId(3, NodePath.dataMachine(0)));
        public static final ExpandedNodeId XML = new ExpandedNodeId(new NodeId(3, NodePath.dataMachine(0)));

        public ExpandedNodeId getTypeId() {
            return ID;
        }

        public ExpandedNodeId getXmlEncodeId() {
            return XML;
        }

        public ExpandedNodeId getBinaryEncodeId() {
            return BINARY;
        }
    }

    private void customStructure(ConnectionHandler connection) {

        EncodeableSerializer ser = EncodeableSerializer.getInstance();

        ser.addSerializer(new AbstractSerializer(MachineType.class, MachineType.BINARY, MachineType.XML, MachineType.ID) {
            public void calcEncodeable(IEncodeable encodeable, IEncoder calculator) throws EncodingException {
                MachineType obj = (MachineType) encodeable;
// ENCODING COMMENTED OUT FOR NOW...
//                calculator.putQualifiedName(null,  (obj==null)?null:obj.getKey() );
//                calculator.putVariant(null,  (obj==null)?null:obj.getValue() );
            }
            public void putEncodeable(IEncodeable encodeable, IEncoder encoder) throws EncodingException {
// ENCODING COMMENTED OUT FOR NOW...
//                encoder.putQualifiedName("Key",  (obj==null)?null:obj.getKey() );
//                encoder.putVariant("Value",  (obj==null)?null:obj.getValue() );
            }
            public IEncodeable getEncodeable(IDecoder decoder) throws DecodingException {
                MachineType result = new MachineType();
                QualifiedName qn = decoder.getQualifiedName("Key");
                Variant var = decoder.getVariant("Value");
                return result;
            }
        });
    }

but getting an error:

Exception in thread "Thread-0" java.lang.IllegalArgumentException: Only ExpandedNodeIds that contain the URI are allowed as parameter
	at org.opcfoundation.ua.encoding.utils.AbstractSerializer.fixAndValidateId(AbstractSerializer.java:58)
	at org.opcfoundation.ua.encoding.utils.AbstractSerializer.<init>(AbstractSerializer.java:107)
	at org.opcfoundation.ua.encoding.utils.AbstractSerializer.<init>(AbstractSerializer.java:88

Can some one help, as this is a huge limiter for us and prohibits completing the project.
The solution can be either reading a list of NodeIs as of now, but speed it up to ~30ms, or solving the read speed by reading the whole structure at once. If reading the whole structure help with read speed, I don't expect someone to provide full implementation of Structure and Serializers, but some pseudo-code would help, doesn't have to compile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants