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_Int32 a_NoOfResults,
OpcUa_Int32 a_NoOfDiagnosticInfos,
OpcUa_Void *a_pUserData)
{
SampleClientContext *pClientContext = a_pSession->
pUserData;
OpcUa_ReferenceParameter(a_NoOfDiagnosticInfos);
OpcUa_ReferenceParameter(a_pDiagnosticInfos);
OpcUa_ReferenceParameter(a_pUserData);
{
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
{
if (a_pResults[i].Value.ArrayType == OpcUa_VariantArrayType_Scalar &&
a_pResults[i].
Value.
Value.ExtensionObject != NULL &&
{
OpcUa_SimpleBinaryDecoder binaryDecoder;
OpcUa_Double doubleValue = 0;
OpcUa_String_Initialize(&stringValue);
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);
OpcUa_SimpleBinaryDecoder_ReadDouble(&binaryDecoder, &doubleValue);
OpcUa_SimpleBinaryDecoder_ReadString(&binaryDecoder, &stringValue);
OpcUa_SimpleBinaryDecoder_Clear(&binaryDecoder);
}
}
}
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;
}
}