• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Packet Description Language
2
3[TOC]
4
5## Notation
6
7|    Notation   |            Example           |                        Meaning                       |
8|:-------------:|:----------------------------:|:----------------------------------------------------:|
9| __ANY__       | __ANY__                      | Any character                                        |
10| CAPITAL       | IDENTIFIER, INT              | A token production                                   |
11| snake_case    | declaration, constraint      | A syntactical production                             |
12| `string`      | `enum`, `=`                  | The exact character(s)                               |
13| \x            | \n, \r, \t, \0               | The character represented by this escape             |
14| x?            | `,`?                         | An optional item                                     |
15| x*            | ALPHANUM*                    | 0 or more of x                                       |
16| x+            | HEXDIGIT+                    | 1 or more of x                                       |
17| x \| y        | ALPHA \| DIGIT, `0x` \| `0X` | Either x or y                                        |
18| [x-y]         | [`a`-`z`]                    | Any of the characters in the range from x to y       |
19| !x            | !\n                          | Negative Predicate (lookahead), do not consume input |
20| ()            | (`,` enum_tag)               | Groups items                                         |
21
22
23[WHITESPACE](#Whitespace) and [COMMENT](#Comment) are implicitly inserted between every item
24and repetitions in syntactical rules (snake_case).
25
26```
27file: endianess declaration*
28```
29behaves like:
30```
31file: (WHITESPACE | COMMENT)* endianess (WHITESPACE | COMMENT)* (declaration | WHITESPACE | COMMENT)*
32```
33
34## File
35
36> file:\
37>    endianess [declaration](#declarations)*
38>
39> endianess:\
40>    `little_endian_packets` | `big_endian_packets`
41
42The structure of a `.pdl`file is:
431. A declaration of the protocol endianess: `little_endian_packets` or `big_endian_packets`. Followed by
442. Declarations describing the structure of the protocol.
45
46```
47// The protocol is little endian
48little_endian_packets
49
50// Brew a coffee
51packet Brew {
52  pot: 8, // Output Pot: 8bit, 0-255
53  additions: CoffeeAddition[2] // Coffee Additions: array of 2 CoffeeAddition
54}
55```
56
57The endianess affects how fields of fractional byte sizes (hence named
58bit-fields) are parsed or serialized. Such fields are grouped together to the
59next byte boundary, least significant bit first, and then byte-swapped to the
60required endianess before being written to memory, or after being read from
61memory.
62
63```
64packet Coffee {
65  a: 1,
66  b: 15,
67  c: 3,
68  d: 5,
69}
70
71// The first two field are laid out as a single
72// integer of 16-bits
73//     MSB                                   LSB
74//     16                  8                 0
75//     +---------------------------------------+
76//     | b14 ..                        .. b0 |a|
77//     +---------------------------------------+
78//
79// The file endianness is applied to this integer
80// to obtain the byte layout of the packet fields.
81//
82// Little endian layout
83//     MSB                                   LSB
84//     7    6    5    4    3    2    1    0
85//     +---------------------------------------+
86//  0  |            b[6:0]                | a  |
87//     +---------------------------------------+
88//  1  |               b[14:7]                 |
89//     +---------------------------------------+
90//  2  |          d             |       c      |
91//     +---------------------------------------+
92//
93// Big endian layout
94//     MSB                                   LSB
95//     7    6    5    4    3    2    1    0
96//     +---------------------------------------+
97//  0  |               b[14:7]                 |
98//     +---------------------------------------+
99//  1  |            b[6:0]                | a  |
100//     +---------------------------------------+
101//  2  |          d             |       c      |
102//     +---------------------------------------+
103```
104
105Fields which qualify as bit-fields are:
106- [Scalar](#fields-scalar) fields
107- [Size](#fields-size) fields
108- [Count](#fields-count) fields
109- [Fixed](#fields-fixed) fields
110- [Reserved](#fields-reserved) fields
111- [Typedef](#fields-typedef) fields, when the field type is an
112  [Enum](#enum)
113
114Fields that do not qualify as bit-fields _must_ start and end on a byte boundary.
115
116## Identifiers
117
118- Identifiers can denote a field; an enumeration tag; or a declared type.
119
120- Field identifiers declared in a [packet](#packet) (resp. [struct](#struct)) belong to the _scope_ that extends
121  to the packet (resp. struct), and all derived packets (resp. structs).
122
123- Field identifiers declared in a [group](#group) belong to the _scope_ that
124  extends to the packets declaring a [group field](#group_field) for this group.
125
126- Two fields may not be declared with the same identifier in any packet scope.
127
128- Two types may not be declared width the same identifier.
129
130## Declarations
131
132> declaration: {#declaration}\
133>    [enum_declaration](#enum) |\
134>    [packet_declaration](#packet) |\
135>    [struct_declaration](#struct) |\
136>    [group_declaration](#group) |\
137>    [checksum_declaration](#checksum) |\
138>    [custom_field_declaration](#custom-field) |\
139>    [test_declaration](#test)
140
141A *declaration* defines a type inside a `.pdl` file. A declaration can reference
142another declaration appearing later in the file.
143
144A declaration is either:
145- an [Enum](#enum) declaration
146- a [Packet](#packet) declaration
147- a [Struct](#struct) declaration
148- a [Group](#group) declaration
149- a [Checksum](#checksum) declaration
150- a [Custom Field](#custom-field) declaration
151- a [Test](#test) declaration
152
153### Enum
154
155> enum_declaration:\
156>    `enum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) `{`\
157>      enum_tag_list\
158>    `}`
159>
160> enum_tag_list:\
161>    enum_tag (`,` enum_tag)* `,`?
162>
163> enum_tag:\
164>    enum_range | enum_value
165>
166> enum_range:\
167>    [IDENTIFIER](#identifier) `=` [INTEGER](#integer) `..` [INTEGER](#integer)) (`{`\
168>      enum_value_list\
169>    `}`)?
170>
171> enum_value_list:\
172>    enum_value (`,` enum_value)* `,`?
173>
174> enum_value:\
175>    [IDENTIFIER](#identifier) `=` [INTEGER](#integer)
176
177An *enumeration* or for short *enum*, is a declaration of a set of named [integer](#integer) constants
178or named [integer](#integer) ranges. [integer](#integer) ranges are inclusive in both ends.
179[integer](#integer) value within a range *must* be unique. [integer](#integer) ranges
180*must not* overlap.
181
182The [integer](#integer) following the name specifies the bit size of the values.
183
184```
185enum CoffeeAddition: 5 {
186  Empty = 0,
187
188  NonAlcoholic = 1..9 {
189    Cream = 1,
190    Vanilla = 2,
191    Chocolate = 3,
192  },
193
194  Alcoholic = 10..19 {
195    Whisky = 10,
196    Rum = 11,
197    Kahlua = 12,
198    Aquavit = 13,
199  },
200
201  Custom = 20..29,
202}
203```
204
205### Packet
206
207> packet_declaration:\
208>    `packet` [IDENTIFIER](#identifier)\
209>      (`:` [IDENTIFIER](#identifier)\
210>        (`(` [constraint_list](#constraints) `)`)?\
211>      )?\
212>    `{`\
213>      [field_list](#fields)?\
214>    `}`
215
216A *packet* is a declaration of a sequence of [fields](#fields). While packets
217can contain bit-fields, the size of the whole packet must be a multiple of 8
218bits.
219
220A *packet* can optionally inherit from another *packet* declaration. In this case the packet
221inherits the parent's fields and the child's fields replace the
222[*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body) field of the parent.
223
224When inheriting, you can use constraints to set values on parent fields.
225See [constraints](#constraints) for more details.
226
227```
228packet Error {
229  code: 32,
230  _payload_
231}
232
233packet ImATeapot: Error(code = 418) {
234  brand_id: 8
235}
236```
237
238### Struct
239
240> struct_declaration:\
241>    `struct` [IDENTIFIER](#identifier)\
242>      (`:` [IDENTIFIER](#identifier)\
243>        (`(` [constraint_list](#constraints) `)`)?\
244>      )?\
245>    `{`\
246>      [field_list](#fields)?\
247>    `}`
248
249A *struct* follows the same rules as a [*packet*](#packet) with the following differences:
250- It inherits from a *struct* declaration instead of *packet* declaration.
251- A [typedef](#fields-typedef) field can reference a *struct*.
252
253### Group
254
255> group_declaration:\
256>    `group` [IDENTIFIER](#identifier) `{`\
257>      [field_list](#fields)\
258>    `}`
259
260A *group* is a sequence of [fields](#fields) that expand in a
261[packet](#packet) or [struct](#struct) when used.
262
263See also the [Group field](#fields-group).
264
265```
266group Paged {
267  offset: 8,
268  limit: 8
269}
270
271packet AskBrewHistory {
272  pot: 8, // Coffee Pot
273  Paged
274}
275```
276behaves like:
277```
278packet AskBrewHistory {
279  pot: 8, // Coffee Pot
280  offset: 8,
281  limit: 8
282}
283```
284
285### Checksum
286
287> checksum_declaration:\
288>    `checksum` [IDENTIFIER](#identifier) `:` [INTEGER](#integer) [STRING](#string)
289
290A *checksum* is a native type (not implemented in PDL). See your generator documentation
291for more information on how to use it.
292
293The [integer](#integer) following the name specify the bit size of the checksum value.
294The [string](#string) following the size is a value defined by the generator implementation.
295
296```
297checksum CRC16: 16 "crc16"
298```
299
300### Custom Field
301
302> custom_field_declaration:\
303>    `custom_field` [IDENTIFIER](#identifier) (`:` [INTEGER](#integer))? [STRING](#string)
304
305A *custom field* is a native type (not implemented in PDL). See your generator documentation for more
306information on how to use it.
307
308If present, the [integer](#integer) following the name specify the bit size of the value.
309The [string](#string) following the size is a value defined by the generator implementation.
310
311```
312custom_field URL "url"
313```
314
315### Test
316
317> test_declaration:\
318>    `test` [IDENTIFIER](#identifier) `{`\
319>      test_case_list\
320>    `}`
321>
322> test_case_list:\
323>    test_case (`,` test_case)* `,`?
324>
325> test_case:\
326>    [STRING](#string)
327
328A *test* declares a set of valid octet representations of a packet identified by its name.
329The generator implementation defines how to use the test data.
330
331A test passes if the packet parser accepts the input; if you want to test
332the values returned for each field, you may specify a derived packet with field values enforced using
333constraints.
334
335```
336packet Brew {
337  pot: 8,
338  addition: CoffeeAddition
339}
340
341test Brew {
342  "\x00\x00",
343  "\x00\x04"
344}
345
346// Fully Constrained Packet
347packet IrishCoffeeBrew: Brew(pot = 0, additions_list = Whisky) {}
348
349test IrishCoffeeBrew {
350  "\x00\x04"
351}
352```
353
354## Constraints
355
356> constraint:\
357>    [IDENTIFIER](#identifier) `=` [IDENTIFIER](#identifier) | [INTEGER](#integer)
358>
359> constraint_list:\
360>    constraint (`,` constraint)* `,`?
361
362A *constraint* defines the value of a parent field.
363The value can either be an [enum](#enum) tag or an [integer](#integer).
364
365```
366group Additionable {
367  addition: CoffeAddition
368}
369
370packet IrishCoffeeBrew {
371  pot: 8,
372  Additionable {
373    addition = Whisky
374  }
375}
376
377packet Pot0IrishCoffeeBrew: IrishCoffeeBrew(pot = 0) {}
378```
379
380## Fields
381
382> field_list:\
383>    field (`,` field)* `,`?
384>
385> field:\
386>    [checksum_field](#fields-checksum) |\
387>    [padding_field](#fields-padding) |\
388>    [size_field](#fields-size) |\
389>    [count_field](#fields-count) |\
390>    [payload_field](#fields-payload) |\
391>    [body_field](#fields-body) |\
392>    [fixed_field](#fields-fixed) |\
393>    [reserved_field](#fields-reserved) |\
394>    [array_field](#fields-array) |\
395>    [scalar_field](#fields-scalar) |\
396>    [typedef_field](#fields-typedef) |\
397>    [group_field](#fields-group)
398
399A field is either:
400- a [Scalar](#fields-scalar) field
401- a [Typedef](#fields-typedef) field
402- a [Group](#fields-group) field
403- an [Array](#fields-array) field
404- a [Size](#fields-size) field
405- a [Count](#fields-count) field
406- a [Payload](#fields-payload) field
407- a [Body](#fields-body) field
408- a [Fixed](#fields-fixed) field
409- a [Checksum](#fields-checksum) field
410- a [Padding](#fields-padding) field
411- a [Reserved](#fields-reserved) field
412
413### Scalar {#fields-scalar}
414
415> scalar_field:\
416>    [IDENTIFIER](#identifier) `:` [INTEGER](#integer)
417
418A *scalar* field defines a numeric value with a bit size.
419
420```
421struct Coffee {
422  temperature: 8
423}
424```
425
426### Typedef {#fields-typedef}
427
428> typedef_field:\
429>    [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier)
430
431A *typedef* field defines a field taking as value either an [enum](#enum), [struct](#struct),
432[checksum](#checksum) or a [custom_field](#custom-field).
433
434```
435packet LastTimeModification {
436  coffee: Coffee,
437  addition: CoffeeAddition
438}
439```
440
441### Array {#fields-array}
442
443> array_field:\
444>    [IDENTIFIER](#identifier) `:` [INTEGER](#integer) | [IDENTIFIER](#identifier) `[`\
445>      [SIZE_MODIFIER](#size-modifier) | [INTEGER](#integer)\
446>    `]`
447
448An *array* field defines a sequence of `N` elements of type `T`.
449
450`N` can be:
451- An [integer](#integer) value.
452- A [size modifier](#size-modifier).
453- Unspecified: In this case the array is dynamically sized using a
454[*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count).
455
456`T` can be:
457- An [integer](#integer) denoting the bit size of one element.
458- An [identifier](#identifier) referencing an [enum](#enum), a [struct](#struct)
459or a [custom field](#custom-field) type.
460
461The size of `T` must always be a multiple of 8 bits, that is, the array elements
462must start at byte boundaries.
463
464```
465packet Brew {
466   pots: 8[2],
467   additions: CoffeeAddition[2],
468   extra_additions: CoffeeAddition[],
469}
470```
471
472### Group {#fields-group}
473
474> group_field:\
475>    [IDENTIFIER](#identifier) (`{` [constraint_list](#constraints) `}`)?
476
477A *group* field inlines all the fields defined in the referenced group.
478
479If a [constraint list](#constraints) constrains a [scalar](#fields-scalar) field
480or [typedef](#fields-typedef) field with an [enum](#enum) type, the field will
481become a [fixed](#fields-fixed) field.
482The [fixed](#fields-fixed) field inherits the type or size of the original field and the
483value from the constraint list.
484
485See [Group Declaration](#group) for more information.
486
487### Size {#fields-size}
488
489> size_field:\
490>    `_size_` `(` [IDENTIFIER](#identifier) | `_payload_` | `_body_` `)` `:` [INTEGER](#integer)
491
492A *\_size\_* field is a [scalar](#fields-scalar) field with as value the size in octet of the designated
493[array](#fields-array), [*\_payload\_*](#fields-payload) or [*\_body\_*](#fields-body).
494
495```
496packet Parent {
497  _size_(_payload_): 2,
498  _payload_
499}
500
501packet Brew {
502  pot: 8,
503  _size_(additions): 8,
504  additions: CoffeeAddition[]
505}
506```
507
508### Count {#fields-count}
509
510> count_field:\
511>    `_count_` `(` [IDENTIFIER](#identifier) `)` `:` [INTEGER](#integer)
512
513A *\_count\_* field is a [*scalar*](#fields-scalar) field with as value the number of elements of the designated
514[array](#fields-array).
515
516```
517packet Brew {
518  pot: 8,
519  _count_(additions): 8,
520  additions: CoffeeAddition[]
521}
522```
523
524### Payload {#fields-payload}
525
526> payload_field:\
527>    `_payload_` (`:` `[` [SIZE_MODIFIER](#size-modifier) `]` )?
528
529A *\_payload\_* field is a dynamically sized array of octets.
530
531It declares where to parse the definition of a child [packet](#packet) or [struct](#struct).
532
533A [*\_size\_*](#fields-size) or a [*\_count\_*](#fields-count) field referencing
534the payload induce its size.
535
536If used, a [size modifier](#size-modifier) can alter the octet size.
537
538### Body {#fields-body}
539
540> body_field:\
541>    `_body_`
542
543A *\_body\_* field is like a [*\_payload\_*](#fields-payload) field with the following differences:
544- The body field is private to the packet definition, it's accessible only when inheriting.
545- The body does not accept a size modifier.
546
547### Fixed {#fields-fixed}
548
549> fixed_field:\
550>    `_fixed_` `=` \
551>      ( [INTEGER](#integer) `:` [INTEGER](#integer) ) |\
552>      ( [IDENTIFIER](#identifier) `:` [IDENTIFIER](#identifier) )
553
554A *\_fixed\_* field defines a constant with a known bit size.
555The constant can be either:
556- An [integer](#integer) value
557- An [enum](#enum) tag
558
559```
560packet Teapot {
561  _fixed_ = 42: 8,
562  _fixed_ = Empty: CoffeeAddition
563}
564```
565
566### Checksum {#fields-checksum}
567
568> checksum_field:\
569>    `_checksum_start_` `(` [IDENTIFIER](#identifier) `)`
570
571A *\_checksum_start\_* field is a zero sized field that acts as a marker for the beginning of
572the fields covered by a checksum.
573
574The *\_checksum_start\_* references a [typedef](#fields-typedef) field
575with a [checksum](#checksum) type that stores the checksum value and selects the algorithm
576for the checksum.
577
578```
579checksum CRC16: 16 "crc16"
580
581packet CRCedBrew {
582  crc: CRC16,
583  _checksum_start_(crc),
584  pot: 8,
585}
586```
587
588### Padding {#fields-padding}
589
590> padding_field:\
591>    `_padding_` `[` [INTEGER](#integer) `]`
592
593A *\_padding\_* field immediately following an array field pads the array field with `0`s to the
594specified number of **octets**.
595
596```
597packet PaddedCoffee {
598  additions: CoffeeAddition[],
599  _padding_[100]
600}
601```
602
603### Reserved {#fields-reserved}
604
605> reserved_field:\
606>    `_reserved_` `:` [INTEGER](#integer)
607
608A *\_reserved\_* field adds reserved bits.
609
610```
611packet DeloreanCoffee {
612  _reserved_: 2014
613}
614```
615
616## Tokens
617
618### Integer
619
620> INTEGER:\
621>    HEXVALUE | INTVALUE
622>
623> HEXVALUE:\
624> &nbsp;&nbsp; `0x` | `0X` HEXDIGIT<sup>+</sup>
625>
626> INTVALUE:\
627> &nbsp;&nbsp; DIGIT<sup>+</sup>
628>
629> HEXDIGIT:\
630> &nbsp;&nbsp; DIGIT | [`a`-`f`] | [`A`-`F`]
631>
632> DIGIT:\
633> &nbsp;&nbsp; [`0`-`9`]
634
635A integer is a number in base 10 (decimal) or in base 16 (hexadecimal) with
636the prefix `0x`
637
638### String
639
640> STRING:\
641> &nbsp;&nbsp; `"` (!`"` __ANY__)* `"`
642
643A string is sequence of character. It can be multi-line.
644
645### Identifier
646
647> IDENTIFIER: \
648> &nbsp;&nbsp; ALPHA (ALPHANUM | `_`)*
649>
650> ALPHA:\
651> &nbsp;&nbsp; [`a`-`z`] | [`A`-`Z`]
652>
653> ALPHANUM:\
654> &nbsp;&nbsp; ALPHA | DIGIT
655
656An identifier is a sequence of alphanumeric or `_` characters
657starting with a letter.
658
659### Size Modifier
660
661> SIZE_MODIFIER:\
662> &nbsp;&nbsp; `+` INTVALUE
663
664A size modifier alters the octet size of the field it is attached to.
665For example, `+ 2` defines that the size is 2 octet bigger than the
666actual field size.
667
668### Comment
669
670> COMMENT:\
671> &nbsp;&nbsp; BLOCK_COMMENT | LINE_COMMENT
672>
673> BLOCK_COMMENT:\
674> &nbsp;&nbsp; `/*` (!`*/` ANY) `*/`
675>
676> LINE_COMMENT:\
677> &nbsp;&nbsp; `//` (!\n ANY) `//`
678
679### Whitespace
680
681> WHITESPACE:\
682> &nbsp;&nbsp; ` ` | `\t` | `\n`
683