Issues with setting even field with custom DataType

Questions regarding the use of the ANSI C SDK for Server or Client development or integration into customer products ...

Moderator: uasdkc

Post Reply
JeromeBos
Sr. Member
Sr. Member
Posts: 14
Joined: 09 May 2016, 15:31

Issues with setting even field with custom DataType

Post by JeromeBos »

I'm having issues setting an event field with a custom DataType.

Model of the DataType:

Code: Select all

Types
|- DataTypes
|  |- BaseDataType
|  |  |- Structure
|  |  |  |- CustomDataType
|  |  |  |  |- CustomArray [ArrayOfFloat]
Model of the EventType:

Code: Select all

Types
|- EventTypes
|  |- BaseEventType
|  |  |- CustomEventType
|  |  |  |- CustomData (TypeDefinition=CustomDataType, ValueRank=Array, ArrayDimensions=0)
|  |  |  |  |- CustomArray
UaModeler generates the following function to set the CustomData event field:

Code: Select all

OpcUa_StatusCode UaProvider_CustomProvider_Events_Set_CustomEventType_CustomData(
    UaServer_Event *a_pEvent,
    OpcUa_Int32 a_iNoOfValues,
    CustomProvider_CustomDataType *a_pValues)
{
    OpcUa_Variant *pValue = OpcUa_Null;
    OpcUa_Int32 i = 0;

OpcUa_InitializeStatus(OpcUa_Module_Server, "UaProvider_CustomProvider_Events_SetCustomEventTypeCustomData"); // remark: this name doesn't exactly match the function-name as it lacks some underscores

    OpcUa_ReturnErrorIfArgumentNull(a_pEvent);
    OpcUa_ReturnErrorIfArgumentNull(a_pValues);

    pValue = (OpcUa_Variant*)UaBase_Vector_Get(&a_pEvent->EventFields, CustomEventTypeField_CustomData);
    OpcUa_ReturnErrorIfNull(pValue, OpcUa_BadNoData);

    OpcUa_Variant_Clear(pValue);
    if (pValue->Value.Array.Length <= a_iNoOfValues)
    {
        pValue->Value.Array.Value.ExtensionObjectArray = OpcUa_Null;
    }
    else
    {
        pValue->Value.Array.Value.ExtensionObjectArray = (OpcUa_ExtensionObject*)OpcUa_Alloc(a_iNoOfValues * sizeof(OpcUa_ExtensionObject));
        OpcUa_ReturnErrorIfAllocFailed(pValue->Value.Array.Value.ExtensionObjectArray);
        for (i = 0; i < a_iNoOfValues; i++)
        {
            OpcUa_ExtensionObject_Initialize(&pValue->Value.Array.Value.ExtensionObjectArray[i]);
        }
        for (i = 0; i < a_iNoOfValues; i++)
        {
            pValue->Value.Array.Value.ExtensionObjectArray[i].Encoding = OpcUa_ExtensionObjectEncoding_EncodeableObject;
            pValue->Value.Array.Value.ExtensionObjectArray[i].Body.EncodeableObject.Type = &CustomProvider_CustomDataType_EncodeableType;
            uStatus = CustomProvider_CustomDataType_Copy(&a_pValues[i], (CustomProvider_CustsomDataType**) &pValue->Value.Array.Value.ExtensionObjectArray[i].Body.EncodeableObject.Object);
            OpcUa_GotoErrorIfBad(uStatus);
        }
    }
    pValue->Datatype = OpcUaType_ExtensionObject;
    pValue->ArrayType = OpcUa_VariantArrayType_Array;
    pValue->Value.Array.Length = a_iNoOfValues;

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    OpcUa_Variant_Clear(pValue);

OpcUa_FinishErrorHandling;
}
The event code:

Code: Select all

CustomProvider_CustomDataType* pData;

pData = (CustomProvider_CustomDataType*)OpcUa_Alloc(sizeof(CustomProvider_CustomDataType) * NoOfData);
OpcUa_GotoErrorIfAllocFailed(pMTData);

for(i=0; i <NoOfData; ++i)
{
	CustomProvider_CustomDataType_Initialize(&pData[i]);
	... Set CustomDataType fields
}

