Packet/structure declarations declare named packet/structure objects. A packet/structure object gives its target byte stream a set of "fields", each having a unique name. You can fully set up a byte stream using packet/structure fields.
Note: Templates can inherit field layouts from other templates through ancestor lists.
( Packet | Struct ) Template_Name [ : Ancestor_1, Ancestor_ 2, … ] [ (Attribute list) ]
[
{
Field Definition 1
Field Definition 2
...
}
]
Note: For packet/structure template declarations, you can use the Packet or Struct keyword. However, structures are supposed to be used as building blocks for constructing packet payloads (or similar purposes), rather than for describing full packets.
Field Definitions
You can define template fields using the following syntax:
Field_Name : [ offset, ] length [ (Byte Order attribute) ] [ = Field_Value ] [ [ list of possible values ] ]
or
Field_Name [: length] { Subfield definitions } [ (Byte Order attribute) [ = Field_Value ] [ [ list of possible values ] ]
Note: Specify all field offsets and lengths in bits. Numeric expressions with declared constants are allowed in field offset and length definitions. All field and subfield names must be unique inside a template.
Note: You can define local fields for packet variable instances and when sending a packet.
Defining a Field at a Specific Offset
If the offset parameter is in a field definition, the field is bound to a specific offset.
Examples
const F3_OFFSET = 16
const F3_LEN = 8
# Declare the packet template 'SomeTemplate'.
Packet SomeTemplate
{
F1 : 0, 16 # Declare the 16-bit field 'F1' at offset 0.
F2 : 64, 32 # Declare the 32-bit field 'F2' at offset 64.
F3 : F3_OFFSET, F3_LEN # Declare the 8-bit field 'F2' at offset 16.
F4 : F3_OFFSET + F3_LEN, 16 # Declare the 16-bit field 'F4' at
# offset 16+8.
}
Defining a Field at the Current Offset
If the field offset is omitted, the field's offset is calculated based on the lengths of previously declared fields. The initial template offset is always 0.
Example
const F3_OFFSET = 64
const F3_LEN = 8
# Declare the packet template 'SomeTemplate'.
Packet SomeTemplate
{
F1 : 16 # Declare the 16-bit field 'F1' at offset 0.
F2 : 32 # Declare the 32-bit field 'F2' at offset 16.
F3 : F3_OFFSET, F3_LEN # Declare the 8-bit field 'F2' at offset 64.
F4 : 16 # Declare the 16-bit field 'F4' at offset 64+8.
}
Defining a Field with Variable Length
If the field length is set to *, the field’s length is defined by the value that is assigned to the field. If no value is assigned to the variable length field, the field’s length is set to 0.
Note: When a value is assigned to a variable length field, the field's length is changed based on the difference between the previous and current values. In this case, the offsets of following fields not bound to fixed offsets are shifted by the difference.
Examples
# Declare packet template 'SomeTemplate'.
Packet Some Template
{
F1 : 16 # Declare the 16-bit field 'F1' at offset 0.
F2 : 32 # Declare the 32-bit field 'F2' at offset 16.
Data : * # Declare the variable-length field 'Data'. The field
# length is now 0.
CRC32 : 32 # Declare the 32-bit field 'CRC32' at offset 16+32.
}
# Declare packet template 'SomeTemplate1', inheriting fields from
# 'SomeTemplate'.
Packet Some Template1 : Some Template
{
Data = 0xAABB # Assign a value to the 'Data' field.
# Now the field has length 16 bits and the
# field 'CRC32' offset is shifted by 16 bits =
# 16+32+16.
}
Defining a Default Field Value
When defining a field, you can specify a default field value. If the default value is not provided, the field is filled with zeros based on the field length.
Note: When a value is assigned to a variable length field, the field's length is changed based on the difference between the previous and current values. In this case, the offsets of following fields not bound to fixed offsets are shifted by the difference.
Example
const F3_OFFSET = 64
const F3_LEN = 8
# Declare the packet template 'SomeTemplate.
Packet SomeTemplate
{
F1 : 16 # Declare the 16-bit field 'F1' at offset 0.
F2 : 32 = 123456 # Declare the 32-bit field 'F2' with default
# value 123456.
F3 : * = {AA BB} # Declare a variable length field and assign
# hex value {AA BB} to it.
# Now its length is 16 bits.
}
Specifying Byte Order in Field Definitions
You can specify the byte order for integer fields (length <= 32 bits) using the Byte Order field attribute. The Byte Order field attribute indicates how numeric values are assigned to integer fields. By default, the byte order for integer fields is Big Endian: MSB->LSB. For example, the integer value 0xAABBCCDD is assigned as the {AA BB CC DD} byte stream.
Example
# Specify byte order for some fields of a template.
Packet Mixed
{
F1 : 16
F2 : 32 (MSB)
F3 : 16 (MSB) = 0xAABB
F4 : 32 = 0xAABBCCDD
}
# Template with the same field layout as the template above
Packet MSBMixed (MSB)
{
F1 : 16 (LSB)
F2 : 32
F3 : 16 = 0xAABB
F4 : 32 (LSB) = 0xAABBCCDD
}
Using Byte Stream Literals in Field Assignments
You can specify the byte order explicitly using byte stream literals:
Example
Field_32 : 32 = { AA BB CC DD }
List of Possible Field Values Attribute
You can specify a list of possible field values (defined by constant or data pattern names) for declared template fields. The Voyager USB 3.1 Exerciser Application Development Environment (Voyager USB 3.1 Exerciser Script Editor Intellisense) uses this list to quickly assign field values.
Note: The list does not affect compilation or traffic generation.
Example
Const MyConst = 10
DataPattern MyPattern = { AA BB CC DD _11110000 }
Packet MY_TEMPLATE
{
Field_1 : 16 [MyConst, MyPattern] # possible value list
Field_2 : 32 = 0xAABBCCDD [MyPattern] # possible value list
Field_3 : 32 (MSB) = [MyConst] # possible value list
}
Defining Subfields
You can define named subfields for top-level template fields. Subfields allow you to set a field value using DWORD little-endian bit order. Subfield and field names must be unique inside a template. You can also assign field values using field names directly.
Note: You cannot define subfields for lower-level template fields.
Syntax
Field_Name [ : length ]
{
SubField [ : length ] [ (Byte Order attribute) [ = Field_Value ] [ [ list of possible values ] ]
SubField [ : length ] [ (Byte Order attribute) [ = Field_Value ] [ [ list of possible values ] ]
SubField [ : length ] [ (Byte Order attribute) [ = Field_Value ] [ [ list of possible values ] ]
…
}
[ (Byte Order attribute) [ = Field_Value ] [ [ list of possible values ] ]
If the length of a parent field is less than the total length of its subfields, the total length of the subfields defines the parent field length.
Note: The subfields always use their parent field as a DWORD little-endian buffer. For example, if the parent field has a 64-bit length for subfield assignments, the subfields use it as two little-endian DWORDs.
Example
struct Templ_1
{
F1 : 8
F2
{
SF1 : 8 = 0xCC
SF2 : 16
SF3 : 8
}
}
struct Templ_2
{
F1 : 8
F2 : 16 # Declare parent field length.
{
SF1 : 8
}
}
Main
{
# Send a packet with payload: 00 EE AA BB CC
Send Templ_1
{
SF2 = {AA BB}
SF3 = 0xEE
}
# The same as above
Send Templ_1
{
# Use direct parent field assignment instead of subfields.
F2 = {EE AA BB CC}
}
# Send a packet with payload: 0A 00 EE
Send Templ_2
{
F1 = 0xA
SF1 = 0xEE
}
}
Constants/Arithmetic Expressions in Template Declarations
You can use constants and arithmetic expressions in both field definitions and value declarations.
Examples
const DPH = _1000 # 0x8
struct LinkCtrlWord
{
Hseq : 3
LcwRsvd : 3
HDepth : 3
D1 : 1
D2 : 1
CRC_5 : 5 # Auto calculated
}
const TYPE_LEN = 5
Packet DPH
{
#Dword 0
Type : TYPE_LEN = DPH
RouteStr : 20
DevAddr : 7
#Dword 1
SeqNum : 5
Rsvd1 : 1
Delayed : 1
EOB : 1
Endp : 4
Rsvd2 : 3
Setup : 1
DataLen : 16
#Dword 2
StreamID : 16
Rsvd3 : 11
PP : 1
Rsvd4 : 4
#Dword 3
CRC_16 : 16 # Auto calculated
: LinkCtrlWord # structure template insertion
}
const CRC32_LEN = 32
Packet DataPacket : DPH
{
Data : *
CRC32 : CRC32_LEN
}
Packet Template Inheritance
You can create a packet/struct template that inherits field layouts defined in another template. The created template has all the fields defined in the inherited templates plus its own fields. All fields must have unique names.
Note: The parser adds the fields defined in the created packet template after it adds fields from the inherited templates.
You can change the default field values of the inherited fields.
Packet Template Single Inheritance
A new template inherits the field layouts from another template using an ancestor list.
Examples
Packet MY_DataPacket : DataPacket
{
# Example of a field with variable length having a default value.
Data : * = { 00 00 00 01 }
}
# More examples of template inheritance
const LMP = 0
const LMP_SET_LINK_FUNC = 1
Packet USB3Common
{
Type : 5
}
Packet LMPCommon : USB3Common # Derive a template from a USB3Common template.
{
Type = LMP
SubType : 4
}
Packet LMP_SetLinkFunction : LMPCommon
{
SubType = LMP_SET_LINK_FUNC
Resv1 : 1;
Force_LinkPM_Accept : 1;
Resv2 : 5;
Resv3 : 16;
Resv4 : 32;
Resv5 : 32;
CRC_16 : 16 # Auto calculated
: LinkCtrlWord # structure template insertion
}
Packet Template Multiple Inheritance
You can create a packet/struct template that inherits field layouts defined in several templates. The created template has all the fields defined in the inherited templates plus its own fields. All fields must have unique names.
Multiple inheritance can simplify the construction of complex templates.
Note: The parser adds the fields defined in the created template after it adds fields from the inherited templates. The parser adds the fields defined in the inherited templates in order from the left-most ancestor to the right-most ancestor.
Examples
Packet Base
{
F1 : 16
F2 : 8
F3 : 32
}
Packet Templ_0
{
FieldT0_8 : 8
FieldT0_16 : 16
}
Packet Templ_1
{
FieldT1_24 : 24
FieldT1_32 : 32
}
Packet Combined : Base, Templ_0, Templ_1
{
}
The Combined template above has the following fields:
-
F1 : 16 # Base
-
F2 : 8 # Base
-
F3 : 32 # Base
-
FieldT0_8 : 8 # Templ_0
-
FieldT0_16 : 16 # Templ_0
-
FieldT1_24 : 24 # Templ_1
-
FieldT1_32 : 32 # Templ_1
-
Data : * # Combined
Examples
const DPH = _1000 # 0x8
struct LinkCtrlWord
{
Hseq : 3
LcwRsvd : 3
HDepth : 3
D1 : 1
D2 : 1
CRC_5 : 5 # Auto calculated
}
struct DPH_DWORD_0
{
Type : 5 = DPH
RouteStr : 20
DevAddr : 7
}
struct DPH_DWORD_1
{
SeqNum : 5
Rsvd1 : 1
Delayed : 1
EOB : 1
Endp : 4
Rsvd2 : 3
Setup : 1
DataLen : 16
}
struct DPH_DWORD_2
{
StreamID : 16
Rsvd3 : 11
PP : 1
Rsvd4 : 4
}
Packet DPH : DPH_DWORD_0, DPH_DWORD_1, DPH_DWORD_2 # Multiple template
# inheritance
{
CRC_16 : 16 # Auto calculated
: LinkCtrlWord # structure template insertion
}
Packet Template Insert Directive
You can insert field layouts from another template after a specific field in a template. Use the insert or ':' directive.
Example 1
Packet Base
{
F1 : 16
F2 : 8
F3 : 32
}
Packet Templ_0
{
FieldT0_8 : 8
FieldT0_16 : 16
}
Packet Templ_1
{
FieldT1_24 : 24
FieldT1_32 : 32
}
Packet Combined : Base
{
Cmb_F1 : 8
insert Templ_0 # Insert fields from packet template Templ_0.
Cmb_F2 : 16
insert Templ_1 # Insert fields from packet template Templ_1.
Data : 32
}
The Combined template above has the fields:
-
F1 16 # Base
-
F2 8 # Base
-
F3 32 # Base
-
Cmb_F1 8 # Combined
-
FieldT0_8 8 # Templ_0
-
FieldT0_16 16 # Templ_0
-
Cmb_F2 16 # Combined
-
FieldT1_24 24 # Templ_1
-
FieldT1_32 32 # Templ_1
-
Data 32 # Combined
Example 2
Packet Combined : Base
{
Cmb_F1 : 8
: Templ_0 # Insert fields from packet template Templ_0.
Cmb_F2 : 16
: Templ_1 # Insert fields from packet template Templ_1.
Data : 32
}
Complex Packet Templates
Template insertions can simplify construction of complex templates.
Examples
const DPH = _1000 # 0x8
struct LinkCtrlWord
{
Hseq : 3
LcwRsvd : 3
HDepth : 3
D1 : 1
D2 : 1
CRC_5 : 5 # Auto calculated
}
struct DPH_DWORD_0
{
Type : 5 = DPH
RouteStr : 20
DevAddr : 7
}
struct DPH_DWORD_1
{
SeqNum : 5
Rsvd1 : 1
Delayed : 1
EOB : 1
Endp : 4
Rsvd2 : 3
Setup : 1
DataLen : 16
}
struct DPH_DWORD_2
{
StreamID : 16
Rsvd3 : 11
PP : 1
Rsvd4 : 4
}
Packet DPH
{
: DPH_DWORD_0
: DPH_DWORD_1
: DPH_DWORD_2 # Use template insertion instead of multiple inheritance.
CRC_16 : 16 # Auto calculated
: LinkCtrlWord # Another template insertion
}
Packet Template Multi-byte Field Byte Order Attribute
By default, for fields up to 32 bits, the parser uses the Little Endian (LSB -> MSB) byte order. For example, if a 32-bit field has the value 0xAABBCCDD, it is written into the byte stream as:
DD CC BB AA
Example
Packet MY_TEMPLATE
{
Field_16 : 16 = 0xEEFF
Field_32 : 32 = 0xAABBCCDD
}
The byte stream based on this template is:
FF EE DD CC BB AA
Big Endian Byte Order
You can require that all template fields have the Big Endian (MSB -> LSB) byte order. Adding (MSB) after the ancestor list in the template declaration instructs the script parser to choose the MSB -> LSB byte order.
Example
Packet MY_TEMPLATE (MSB)
{
Field_16 : 16 = 0xEEFF
Field_32 : 32 = 0xAABBCCDD
}
The byte stream based on this template is EE FF AA BB CC DD.
Note: This attribute is needed only for assignments in which numeric literals (such as 0xAABBCCDD or 12323344 ) are used.
Another Example
struct UsbReq {LSB} # Using LSB attribute for integer field assignments
# instructs that all short fields have
# LSB to MSB byte order when assigned values.
{
bmType : 8
bReq : 8
wValue : 16
wIndex : 16
wLen : 16
Data : * # variable length field
}
Note: The Byte Order attribute applies only for fields defined inside a template and does not affect fields specified in inherited or inserted templates.
Examples
Packet Base_0 (MSB)
{
F1 : 16
}
Packet Base_1 # LSB to MSB byte order by default
{
F2 : 32
}
Packet Combined : Base0, Base_1 (MSB)
# The attribute goes after the template ancestor list.
{
Cmb_Fld : 32
}
# Combined template has the fields:
# F1 : 16 (MSB)
# F2 : 32 (LSB)
# Cmb_Fld : 32 (MSB)
Structure Declaration Examples
To the parser, structures are the same as packet templates. However, you should use structures to assign packet field values, rather than packet layouts in Send Packet instructions.
Note: Also see the examples using the Struct keyword to assign packet field values, in later sections.
Examples
struct S1
{
F16 : 16 = 0xAABB
F8 : 8 = 0xFE
F32 : 32 = 0xABCD1234
}
struct S2
{
S8 : 8 = 0xDA
S32 : 32 = 0x56781122
S16 : 16 = 0xBEEF
}