Files
bproto/docs/syntax.md
2025-04-14 14:43:03 +02:00

9.0 KiB

Syntax Documentation

bproto uses a custom syntax bproto (file extension .bproto). Each protocol is described in a single bproto file.

For Beginners, a simple example of a protocol definition and usage can be found here.

The protocol definitions consist of the following basic components: messages, enums, bitfields, and the protocol tag line.

Table of Contents

Names and IDs

Names of enums, bitfields, messages, and fields support any letter (lower and uppercase), numbers, and underscores.

Regular expression: [a-zA-Z0-9_]+

Numbers/IDs are decimal encoded numbers. Trailing zeros are ignored.

Regular expression: [0-9]+

Protocol Tag Line

This is a short description of the protocol consisting of a name and a version number. This must be the first line of any bproto definition file.

Syntax:

protocol <name> version <version>

Example:

protocol myCustomAirplaneProtocol version 2

The name should identify the protocol in the implementation context (like robotControlProtocol or weatherStationTelemetryDataStream). The version number is used to differentiate between different iterations of the protocol. Different versions of the same protocol are incompatible.

For detailed information on naming conventions and versioning strategies, please refer to the compatibility documentation.

Message

A message is a collection of fields that can be serialized and deserialized to be sent over the wire or channel. A message should only be a transport container and should not, if possible, be stored permanently.

Syntax:

message [<Message ID>] <Message Name> {
    // List of fields
    [<field ID #0>] <field name #0> : <field type #0>,
    [<field ID #1>] <field name #1> : <field type #1>,
    ....
    [<field ID #N>] <field name #N> : <field type #N>,
}

Example:

message [1] EngineSensorData {
    [0] engine_thrust_left  : float32,
    [1] engine_thrust_right : float32,
    [2] fuel_tanks_fill     : uint32[8], // Fill levels of 8 fuel tanks
    [3] engine_fault_left   : bool,
    [4] engine_fault_right  : bool
}
  • Message ID: Unique identifier within a protocol definition used to differentiate different messages from each other. The Message ID should be between 0 and 255.
  • Message Name: Unique name given to this message. This will be used to identify a field in the protocol implementation.

Fields

A message can have as many fields as necessary. These are comparable to members in a class or fields in a C-struct. A field has an ID, Name, and a datatype.

Syntax: [<ID>] <Name> : <datatype> Example: [2] fanSpeed : float32

  • Name: This is a unique name given to the field. This will be used to identify a field in the protocol implementation.
  • ID: A unique identifier used to order the fields in the encoding/decoding. More about serialization can be found here.
  • datatype: What type of data to store in this field.

Datatypes

Datatypes in bproto are independent of language and are translated into the target language-specific type. Every Field in a message must have a datatype.

Here is a list of datatypes available:

bproto Datatype Encode Size (bytes) Python C Value Range Description
uint8 1 int uint8_t 0 to 255 Unsigned 8-bit integer
uint16 2 int uint16_t 0 to 65,535 Unsigned 16-bit integer
uint32 4 int uint32_t 0 to 4,294,967,295 Unsigned 32-bit integer
int64 8 int uint64_t 0 to 18,446,744,073,709,551,615 Unsigned 64-bit integer
int8 1 int int8_t -128 to 127 Signed 8-bit integer
int16 2 int int16_t -32,768 to 32,767 Signed 16-bit integer
int32 4 int int32_t -2,147,483,648 to 2,147,483,647 Signed 32-bit integer
int64 8 int int64_t -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 Signed 64-bit integer
float32 4 float float 1.2E-38 to 3.4E+38 32-bit floating point number
float64 8 float double 2.3E-308 to 1.7E+308 64-bit floating point number
string[<N>] N str char[] N/A Fixed-size string
char 1 str char Single character Single character
bool 1 bool bool true or false Boolean value

Every datatype in this list can be used in a fixed-size array by using this format:

Syntax: <datatype>[<array_size>] Example: float[]

A special case is string. Strings must be declared as an array because their size must be known from the start.

There are also bits and enum corresponding to bitfields and enums. They are a bit special and are not able to be used as an array. Bitfields and enums can be declared inline. More details can be found in the sections about enums and bitfields.

How different datatypes are encoded can be found here.

Bitfields

A compact representation of multiple boolean flags within a single byte or group of bytes, optimizing space for binary communication. Bitfields are treated as datatypes.

Syntax:

bits <bitfield name> {
    <1st bit>, <2nd bit>, ...
}

Example:

bits engine_enables {
    engine_left, engine_right
}

Each bit can be either 0 or 1 (true or false), represented as a bool in the target language. More details on how Bitfields are encoded in the corresponding language can be found here.

Bitfields, like Enumerations, can be declared inline in a message.

Syntax:

[<Field ID>] <Field Name> : bits {
    <1st bit>, <2nd bit>, ...
}

Example:

    [1] lightsEnable: bits {
        Front, Spot, Key, BackLight
    }

Bitfield naming when using them inline is found here.

Enumerations

A set of named integer values that represent discrete states or options. Enums enhance code clarity by using descriptive names instead of raw numeric values. Enumerations or Enums in bproto are comparable to C or Python enums. More details on how Enums are encoded in the corresponding language can be found here. Enums are treated as datatypes in bproto.

Each Enum item represents a positive (or zero) numeric value. These can be implicitly generated by bproto, incrementing by 1. The value of the Enum value therefore depends on the declaration order. This may lead to bugs and issues when updating one client/receiver's protocol but not the counterparts. For more info about this problem, see here.

Enum values can also be set explicitly, which eliminates this problem.

Syntax:

enum <enum name> {
    <Name #0> (= <Value #0>),
    <Name #1> (= <Value #1>),
    ...
    <Name #N> (= <Value #N>),
}

Example:

dangerLvl: enum {
    WARNING,
    MELTDOWN,
    ERROR = 10,
}

Syntax:

[<Field ID>] <Field Name> : enum {
    <Name #0> (= <Value #0>),
    <Name #1> (= <Value #1>),
    ...
    <Name #N> (= <Value #N>),
}

Example:

    [6] dangerLvl: enum {
        WARNING, 
        MELTDOWN = 5,
        ERROR, 
    }

Enumeration naming when using them inline is found here.

Comments

bproto supports C-style comments (with // ... and /* ... */).