... Create Event and set Event Fields ...

UaProvider_CustomProvider_Events_Set_CustomEventType_CustomData(pEvent,NoOfData,pData);

uStatus = UaServer_Events_FireEvent(pEvent);
OpcUa_GotoErrorIfBad(uStatus);
The first issue I encounter is the comparison '(pValue->Value.Array.Length <= a_iNoOfValues)'. In my application that comparison always results in false, since pValue->Value.Array.Length is always 0. However, I would like to be able to pass multiple values. When 'pValue->Value.Array.Value.ExtensionObjectArray' is set to OpcUa_Null the application crashes once the event is fired. Is this comparison actually required or can it be removed?



On to the second issue; After removing the comparison-code I end up with the following code.

Code: Select all

OpcUa_StatusCode UaProvider_CustomProvider_Events_Set_CustomEventType_CustomData(
    UaServer_Event *a_pEvent,
    OpcUa_Int32 a_iNoOfValues,
    CustomProvider_CustomDataType *a_pValues)
{
    OpcUa_Variant *pValue = OpcUa_Null;
    OpcUa_Int32 i = 0;

OpcUa_InitializeStatus(OpcUa_Module_Server, "UaProvider_CustomProvider_Events_SetCustomEventTypeCustomData"); // remark: this name doesn't exactly match the function-name as it lacks some underscores

    OpcUa_ReturnErrorIfArgumentNull(a_pEvent);
    OpcUa_ReturnErrorIfArgumentNull(a_pValues);

    pValue = (OpcUa_Variant*)UaBase_Vector_Get(&a_pEvent->EventFields, CustomEventTypeField_CustomData);
    OpcUa_ReturnErrorIfNull(pValue, OpcUa_BadNoData);

    OpcUa_Variant_Clear(pValue);

    pValue->Value.Array.Value.ExtensionObjectArray = (OpcUa_ExtensionObject*)OpcUa_Alloc(a_iNoOfValues * sizeof(OpcUa_ExtensionObject));
    OpcUa_ReturnErrorIfAllocFailed(pValue->Value.Array.Value.ExtensionObjectArray);
    for (i = 0; i < a_iNoOfValues; i++)
    {
        OpcUa_ExtensionObject_Initialize(&pValue->Value.Array.Value.ExtensionObjectArray[i]);
    }
    for (i = 0; i < a_iNoOfValues; i++)
    {
        pValue->Value.Array.Value.ExtensionObjectArray[i].Encoding = OpcUa_ExtensionObjectEncoding_EncodeableObject;
        pValue->Value.Array.Value.ExtensionObjectArray[i].Body.EncodeableObject.Type = &CustomProvider_CustomDataType_EncodeableType;
        uStatus = CustomProvider_CustomDataType_Copy(&a_pValues[i], (CustomProvider_CustsomDataType**) &pValue->Value.Array.Value.ExtensionObjectArray[i].Body.EncodeableObject.Object);
        OpcUa_GotoErrorIfBad(uStatus);
    }

    pValue->Datatype = OpcUaType_ExtensionObject;
    pValue->ArrayType = OpcUa_VariantArrayType_Array;
    pValue->Value.Array.Length = a_iNoOfValues;

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    OpcUa_Variant_Clear(pValue);

OpcUa_FinishErrorHandling;
}
This appears to be working when the application is compiled using the Visual Studio compiler under Windows.

UaExpert EventView Details:

Code: Select all

-----------------------------------------------
| Name            | Value                     |
-----------------------------------------------
| ns:Customdata   | Array of ExtensionObjects |
|   [0]           | CustomDataType            |
|     CustomArray | ... Null or data present  |
|   [1]           | CustomDataType            |
|     CustomArray | ... Null or data present  |
-----------------------------------------------
Unfortunately it doesn't work when the application is compiled using GCC under Linux:

UaExpert EventView Details:

Code: Select all

-----------------------------------------------
| Name            | Value                     |
-----------------------------------------------
| ns:Customdata   | Array of ExtensionObjects |
|   [0]           | ExtensionObject           |
|   [1]           | ExtensionObject           |
-----------------------------------------------

I've also tried the following code, but the issue remains:

