Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
Structs returned as binary extension object
February 7, 2022
16:39, EET
Avatar
Sand0rf
Member
Members
Forum Posts: 6
Member Since:
January 21, 2022
sp_UserOfflineSmall Offline

Hi all,

For testing I’ve got a server that has a struct of structs as follows:
-superStruct (ns=4;i=257)
–stChildStructTD(ns=4;i=291)
—-variable1
—-variable2
—-extensionObject consisting of multiple items
—-…
–stChildStruct2(ns=4;i=310)
—-variable1
—-variable2
—-…
etc.

I’ve created a generic listener that will simply log the old value and the new value when a change was detected which I can add to any monitored data item. I’ve I set up a monitored data item on the extensionObject with the different items or any of the childStructs I get the expected results:
15:25:22 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@65036e8d] GenericNodeChangedListener [stChildStructTD (ns=4;i=291)] changed from DataValue(value=”OPC-DB5624-YCiPLC2ECS”.”stParentstruct”.”stChildStructTD” [tTimeMS=”5″, ltTimeNS=”25″, todTimeOfDay=”43932000″, dDate=”0″, ltodTimeOfDay=”0″, tdTimeAndDay=”8″, ldtTimeAndDay=”01/02/01 06:43:42.2514176 GMT”, tdlTimeAndDay=”DTL [YEAR=”2022″, MONTH=”2″, DAY=”7″, WEEKDAY=”2″, HOUR=”15″, MINUTE=”31″, SECOND=”46″, NANOSECOND=”3858880540″]”], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/07/22 14:23:31.2514531 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0) to DataValue(value=”OPC-DB5624-YCiPLC2ECS”.”stParentstruct”.”stChildStructTD” [tTimeMS=”5″, ltTimeNS=”25″, todTimeOfDay=”43932000″, dDate=”0″, ltodTimeOfDay=”0″, tdTimeAndDay=”8″, ldtTimeAndDay=”01/02/01 06:43:42.2514176 GMT”, tdlTimeAndDay=”DTL [YEAR=”2022″, MONTH=”2″, DAY=”7″, WEEKDAY=”2″, HOUR=”15″, MINUTE=”31″, SECOND=”41″, NANOSECOND=”3858880540″]”], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/07/22 14:23:32.2565732 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)

