OPCFoundation / UA-ModelCompiler

ModelCompiler converts XML files into C# and ANSI C
MIT License
151 stars 92 forks source link

Optional fields in DataTypes. #48

Closed eoursel closed 3 years ago

eoursel commented 4 years ago

Hi

How is it possible to describe in ModelDesign format a DataTypes which contains Optional Fields. So for instance in in the NodeSet2 format i have something like that (from the VDMA Machine Vision companion specification

>  <UADataType IsAbstract="true" NodeId="ns=1;i=3019" BrowseName="1:BinaryIdBaseDataType">
>         <DisplayName>BinaryIdBaseDataType</DisplayName>
>         <References>
>             <Reference ReferenceType="HasSubtype" IsForward="false">i=22</Reference>
>             <Reference ReferenceType="HasEncoding">ns=1;i=5027</Reference>
>             <Reference ReferenceType="HasEncoding">ns=1;i=5271</Reference>
>         </References>
>         <Definition Name="1:BinaryIdBaseDataType">
>             <Field DataType="TrimmedString" Name="Id">
>                 <Description>Id is a system-wide unique name for identifying the recipe.</Description>
>             </Field>
>             <Field **IsOptional**="true" DataType="TrimmedString" Name="Version">
>                 <Description>Represents an optional version number of the identified recipe. It is recommended to be of the format Major.minor.patch.build or a subset thereof, but the actual format is implementation defined.</Description>
>             </Field>
>             <Field **IsOptional**="true" DataType="ByteString" Name="Hash">
>                 <Description>Represents an optional hash of the binary content of the actual recipe (as it would be transmitted by the transfer methods).
> The hash is supposed to be provided by the environment if existing. The environment shall use the same hash function on all recipes so that a difference in the hash indicates a difference in the recipe. It is recommended to use the SHA-256 algorithm for computing the hash, however, the actual algorithm is implementation-defined.</Description>
>             </Field>
>             <Field **IsOptional**="true" DataType="String" Name="HashAlgorithm">
>                 <Description>Name of the hash function used. Required if internally and externally computed hashes are to be compared.</Description>
>             </Field>
>             <Field **IsOptional**="true" DataType="LocalizedText" Name="Description">
>                 <Description>Optional short human readable description of the configuration.</Description>
>             </Field>
>         </Definition>
>     </UADataType>

So in the model design format do we have something to describe that fields are optional. The problem is that the encoders/decoders are not generated correctly in C# since it is written in part 6 we should generate a 4 bytes (UInt32) at the beginning of the encoding.

Is there something missing in the modelcompiler?

Thanks

opcfoundation-org commented 4 years ago

The ModelCompiler does not support Structures with Optional fields at this time.

eoursel commented 4 years ago

Hi @opcfoundation-org, @randy-armstrong. Do you a plan to support that in the near future ? Thanks

opcfoundation-org commented 4 years ago

It is not likely to happen before December.

opcfoundation-org commented 3 years ago

Option fields have been supported for awhile.

mregen commented 3 years ago

Hi @opcfoundation-org, I don't see in the code where the C# Modelcompiler generated code is fixed.

When I run this description through ModelCompiler:

<opc:DataType SymbolicName="ComplexTypeWithOptionsType" BaseType="ua:Structure">
    <opc:Fields>
      <opc:Field Name="X" DataType="ua:Double" IsOptional="true" />
      <opc:Field Name="Y" DataType="ua:Double" IsOptional="true" />
      <opc:Field Name="Z" DataType="ua:Double" IsOptional="true" />
    </opc:Fields>
  </opc:DataType>

the generated C# code:

       /// <summary cref="IEncodeable.Encode(IEncoder)" />
        public virtual void Encode(IEncoder encoder)
        {
            encoder.PushNamespace(ComplexTypesInterop.Namespaces.ComplexTypesInterop);

            encoder.WriteDouble("X", X);
            encoder.WriteDouble("Y", Y);
            encoder.WriteDouble("Z", Z);

            encoder.PopNamespace();
        }

I'd expect generated code like this for structure with optional fields:

       /// <summary cref="IEncodeable.Encode(IEncoder)" />
        public virtual void Encode(IEncoder encoder)
        {
            encoder.PushNamespace(ComplexTypesInterop.Namespaces.ComplexTypesInterop);

            encoder.WriteUInt32("EncodingMask", m_bitMask);
            if ((m_bitMask & 1)!=0) encoder.WriteDouble("X", X);
            if ((m_bitMask & 2)!=0) encoder.WriteDouble("Y", Y);
            if ((m_bitMask & 4)!=0) encoder.WriteDouble("Z", Z);

            encoder.PopNamespace();
        }