Hi,
I'm working with Open62541 for several weeks. First of all I want to thank you for the very proffesional work you guys do.
I've implemented server and client on windows and linux platforms with customized types. I also succeeded to present this type in UA Expert by creating automatic dictionary implemntation for every new customize data structure (contact to dictionary byte string value).
When I started to work with Beckhoff server I came up against several problems. I've managed to solve them by monitoring wireshark transportation from UA expert and implementing them by hand. I would like your advise what is the correct way.
The issues:
1. Structure data types in Beckhoff are defined as string node ID and not Numeric.
2. All the structures are Extension Objects.
I've tried to follow the same concept of defining reflection of the structures in the client configuration, but it didn't work for me.
Finally I've implemnted the below:
Example for Write:
-------------------------
template <typename T>
static UA_StatusCode setOpcUaValue(UA_NodeId nodeId, T value)
{
UA_StatusCode retval = UA_STATUSCODE_GOOD;
UA_NodeId dataTypeNodeId{};
retval = UA_Client_readDataTypeAttribute(client, nodeId, &dataTypeNodeId);
if (retval != UA_STATUSCODE_GOOD)
return retval;
// This is quite true assumption that we don't have builtin support for other namespaces
if (dataTypeNodeId.namespaceIndex == 0)
{
UA_Variant myVariant; /* Variants can hold scalar values and arrays of any type */
UA_Variant_init(&myVariant);
// Maybe need to check validation of size etc.
// This is O(1) search - need to be optimized - maybe we can predict where is it in the array
const UA_DataType* dataType = UA_findDataType(&dataTypeNodeId);
UA_Variant_setScalarCopy(&myVariant, &value, dataType);
retval = UA_Client_writeValueAttribute(client, nodeId, &myVariant);
}
else
{
UA_Variant myVariant; /* Variants can hold scalar values and arrays of any type */
UA_Variant_init(&myVariant);
UA_ExtensionObject dataValue;
dataValue.encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
dataValue.content.encoded.typeId = dataTypeNodeId;
dataValue.content.encoded.body.data = (UA_Byte*)&value;
dataValue.content.encoded.body.length = sizeof(value);
UA_Variant_setScalarCopy(&myVariant, &dataValue, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
retval = UA_Client_writeValueAttribute(client, nodeId, &myVariant);
}
return retval;
}
Example for read:
-------------------------
retval = UA_Client_readValueAttribute(client, nodeId, &value);
if (retval == UA_STATUSCODE_GOOD)
{
if (UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]))
{
UA_ExtensionObject dataValue;
dataValue = *(UA_ExtensionObject *)value.data;
raw_data = *(T*)dataValue.content.encoded.body.data;
}
}
Same trick also for monitored item callback.
I'll be glad to get your comments. Do we have other builtin way?
Best Regards,
Yehuda