Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom structure encodable by reflection. #159

Open
awcullen opened this issue Aug 2, 2020 · 4 comments
Open

Custom structure encodable by reflection. #159

awcullen opened this issue Aug 2, 2020 · 4 comments

Comments

@awcullen
Copy link
Contributor

awcullen commented Aug 2, 2020

Consider adding support for simple structures that may be encoded by reflection.

In a PLC you may create a UDT, for example:

TYPE "Vector"
VERSION : 0.1
   STRUCT
      X : LReal;
      Y : LReal;
      Z : LReal;
   END_STRUCT;

END_TYPE

Today, this library supports custom data types that implement IEncodable. I propose we add fallback support to use reflection to discover the properties and values.

using Workstation.ServiceModel.Ua;

[assembly: TypeLibrary()]
namespace PLCTypeLibrary
{
    [BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"Vector\"")]
    public class Vector
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }
    }
}

Reflection mode would only need to support the kind of types found in PLC UDT's.

Further, a tool could be written to extract the UDTs from your PLC program and generate the source code for a custom type library.

@quinmars
Copy link
Contributor

This is definately interesting. An alternative to runtime reflection could be roslyn source generators. I haven't ever used them nor do I have experience in roslyn analyzers, but the user would write:

[BinaryEncodingId("nsu=http://www.siemens.com/simatic-s7-opcua;s=TE_\"Vector\"")]
partial public class Vector  // note the `partial` modifier
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
}

and the source generator would generate (because Vector does not yet implement IEncodable):

partial public class Vector : IEncodable
{
    public virtual void Encode(IEncoder encoder)
    {
        encoder.PushNamespace("http://www.siemens.com/simatic-s7-opcua");
        encoder.WriteDouble("X", this.X);
        encoder.WriteDouble("Y", this.Y);
        encoder.WriteDouble("Z", this.Z);
        encoder.PopNamespace();
    }

    public virtual void Decode(IDecoder decoder)
    {
        decoder.PushNamespace("http://www.siemens.com/simatic-s7-opcua");
        X = decoder.ReadDouble("X");
        Y = decoder.ReadDouble("Y");
        Z = decoder.ReadDouble("Z");
        decoder.PopNamespace();
    }
}

The benefit would be that you do not have to pay for reflection, because everything happens during compile time.

@quinmars
Copy link
Contributor

Further, a tool could be written to extract the UDTs from your PLC program and generate the source code for a custom type library.

I'm playing at the moment with the idea, to write an source generator that will transform NodeSet2 files into .NET data types. I haven't done any code for that yet, but the idea is that you can eventuelly install one nuget package and add the node set file to your solution. Roslyn will then generate all the needed classes for you.

This would make it easy to provide classes for companion specifications and also for PLCs. With the Siemens TIA portal you can for instance export the NodeSet.xml file.

@yang909044315
Copy link

I have UDT ,EX:
{TYPE "Vector"
VERSION : 0.1
STRUCT
X : LReal;
Y : LReal;
Z : LReal;
END_STRUCT;

END_TYPE};and SiemensPLC NodeId is "ns=2;i=3", How can I read and write?I use WPF ;Looking forward to your response

@ismdiego
Copy link

I'm playing at the moment with the idea, to write an source generator that will transform NodeSet2 files into .NET data types. I haven't done any code for that yet, but the idea is that you can eventuelly install one nuget package and add the node set file to your solution. Roslyn will then generate all the needed classes for you.

I have found your "playground" (https://github.com/quinmars/UaTypeGenerator) and it is brilliant!

The problem I actually have that prevents me from using it is that some vendors make it really hard or impossible to generate the .NodeSet2.xml file.

So I am trying to use your tool in a simpler way, passing as input something like the opc:StructuredType data that the OPC UA Browser plugin (for VS2019) generates when dragging a Structure type into a code window. In fact, it will be fine if this structure can be read from the OPC UA Server directly without using that plugin. I have to also check the plugin code to see how to achieve this (LoadChildrenAsync method from UaBrowserViewModel seems a good starting point).

@awcullen I suspect the https://github.com/convertersystems/opc-ua-tools is abandoned and you could not achieve the goal of generating the Decode and Encode code by itself. I think that combining the efforts in these two projects would help in that matter. @quinmars project is fantastic in generating the code, and the plugin can read the datatypes (at least enough to have all the required information to create the Decode/Encode methods).

I will try to use code from both to see if I can integrate them in a standalone utility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants