ANSI C Based OPC UA Client/Server/PubSub SDK  1.9.4.474
Handling structure DataTypes

The handling of structure DataTypes requires the creation of a DataType cache.

The necessary introduction for filling a DataType cache is provided by the introduction to OPC UA Data Types.

A value with a structure DataType can be used in variable values (Read/Write), method arguments and event fields. A received value must be decoded by the client following the DataType information provided in the StructureField descriptions. This information is retrieved from the type cache.

The SDK provides helper functions for decoding structure fields using the OpcUa_SimpleBinaryDecoder or for encoding structure fields using the OpcUa_SimpleBinaryEncoder.

The following pseudo sample code extends the Read example in Getting Started Lesson 1 for the Read Callback. The sample code shows how to detect a structure DataType, how to initialize the decoder and how to decode structure fields. The sample code does not include the type cache and is therefore not complete.

The extensions are marked with 'ADDED SAMPLE CODE FOR EXTENSION OBJECT'.

OpcUa_Void Sample_Read_CB(const UaClient_Session *a_pSession,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Int32 a_NoOfResults,
OpcUa_DataValue *a_pResults,
OpcUa_Int32 a_NoOfDiagnosticInfos,
OpcUa_DiagnosticInfo *a_pDiagnosticInfos,
OpcUa_Void *a_pUserData)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
OpcUa_ReferenceParameter(a_NoOfDiagnosticInfos);
OpcUa_ReferenceParameter(a_pDiagnosticInfos);
OpcUa_ReferenceParameter(a_pUserData);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Int32 i;
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Read_CB:\n");
for (i = 0; i < a_NoOfResults; i++)
{
char szSourceTimestamp[64] = {0};
char szServerTimestamp[64] = {0};
char szValue[64] = {0};
OpcUa_DateTime_GetStringFromDateTime(a_pResults[i].SourceTimestamp, szSourceTimestamp, sizeof(szSourceTimestamp));
OpcUa_DateTime_GetStringFromDateTime(a_pResults[i].ServerTimestamp, szServerTimestamp, sizeof(szServerTimestamp));
if (a_pResults[i].Value.Datatype != OpcUaType_ExtensionObject)
{
Variant_ToString(&a_pResults[i].Value, szValue, sizeof(szValue));
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " [%i]:\n", i);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Status: 0x%08x\n", a_pResults[i].StatusCode);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " SourceTimestamp: %s\n", szSourceTimestamp);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " ServerTimestamp: %s\n", szServerTimestamp);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Value: %s\n", szValue);
}
else
{
/* ADDED SAMPLE CODE FOR EXTENSION OBJECT BEGIN */
if (a_pResults[i].Value.ArrayType == OpcUa_VariantArrayType_Scalar &&
a_pResults[i].Value.Value.ExtensionObject != NULL &&
a_pResults[i].Value.Value.ExtensionObject->Encoding == OpcUa_ExtensionObjectEncoding_Binary)
{
OpcUa_SimpleBinaryDecoder binaryDecoder;
OpcUa_Double doubleValue = 0;
OpcUa_String stringValue;
OpcUa_String_Initialize(&stringValue);
/* Use the encoding ID to get the description of the structure from the type cache or from the server
a_pResults[i].Value.Value.ExtensionObject->TypeId.NodeId
*/
OpcUa_SimpleBinaryDecoder_Initialize(&binaryDecoder);
OpcUa_SimpleBinaryDecoder_Attach(
&binaryDecoder,
a_pResults[i].Value.Value.ExtensionObject->Body.Binary.Data,
a_pResults[i].Value.Value.ExtensionObject->Body.Binary.Length,
0);
/* Decode structure by using decoding functions for the data types in the structure description */
OpcUa_SimpleBinaryDecoder_ReadDouble(&binaryDecoder, &doubleValue);
OpcUa_SimpleBinaryDecoder_ReadString(&binaryDecoder, &stringValue);
OpcUa_SimpleBinaryDecoder_Clear(&binaryDecoder);
}
/* ADDED SAMPLE CODE FOR EXTENSION OBJECT END */
}
}
if (pClientContext->State == State_Read)
pClientContext->State = State_ReadDone;
else
pClientContext->State = State_Error;
}
else
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Read_CB failed (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}