Code: Select all

OpcUa_StatusCode UaProvider_CustomProvider_Events_Set_CustomEventType_CustomData(
    UaServer_Event *a_pEvent,
    OpcUa_Int32 a_iNoOfValues,
    CustomProvider_CustomDataType *a_pValues)
{
    CustomProvider_CustomDataType* pCustomDataValue;
    OpcUa_Variant *pValue = OpcUa_Null;
    OpcUa_Int32 i = 0;

OpcUa_InitializeStatus(OpcUa_Module_Server, "UaProvider_CustomProvider_Events_SetCustomEventTypeCustomData"); // remark: this name doesn't exactly match the function-name as it lacks some underscores

    OpcUa_ReturnErrorIfArgumentNull(a_pEvent);
    OpcUa_ReturnErrorIfArgumentNull(a_pValues);

    pValue = (OpcUa_Variant*)UaBase_Vector_Get(&a_pEvent->EventFields, CustomEventTypeField_CustomData);
    OpcUa_ReturnErrorIfNull(pValue, OpcUa_BadNoData);

    OpcUa_Variant_Clear(pValue);

    pValue->Value.Array.Value.ExtensionObjectArray = (OpcUa_ExtensionObject*)OpcUa_Alloc(a_iNoOfValues * sizeof(OpcUa_ExtensionObject));
    OpcUa_ReturnErrorIfAllocFailed(pValue->Value.Array.Value.ExtensionObjectArray);
    OpcUa_MemSet(pValue->Value.Array.Value.ExtensionObjectArray, 0, a_iNoOfValues * sizeof (OpcUa_ExtensionObject));
    for (i = 0; i < a_iNoOfValues; i++)
    {
        uStatus = OpcUa_EncodeableObject_CreateExtension(&CustomProvider_CustomDataType_EncodeableType, &pValue->Value.Array.Value.ExtensionObjectArray[i], (OpcUa_Void**)&pCustomDataValue);
	OpcUa_GotoErrorIfBad(uStatus);
    }

    pValue->Datatype = OpcUaType_ExtensionObject;
    pValue->ArrayType = OpcUa_VariantArrayType_Array;
    pValue->Value.Array.Length = a_iNoOfValues;

OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;

    OpcUa_Variant_Clear(pValue);

OpcUa_FinishErrorHandling;
}
Can someone enlighten me?

User avatar
Support Team
Hero Member
Hero Member
Posts: 3064
Joined: 18 Mar 2011, 15:09

Re: Issues with setting even field with custom DataType

Post by Support Team »

Hello,

thank you for your detailed error description. The first issue you mention is indeed an error in the templates for the AnsiC SDK. We will fix this in the next version of the UaModeler. Until then you can work around the problem by replacing the line
'if (pValue->Value.Array.Length <= a_iNoOfValues)'
with
'if (a_iNoOfValues <= 0)'

We couldn't reproduce your second issue, the fixed code works fine on Windows and Linux. Please retry with the new version of UaModeler once it is released, this will happen in the next few weeks.

Best regards
Unified Automation Support Team

User avatar
Support Team
Hero Member
Hero Member
Posts: 3064
Joined: 18 Mar 2011, 15:09

Re: Issues with setting even field with custom DataType

Post by Support Team »

Hello,

regarding your second issue:
UaExpert does not show the custom type in the event field.

If you ensure that the "Client" (UaExpert) really:
1) requests such event field (event filter setting)
2) has turned on TypeDictionary browsing on connect (config setting)
the custom type in the event field should be visible.

If you still can't see the custom type, the "Server" maybe not providing any/proper dictionary for such type. The reason for that (assuming your Windows and Linux code is identical) may be some different defines set when compiling the code. Please make sure that:
1) you have the define "HAVE_ENCODING_BINARY" set to "1"
in the CMake file you use for compiling your server application.

We always recommend to NOT manually create IDE-project files, instead use "CMake" as the only source and "generate" either IDE-project OR generate makefile. This ensures that you are using the same (identical) defines/settings for all your platforms, and it is easy to keep your config consistent, because you only maintain ONE source (which is CMake).

Best Regards
Support Team

Post Reply