However when I set up a monitored data item on the parent super I receive (I think) a binary encoded variant:
15:31:04 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@16d41725] SuperStructChangedListener Super Struct values changed from DataValue(value=ExtensionObject [typeId=nsu=http%3A%2F%2FYCiPLC-YC-Client-OPCUA-Server;i=282, encodeType=Binary, object=[248] 0x000105000000190000000000000060599e020000000000000000000008000000900101000000000270e602362f1cd801e6070107020f1e0ae010050001ff7f7f0300ffffff7fffffffffffffff7fffff7f7fffffffffffffef7f0b000000537472696e67343b3235330c00000057537472696e67343b32353422430001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/07/22 14:28:21.2525232 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0) to DataValue(value=ExtensionObject [typeId=nsu=http%3A%2F%2FYCiPLC-YC-Client-OPCUA-Server;i=282, encodeType=Binary, object=[248] 0x000105000000190000000000000060599e020000000000000000000008000000900101000000000270e602362f1cd801e6070107020f1e14e010050001ff7f7f0300ffffff7fffffffffffffff7fffff7f7fffffffffffffef7f0b000000537472696e67343b3235330c00000057537472696e67343b32353422430001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/07/22 14:29:14.2520679 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)

When I try to decode this value to a structure using “this.uaClient.getTypeDictionary().decode((ExtensionObject) newValue.getValue().getValue());” an error is thrown: Bad_DecodingError (code=0x80070000, description=”Unexpected string length -8421377″)

I don’t need to do any transforming for all other listeners and they are added to the subscription of the UaClient in the same way. Is there a limit on structs of structs when using monitored data items or am I missing something here?

Thanks in advance

February 8, 2022
15:19, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1032
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

What version of the SDK do you use (please also try with 4.7.2, that we just released today, since it fixed one case which might help here)? Do you use our SDK also for the server? If not, can you say anything what server it is (e.g. is it a Siemens S7 PLC for example)?

Do you have a DataTypeDefinition (the 1.04 new Attribute) of that “superStruct” to show? i.e. specifically which NodeIds you have used for the fields? Are any of the fields multidimensional arrays?

In general, assuming most scenarios and SDK defaults and more recent 4.x SDK versions, SDK would have already decoded any ExtensionObject to Structures for DataValue if it can do that (i.e. it is very rare that it would need to be done manually or that it would work in the case where the automatic logic would not have worked). The error message means something is wrong with the binary data, as it received a negative String length (of something else than -1, which would have been null string). So either the StructureSpecification for the type (note the TypeId is an encoding id, not the DataType node itself, but a sub encoding node of it) is wrong or the data is wrong. SDK can receive the StructureSpecification in 3 ways: code-generation (if the Codegen that comes with the SDK is used for the model, only useful if you know the models beforehand and the app is designed for those models), DataTypeDefinition Attribute of the Structure DataType or the old DataTypeDictionaries (which was how structure metadata was defined before 1.04). All these are given by the server, so it depends entirely on it to provide proper values.

Since you specifically say “extensionObject consisting of multiple items” as in “ExtensionObject” and not a “Structure”, the rest of this post is to first ensure correct expectations. Depending on what you meant, it might not be relevant, but this is to doublecheck.

“ExtensionObject” and “Structure” .. sort of mean different things in this context. It is extremely important to be exact. OPC UA 1.04.10 (errata) introduced new Structure kinds, but in general I’m going to assume those are not used here. Just note that the following is sort of written from the perspective that they are not a thing.

Is the DataType of “extensionObject consisting of multiple items” exactly i=22 i.e. the raw “Structure” DataType or any subtype of it?

IF IT IS exactly i=22, it will have special encoding rules that a real ExtensionObject binary form is used to encode the field (so while there is no DataType per se for ExtensionObject, the i=22 means that). Only the ExtensionObject encoding form has type information. This is basically used in ServiceRequest parameters where a subtype of a Structure is expected, such as HistoryReadRequest historyReadDetails parameter, since it depends on what kind of history is being read. This is the 1 of 2 special ways to encode subtype data in a Structure field.

IF IT IS NOT exactly i=22, then it uses the rules of having a nested structure in a field: https://reference.opcfoundation.org/Core/docs/Part6/5.2.6/. This is to say, the fields of the structure as a field are taken “as is” they would be defined in the structure where the field is. Basically they are put “as-is” in the binary stream. There is no type information, as that is conveyed already by the parent structure. Basically, if you have a Structure-typed field in a Structure, you cannot use any subtype of that Structure there (decode could not know which one of them it would be as there is no prefix, just the fields). Also, you cannot in practice have abstract types in the fields (e.g. numeric types have different byte-lengths, decode again would not know how many bytes to take). The only exception is the types i=22 and i=24. The i=24 is the BaseDataType and that too has a special form: Variant will be encoded there (which can convey type information, and pretty much any value can be given).

P.S.
Subtypes of OptionSet Structure wont work yet with the SDK. Will be added at some point in the future hopefully soon depending on need.

P.S.2
OPC UA 1.04.10 information model added 2 new kinds of Structures, where you could actually use abstract types in the fields with other datatypes than just i=22 and i=24, but in general as they are … very new I would expect you are not using them. Also, since they can only be understood by 1.04.10+ Clients, I would not recommend to use them .. without caution.

February 8, 2022
15:25, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1032
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

P.S.3.
Also, do you see INFO level log on class TypeDictionary “TypeDictionary initialized successfully” or WARN level on UaClient class “Could not init TypeDictionary, decoding custom Structures might not work”. If the latter, DEBUG level logs on both classes could maybe tell why. Though, in general I would expect a different error on the decode attempt if it was the latter, so maybe it is not that.

February 9, 2022
11:47, EET
Avatar
Sand0rf
Member
Members
Forum Posts: 6
Member Since:
January 21, 2022
sp_UserOfflineSmall Offline

Hi,
Thanks for your extensive reply. I’ve upgraded the SDK to version 4.7.2-13 but that didn’t resolve the issue. I’m using a Siemens S7 PLC as server which is programmed by one of the engineers of the customer. We’re evaluating the SDK for further use and still figuring out items while testing so we might do certain things the wrong way.

When I’m trying to get the structure specification using this.uaClient.getTypeDictionary().getStructureSpecification(UaNodeId.fromLocal(new NodeId(4, 283), this.uaClient.getNamespaceTable())) I got a NULL response. The complete structure is as follows (From UAExpert):

[NS4|Numeric|283] – stSuperStruct – ExtensionObject
-[NS4|Numeric|321] – stChildStructAscii – ExtensionObject
–[NS4|Numeric|322] – strString – String
–[NS4|Numeric|323] – wstrWString – String
–[NS4|Numeric|324] – cChar – Byte
–[NS4|Numeric|325] – wcWChar – UInt16
-[NS4|Numeric|310] – stChildStructNumbers – ExtensionObject
–[NS4|Numeric|311] – bByte8 – Byte
–[NS4|Numeric|312] – iInteger16 – Int16
–[NS4|Numeric|313] – siSInteger – SByte
–[NS4|Numeric|314] – uiUInteger16 – UInt16
–[NS4|Numeric|315] – diDoubleInteger32 – Int32
–[NS4|Numeric|316] – liLongInteger64 – Int64
–[NS4|Numeric|317] – rReal32 – Float
–[NS4|Numeric|318] – lrReal64 – Double
-[NS4|Numeric|291] – stChildStructTD – ExtensionObject
–[NS4|Numeric|292] – tTimeMS – Int32
–[NS4|Numeric|293] – ltTimeNS – Int64
–[NS4|Numeric|294] – todTimeOfDay – UInt32
–[NS4|Numeric|295] – dDate – UInt16
–[NS4|Numeric|296] – ltodTimeOfDay – UInt64
–[NS4|Numeric|297] – tdTimeAndDay – Byte
–[NS4|Numeric|298] – ldtTimeAndDay – DateTime
–[NS4|Numeric|299] – tdTimeAndDay– ExtensionObject (Array of 8 byte values)
-[NS4|Numeric|286] – stChildStructBool – ExtensionObject
–[NS4|Numeric|287] – xStatus – Boolean
–[NS4|Numeric|288] – xToggle – Boolean
-[NS4|Numeric|328] – stOpcUaAllowedDataTypes – ExtensionObject
–[NS4|Numeric|329] – bool – Boolean
–[NS4|Numeric|330] – sInt – SByte
–[NS4|Numeric|331] – int – Int16
–[NS4|Numeric|332] – dInt – Int32
–[NS4|Numeric|333] – lInt – Int64
–[NS4|Numeric|334] – uSInt – Byte
–[NS4|Numeric|335] – uInt – UInt16
–[NS4|Numeric|336] – uDInt – UInt32
–[NS4|Numeric|337] – uLInt – UInt64
–[NS4|Numeric|338] – real – Float
–[NS4|Numeric|339] – lReal – Double
–[NS4|Numeric|340] – ldt – DateTime
–[NS4|Numeric|341] – wString – String
–[NS4|Numeric|342] – opcUaNodeId – NodeId
–[NS4|Numeric|346] – opcUaQualifiedName – QualifiedName
–[NS4|Numeric|351] – myUnion – typeUnionMyDatatype
–[NS4|Numeric|358] – locText – typeOpcUaLocalizedText
–[NS4|Numeric|364] – myByteString – typeOpcUaByteString (Byte Array[12])

So there is at least one byte array but when I create the monitored data item on that extension object (NS4|Numeric|299) or the parent of that value (NS4|Numeric|291) I get the expected result.

The following logging is generated at startup (Removed/abbreviated some sensitive data):
2022-02-09 10:08:54,263 INFO [1 main] com.prosysopc.ua.ApplicationIdentity Creating a new application certificate & private key
2022-02-09 10:08:55,414 INFO [1 main] com.prosysopc.ua.ApplicationIdentity Created a new Certificate: O=, CN=@; ApplicationURI=urn: :OPCUA: KeySize=2048
2022-02-09 10:08:55,422 INFO [1 main] com.prosysopc.ua.stack.utils.CryptoUtil Using CryptoProvider com.prosysopc.ua.stack.transport.security.BcCryptoProvider
2022-02-09 10:08:55,559 INFO [1 main] com.prosysopc.ua.stack.transport.tcp.io.TcpConnection Connecting
2022-02-09 10:08:55,799 INFO [1 main] com.prosysopc.ua.stack.transport.tcp.io.TcpConnection Connected (non-reverse), handshake completed, local=/10.0.5.144:60709, remote=
2022-02-09 10:08:56,079 INFO [1 main] com.prosysopc.ua.stack.transport.tcp.io.SecureChannelTcp 550896255 Closed
2022-02-09 10:08:56,080 INFO [1 main] com.prosysopc.ua.stack.transport.tcp.io.TcpConnection Closed
2022-02-09 10:08:56,080 INFO [37 TcpConnection/Read] com.prosysopc.ua.stack.transport.tcp.io.TcpConnection Closed (expected)
2022-02-09 10:08:56,082 INFO [1 main] com.prosysopc.ua.client.UaClient Using an alternate endpoint URL ‘opc.tcp://192.168.1.44:36500’ instead of the requested ‘opc.tcp:// ‘
2022-02-09 10:08:56,086 INFO [1 main] com.prosysopc.ua.stack.transport.tcp.io.TcpConnection Connecting
2022-02-09 10:08:56,243 INFO [1 main] com.prosysopc.ua.stack.transport.tcp.io.TcpConnection Connected (non-reverse), handshake completed, local=/10.0.5.144:60710, remote=
2022-02-09 10:09:00,531 WARN [1 main] com.prosysopc.ua.client.UaClient Could not Read OperationLimit: Server/ServerCapabilities/OperationLimits/MaxNodesPerHistoryReadData with NodeId: i=12165, either the server does not have the node or the read didn’t return a Good value that can be interpreted as UnsignedInteger, value was: DataValue(value=(null), statusCode=Bad_NodeIdUnknown (0x80340000) “The node id refers to a node that does not exist in the server address space.”, sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), using default value of 4294967295 instead (note that this will be overriden by clientside limits if lower)
2022-02-09 10:09:00,532 WARN [1 main] com.prosysopc.ua.client.UaClient Could not Read OperationLimit: Server/ServerCapabilities/OperationLimits/MaxNodesPerHistoryReadEvents with NodeId: i=12166, either the server does not have the node or the read didn’t return a Good value that can be interpreted as UnsignedInteger, value was: DataValue(value=(null), statusCode=Bad_NodeIdUnknown (0x80340000) “The node id refers to a node that does not exist in the server address space.”, sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), using default value of 4294967295 instead (note that this will be overriden by clientside limits if lower)
2022-02-09 10:09:00,532 WARN [1 main] com.prosysopc.ua.client.UaClient Could not Read OperationLimit: Server/ServerCapabilities/OperationLimits/MaxNodesPerHistoryUpdateData with NodeId: i=12167, either the server does not have the node or the read didn’t return a Good value that can be interpreted as UnsignedInteger, value was: DataValue(value=(null), statusCode=Bad_NodeIdUnknown (0x80340000) “The node id refers to a node that does not exist in the server address space.”, sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), using default value of 4294967295 instead (note that this will be overriden by clientside limits if lower)
2022-02-09 10:09:00,532 WARN [1 main] com.prosysopc.ua.client.UaClient Could not Read OperationLimit: Server/ServerCapabilities/OperationLimits/MaxNodesPerHistoryUpdateEvents with NodeId: i=12168, either the server does not have the node or the read didn’t return a Good value that can be interpreted as UnsignedInteger, value was: DataValue(value=(null), statusCode=Bad_NodeIdUnknown (0x80340000) “The node id refers to a node that does not exist in the server address space.”, sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), using default value of 4294967295 instead (note that this will be overriden by clientside limits if lower)
2022-02-09 10:09:00,532 WARN [1 main] com.prosysopc.ua.client.UaClient Could not Read OperationLimit: Server/ServerCapabilities/OperationLimits/MaxNodesPerNodeManagement with NodeId: i=11713, either the server does not have the node or the read didn’t return a Good value that can be interpreted as UnsignedInteger, value was: DataValue(value=(null), statusCode=Bad_NodeIdUnknown (0x80340000) “The node id refers to a node that does not exist in the server address space.”, sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), using default value of 4294967295 instead (note that this will be overriden by clientside limits if lower)
2022-02-09 10:09:00,533 INFO [1 main] com.prosysopc.ua.client.UaClient Using OperationLimits [maxMonitoredItemsPerCall=1000, maxNodesPerBrowse=1000, maxNodesPerHistoryReadData=10000, maxNodesPerHistoryReadEvents=10000, maxNodesPerHistoryUpdateData=10000, maxNodesPerHistoryUpdateEvents=10000, maxNodesPerMethodCall=1, maxNodesPerNodeManagement=10000, maxNodesPerRead=1000, maxNodesPerRegisterNodes=1000, maxNodesPerTranslateBrowsePathsToNodeIds=1000, maxNodesPerWrite=1000]
2022-02-09 10:09:14,083 INFO [1 main] com.prosysopc.ua.typedictionary.TypeDictionary TypeDictionary initialized successfully
2022-02-09 10:09:14,086 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.OpcServerStatusMonitor Server state change to: Running

I do receive some warnings but I don’t think they cause these issues, the type dictionary is initialized successfully. Afterwards I get events that all child structures change value from null to an object (The null check is done by myself on the parameter oldValue in the listener):

2022-02-09 10:09:14,455 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.GenericNodeChangedListener [stChildStructTD (ns=4;i=291)] changed from NULL to DataValue(value=”OPC-DB5624-YCiPLC2ECS”.”stSuperstruct”.”stChildStructTD” [tTimeMS=”5″, ltTimeNS=”25″, todTimeOfDay=”43932000″, dDate=”0″, ltodTimeOfDay=”0″, tdTimeAndDay=”8″, ldtTimeAndDay=”01/02/01 06:43:42.2514176 GMT”, tdlTimeAndDay=”DTL [YEAR=”0″, MONTH=”2″, DAY=”48″, WEEKDAY=”250″, HOUR=”80″, MINUTE=”63″, SECOND=”143″, NANOSECOND=”3858880541″]”], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.4980586 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)
2022-02-09 10:09:14,456 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.GenericNodeChangedListener [stChildStructAscii (ns=4;i=321)] changed from NULL to DataValue(value=”OPC-DB5624-YCiPLC2ECS”.”stSuperstruct”.”stChildStructAscii” [strString=”String4;253″, wstrWString=”WString4;254″, cChar=”34″, wcWChar=”67″], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.5034563 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)
2022-02-09 10:09:14,457 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.GenericNodeChangedListener [stChildStructNumbers (ns=4;i=310)] changed from NULL to DataValue(value=”OPC-DB5624-YCiPLC2ECS”.”stSuperstruct”.”stChildStructNumbers” [bByte8=”1″, iInteger16=”32767″, siSInteger=”127″, uiUIntegr16=”3″, diDoubleInteger32=”2147483647″, liLongInteger64=”9223372036854775807″, rReal32=”3.4028235E38″, lrReal64=”1.7976931348623157E308″], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.5085157 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)
2022-02-09 10:09:14,458 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.GenericNodeChangedListener [stChildstructBool (ns=4;i=286)] changed from NULL to DataValue(value=”OPC-DB5624-YCiPLC2ECS”.”stSuperstruct”.”stChildstructBool” [xToggle=”false”, xStatus=”true”], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.5135772 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)
2022-02-09 10:09:14,460 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.GenericNodeChangedListener [stOpcUaAllowedDataTypes (ns=4;i=328)] changed from NULL to DataValue(value=typeOpcUaAllowedDataTypes [bool=”true”, sInt=”0″, int=”0″, dInt=”0″, lInt=”0″, uSInt=”0″, uInt=”0″, uDInt=”0″, uLInt=”0″, real=”0.0″, lReal=”0.0″, ldt=”01/01/01 00:00:00.0000000 GMT”, wString=””, opcUaNodeId=”i=0″, opcUaQualifiedName=””, myUnion=”typeUnionMyDatatype [selector=”0″, name=””, number=”0″, time=”01/01/01 00:00:00.0000000 GMT”]”, locText=”typeOpcUaLocalizedText [encodingByte=”0″, locale=””, text=””]”, myByteString=”typeOpcUaByteString [byteString=”[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]”]”, guid=”typeOpcUaGuid [data1=”0″, data2=”0″, data3=”0″, data4=”0″]”], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.5190476 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)
2022-02-09 10:09:14,461 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.GenericNodeChangedListener [tdlTimeAndDay (ns=4;i=299)] changed from NULL to DataValue(value=DTL [YEAR=”2022″, MONTH=”1″, DAY=”9″, WEEKDAY=”4″, HOUR=”9″, MINUTE=”30″, SECOND=”8″, NANOSECOND=”802000″], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.5249759 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)

But a listener on the super struct gives the binary format:

2022-02-09 10:09:14,451 INFO [46 PublishTask-com.prosysopc.ua.client.UaClient@5a7b6b75] n.i.p.e.c.c.p.o.SuperStructChangedListener Super Struct values changed from NULL to DataValue(value=ExtensionObject [typeId=nsu=http%3A%2F%2FYCiPLC-YC-Client-OPCUA-Server;i=282, encodeType=Binary, object=[248] 0x000105000000190000000000000060599e020000000000000000000008000000900101000000000230fa503f8f1dd801e607010904091e08d03c0c0001ff7f7f0300ffffff7fffffffffffffff7fffff7f7fffffffffffffef7f0b000000537472696e67343b3235330c00000057537472696e67343b32353422430001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000], statusCode=GOOD (0x00000000) “The operation succeeded.”, sourceTimestamp=02/09/22 09:07:09.4921171 GMT, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)

February 10, 2022
13:20, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1032
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Structure problems tend to be like this, hard to debug. Also, too many things to comment on for a single post, and even this one is kinda long.

Those OperationLimits warnings can be ignored, it has been a bit unclear part of the spec (we assumed 0 is unlimited, but apparently it should be really not supported at all -indicator). But those are just history read etc. operation related, which doesn’t matter here. If there was some other warnings than those it would be good to see.

So, let’s start why the StructureSpecification is not found. That is odd. While not very descriptive, you should have gotten something like “cannot decode null” or equivalent DecodingException if it cannot be found. Basically everything works of StructureSpecifications nowadays, but the code still delegates to old Class-based serializer system as a fallback. That was used with our code generation before we had a dynamic system in place with TypeDictionary+StructureSpecifications (and generated StructureSpecifications would still use the serializer anyway).

I’m assuming you are not using our codegeneration on the model here? (like, no need and probably better not to in this case, but just ruling out things).

Assuming the namespaceindex 4 is correct here, i.e. check that NamespaceArray index 4 is “http%3A%2F%2FYCiPLC-YC-Client-OPCUA-Server” (in plain, without the %3 etc. i.e. normal uri).

Technically it would be more proper to ask the StructureSpecification with the encoding id, not the type id. But TypeDictionary should be happy with both, but just a note that it is the “Default Binary” node below a DataType node, which is used in the ExtensionObjects. Note that node is linked with the HasEncoding reference type, which is not hierarchical, so it wont be visible in normal tree-like-views. In our https://www.prosysopc.com/products/opc-ua-browser/ we have a toggle to also show non-hierarchical references in the tree, but you can also see them in References views typically. So the proper encoding type here is “nsu=http%3A%2F%2FYCiPLC-YC-Client-OPCUA-Server;i=282” i.e. new NodeId(4,282) NOT new NodeId(4,283), but as said, that should have worked regarding TypeDictionary, so it is odd (assuming the “from UaExpert” “[NS4|Numeric|283] – stSuperStruct” showed it properly).

Technically it could happen if TypeDictionary.init is not called, but assuming defaults SDK will call this automatically as part of UaClient.connect(). I’m assuming you are not adding that type dynamically to the server after that (there is TypeDictionary.refresh() for that case, also if the server supports the 1.04 DataTypeDefinition Attribute, those are automatically resolved if unknown types are encountered). Yes, it would make sense for the getStructureSpecification, maybe someday it works like that (but for now it would be infinite loop during connection). And as said above, not having it during decoding would have given you a different exception.

February 10, 2022
13:29, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1032
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Then for the “it is S7 PLC” part.

Previously there has been some problems at least with Siemens S7-1200 and S7-1500 PLCs where a firmware update has fixed them. At least in one case, things seemed to work with UaExpert, but the data was still incorrect per OPC UA specification. UaExpert just happened to ignore some length prefixes for some known types. While that should not be related to your case, it would be still a good idea to check is there a firmware update for the PLC.

Our design cannot ignore those prefixes, even known Structures still proces things in a generic way without “magically skipping” some data from the binary stream.

However I do note that we should improve our error messages, as now I cannot know in which stage of the decoding the incorrect length was encountered (I can however take a guess as there isn’t that many String fields).

February 10, 2022
13:35, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1032
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Then “some things are odd in the types of your structure” general notes, part 1:

That looks a lot like a “test structure” that tries to use every possible type. This is in general fine.

However at least the “typeOpcUaByteString” and “typeOpcUaLocalizedText” look odd. The DataValue tostring “locText=”typeOpcUaLocalizedText [encodingByte=”0″, locale=””, text=””]” would … look like more of a Structure “toString” than what the OPC UA type LocalizedText would show (it should be “(localeid) textpart” not a “map-like” output). Same with the ByteString (it should show it as HEX). I do not exactly have that much experience with TIA Portal etc. stuff, but I would kinda assume the builtin types LocalizedText and ByteString would be “natively” useable. IF you have made custom structures that try to look like them, this is the wrong way and would confuse users of that Server (as the builtin types have special encodings, see https://reference.opcfoundation.org/Core/docs/Part6/).

Also, our forum’s formatting options are not that good, so this might be incorrent note, but I see “tdTimeAndDay” two times “tdTimeAndDay – Byte” and “tdTimeAndDay– ExtensionObject (Array of 8 byte values)”. The field names must be unique in OPC UA. While technically it _could_ appear to work specifically for Binary encodings, it would not for example JSON encodings. Also, any data from any duplicated name would be lost in the SDK’s DynamicStructure, as data is stored in a name-based Map.

February 10, 2022
13:57, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 1032
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Then “some things are odd in the types of your structure” general notes, part 2:

I would need to see the DataTypeDefinition Attribute value for the super structure DataType node. Assuming UaExpert is of any recent version, you should see this Attribute in the Attributes view. Or use our Browser (https://www.prosysopc.com/products/opc-ua-browser/) application (it is a generic client, like UaExpert is). Or doublecheck it has the same contents of types and fields you showed in previous posts. Also, note that the “node-hierarchy” of subnodes have parts of a larger structure is … a convention, but not exactly a rule per se in OPC UA that would always apply. So basically every node is their individual node with their individual data OPC UA-wise at least (what happens in the server might be different). Also S7 servers use a custom convention for array data. Please doublecheck was any of the fields a multidimensional array (per your post I assume not), but the old datatypedictionaries cannot represent those (the encoding was defined in 1.04, it is not “emulate-able” via dictionary rules).

It is possible, that there is no DataTypeDefinition value and it would show invalid attribute instead. This would mean the server doesn’t support it. Though, I’m not 100% certain, but I would assume S7 to have them, if enough new firmware is in place. And if you have older than that, then most likely it can have all the possible S7 problems anyway, thus updating the firmware would be what I would try next.

IF they would _still_ not be DataTypeDefinition Attribute values for the Structure DataType nodes OR if connected any other server which is pre OPC UA 1.04, I would need to see the DataTypeDictionaries. They are complicated (which is why OPC Foundation made the new Attribute in 1.04). Our Browser version 4.1.0 has a context menu entry to show that, r-click on all nodes below Types/DataTypes/OPC Binary/* and select “View DataTypeDictionary data…” (technically this entry appears for all nodes of DataTypeDictionaryType). However, if we get to this point, most likely we would need to continue by email (which technically is not part of the eval support, though some cases just are not that good to be pasted here in the forum, and the dictionaries are huge XML documents as UTF-8 as ByteString).

Now.. IF it would be DataTypeDictionary-based Structure and not DataTypeDefinition-based one, there is a very deep rabbit hole to explain, which preferably should be avoided. But in short, the dictionary system can be though of a more general one, and then the Part 6 encoding rules are … sort of separate, but you can explain all Part 6 rules (pre 1.04-rules at least!) with dictionary rules. However, dictionary has … encodings that cannot be “represented in OPC UA” (my opinion). And they would not be representable via DataTypeDefinition (which basically uses Part 6 rules, basically the rules that matter). Also the datatypedictionary is deprecated in OPC UA 1.05 (some parts for that version have already been released).

The old dictionaries used to have 4 different String types: CharArray, String, WideCharArray and WideString. Of these the CharArray was the equivalent of Part6-String. Dictionary-strings were null-terminated and CharArrays length-prefix. Part 6 String is length-prefixed. So the OPC Foundation decided to errata the dictionary types, now there is only String and WideString, and they are length-prefixed. But! Part 6 still doesn’t have a WideString type. There is no such DataType node nor a builtin type or encoding rules in Part6. So, a DataTypeDefinition cannot represent that type at all, so in my mind it does not exist. And the way SDK does work is that dictionary data is intepreted as-if it would be “part 6 rules capabable” as there was no other practical way. But it is possible that UaExpert could support those other string types (but might still display “String” for them, as there is no node for them). Our custom Structure handling is much newer than UaExpert’s.

But for the time being, I would consider this more as “OPC UA trivia” and hopefully this was not related. But, in your post I did see I can see “strString – String” and “wstrWString – String”. So I cannot be certain about that. Also it is possible that the S7 properly maps both (IF there was a WideString PLC type) to OPC UA Part6-String.

February 15, 2022
12:08, EET
Avatar
Sand0rf
Member
Members
Forum Posts: 6
Member Since:
January 21, 2022
sp_UserOfflineSmall Offline

Thanks for your extensive reply. We’ve updated the structure and updated the firmware of the Siemens PLC and now everything works as expected. Thanks your time!

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 1919

Currently Online:
12 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Heikki Tahvanainen: 402

hbrackel: 144

rocket science: 88

pramanj: 86

Francesco Zambon: 83

Ibrahim: 78

Sabari: 62

kapsl: 57

gjevremovic: 49

Xavier: 43

Member Stats:

Guest Posters: 0

Members: 728

Moderators: 7

Admins: 1

Forum Stats:

Groups: 3

Forums: 15

Topics: 1529

Posts: 6471

Newest Members:

ellis87832073466, zkxwilliemae, gabriellabachus, Deakin, KTP25Zof, Wojciech Kubala, efrennowell431, wilfredostuart, caitlynfajardo, jeromechubb7

Moderators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1032, Jimmy Ni: 26, Matti Siponen: 349, Lusetti: 0

Administrators: admin: 1