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 /* ... */).