CommsDSL Specification
  • Introduction
  • Version
  • Schema Definition
  • Multiple Files
  • Namespaces
  • Platforms
  • References
  • Properties
  • Numeric Values
  • Boolean Values
  • Names
  • Protocol Versioning
  • Schema
  • Fields
    • Common Properties of Fields
    • enum Field
    • int Field
    • set Field
    • bitfield Field
    • bundle Field
    • string Field
    • data Field
    • list Field
    • float Field
    • ref Field
    • optional Field
    • variant Field
    • Referencing Values of Other Fields
  • Messages
  • Interfaces
  • Aliases
  • Frames
    • Common Properties of Layers
    • payload Layer
    • id Layer
    • size Layer
    • sync Layer
    • checksum Layer
    • value Layer
    • custom Layer
  • Protocol Versioning Summary
  • Appendix
    • Properties of schema
    • Common Properties of Fields
    • Properties of enum Field
    • Properties of int Field
    • Properties of set Field
    • Properties of bitfield Field
    • Properties of bundle Field
    • Properties of string Field
    • Properties of data Field
    • Properties of list Field
    • Properties of float Field
    • Properties of ref Field
    • Properties of optional Field
    • Properties of variant Field
    • Units
    • Properties of message
    • Properties of interface
    • Properties of alias
    • Properties of frame
    • Common Properties of Layers
    • Properties of checksum Layer
    • Properties of value Layer
    • Properties of custom Layer
Powered by GitBook
On this page
  • Member Fields
  • Default Member
  • Extra Display Property

Was this helpful?

  1. Fields

variant Field

Previousoptional FieldNextReferencing Values of Other Fields

Last updated 5 years ago

Was this helpful?

This field is basically a union of other . It can hold only one field at a time out of the provided list of supported . The <variant> field has all the properties as well as extra properties and elements described below.

Member Fields

The <variant> field is there to support heterogeneous lists of fields. The classic example would be a list of key-value pairs, where numeric key defines what type of value follows. Similar to field, member fields need to be listed as children XML elements of the <variant>.

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <int name="Key" type="uint8" failOnInvalid="true" displayReadOnly="true" />

        <variant name="Property">
            <bundle name="Prop1">
                <int reuse="Key" defaultValue="0" validValue="0" />
                <int name="Value" type="uint32" />
            </bundle>
            <bundle name="Prop2">
                <int reuse="Key" defaultValue="1" validValue="1" />
                <string name="Value" length="16" />
            </bundle>
        </variant>

        <list name="PropertiesList" element="Property" />
    </fields>
</schema>
<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <variant name="Property">
            <displayName value="Proper Variant Name" />
            <members>
                <bundle name="Prop1">
                    ...
                </bundle>
                ...
            </members>
        </variant>
    </fields>
</schema>

Another quite popular example of is to have heterogeneous list of TLV (type / length / value) triplets.

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <int name="Type" type="uint8" failOnInvalid="true" displayReadOnly="true" />

        <variant name="Property">
            <bundle name="Prop1">
                <int reuse="Type" defaultValue="0" validValue="0" />
                <int name="Length" type="uint16" semanticType="length" />
                <int name="Value" type="uint32" />
            </bundle>
            <bundle name="Prop2">
                <int reuse="Type" defaultValue="1" validValue="1" />
                <int name="Length" type="uint16" semanticType="length" />
                <string name="Value" />
            </bundle>
            ... 
        </variant>

        <list name="PropertiesList" element="Property" />
    </fields>
</schema>

Please note assigning semanticType property to be length for the Length field in every bundle. It specifies that the field contains remaining length of all the subsequent fields in the <bundle> and allows the code generator to produce correct code. The support for length value of semanticType has been introduced in v2 of this specification.

Quite often the developers wonder why there is a need to use remaining length information for the fields, length of which is constant and known and compile time. It allows introducing more fields in future versions of the protocol while preserving forward / backward compatibility of the protocol. For example:

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big" version="2">
    <fields>
        <int name="Type" type="uint8" failOnInvalid="true" displayReadOnly="true" />

        <variant name="Property">
            <bundle name="Prop1">
                <int reuse="Type" defaultValue="0" validValue="0" />
                <int name="Length" type="uint16" semanticType="length" />
                <int name="Value" type="uint32" />
                <int name="Value2" type="int16" sinceVersion="2"/>
            </bundle>
            ... 
        </variant>

        <list name="PropertiesList" element="Property" />
    </fields>
</schema>

The old version of the protocol code, that is not aware of extra field being added in the new version, will be able to skip over unknown data and read the next property from the correct location.

It also allows safe reception and handling of unexpected (or unknown) properties that could be introduced in the future versions of the protocol while still operating correctly.

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <int name="Type" type="uint8" failOnInvalid="true" displayReadOnly="true" />

        <variant name="Property">
            ...
            <bundle name="UnknownProp">
                <int reuse="Type" failOnInvalid="false" />
                <int name="Length" type="uint16" semanticType="length" />
                <data name="Value" />
            </bundle>
        </variant>

        <list name="PropertiesList" element="Property" />
    </fields>
</schema>

NOTE, that in the example above the UnknownProp is defined to be the last member field of the <variant> field and has non-failing read of its Type (failOnInvalid property has been set to false).

Default Member

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <variant name="Property" defaultMember="Prop1">
            <bundle name="Prop1">
                ...
            </bundle>
            ...
        </variant>
    </fields>
</schema>

The defaultMember property may also specify index instead of the member name.

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <variant name="Property" defaultMember="0">
            <bundle name="Prop1">
                ...
            </bundle>
            ...
        </variant>
    </fields>
</schema>

Negative number as value of defaultMember property will force the <variant> field not to have a default member.

Extra Display Property

<?xml version="1.0" encoding="UTF-8"?>
<schema name="MyProtocol" endian="big">
    <fields>
        <variant name="Property" displayIdxReadOnlyHidden="true">
            <bundle name="Prop1">
                ...
            </bundle>
            ...
        </variant>
    </fields>
</schema>

The example above defines every key-value pair as field, where first field (key) reuses external definition of Key field and adds its default construction value as well as what value considered to be valid. NOTE, that every key member sets failOnInvalid property to true. The code generator is expected to generate code that attempts read operation of every defined member field in the order of their definition. Once the read operation is successful, the right member has been found and the read operation needs to terminate. The in-order read is high level logic, the code generator is allowed to introduce optimizations as long as the outcome of detecting the right member is the same.

If there is any other defined as XML child of the <variant>, then all the members must be wrapped in <members> XML element for separation.

When <variant> field is constructed, it should not hold any field and when serialized, it mustn't produce any output. However, it is possible to specify default member to which the <variant> field should be initialized when constructed. To specify such member use defaultMember .

By default GUI protocol analysis tools should display the index of the held member when displaying <variant> field in "read only" mode. However, for some occasions this information may be irrelevant. To hide display of index use displayIdxReadOnlyHidden with value.

Use for future references.

fields
fields
common
<bundle>
<bundle>
property
property
property
boolean
properties table