titanium-as / TitaniumAS.Opc.Client

Open source .NET client library for OPC DA
MIT License
193 stars 94 forks source link

Getting the right Canonical Data Type #13

Closed pranny closed 6 years ago

pranny commented 7 years ago

Hi,

I am looking for the correct way to get Canonical Data Type for tags. I have tried a few approaches but none of them work across all the OPC Server scenarios that I am testing against:

Approach 1) Using Group

            OpcDaGroup @group = server.AddGroup(GroupName, groupState);  // add group on OPC Server
            OpcDaItemResult[] results = @group.AddItems(itemDefinitions); // add items on OPC server
            foreach (OpcDaItemResult result in results) //print errors
            {
                if (result.Error.Failed)
                {
                    eventLog.WriteEntry("[Deming Capture Service] Error on create item");
                }
                else
                {
                    eventLog.WriteEntry(result.Item.ItemId + "...." +  result.Item.CanonicalDataType);
                }
            }

This prints Random.Int4....System.Int32, Random.Real4....System.Single on Matrikon OPC Simulator. What I am really looking for is the OPC Data Type like VT_R4 or the OPC Data ID like 4,3 etc. This seems to be happening because of https://github.com/titanium-as/TitaniumAS.Opc.Client/blob/06584d25ca3c3d538c518f24597af88e90c16159/TitaniumAS.Opc.Client/Da/OpcDaItem.cs#L39 but I am not sure how to get it back to the original form.

Approach 2) Using browse to get the item properties

            var browser = new OpcDaBrowserAuto(server);

            OpcDaItemProperties[] properties = browser.GetProperties(tags.ToArray(),
                                                                     new OpcDaPropertiesQuery(true, OpcDaItemPropertyIds.OPC_PROP_CDT));
            foreach (OpcDaItemProperties prop in properties)
            {
                foreach (OpcDaItemProperty _prop in prop.Properties)
                {
                    eventLog.WriteEntry(_prop.ItemId + "::" + _prop.Value + "::" + _prop.PropertyId + "  :: " +_prop.ToString());
                    if (_prop.PropertyId == (int)OpcDaItemPropertyIds.OPC_PROP_CDT)
                    {
                        if (_prop.Value == null)
                        {
                            tag_data_types[_prop.ItemId] = "na";
                        }
                        else
                        {
                            tag_data_types[_prop.ItemId] = _prop.Value.ToString();
                        }
                    }
                }
            }

This does seem to work on Matrikon Simulator and one more, but on another system it throws garbage values like

Error::4::1  :: 1 Item Canonical DataType (ItemId: Error, DataType TitaniumAS.Opc.Client.Common.IllegalType, Value: 4, ErrorId: OPC_E_INVALID_PID: The specified property ID is not valid for the item.)

I confirmed by using OpenOPC that the CDT values are set and OpenOPC shows them correctly. I am not sure why I get this error on a particular machine only. It's been on my head for more than a week now. Any idea what should I try or what am I missing here.

alexey-titov commented 6 years ago

To reproduce the issue it is required to setup the environment with your OPC server.

TitaniumAS.Opc.Client.Interop.Helpers.TypeConverter.FromVarEnum does conversation from Variant enumeration to .Net type. It seems that it converts the value to the TitaniumAS.Opc.Client.Common.IllegalType type. You can set breakpoint in the function and check what values are converted to IllegalType.

I think that the workaround is can be to extend OpcDaItem with CanonicalDataTypeRaw RequestedDataTypeRaw property and store the values without conversation. We can merge pull request if someone implements it.