10.2. Syntax of Message Definitions
This page documents the accepted syntax of LN message-definition files as
implemented by python/links_and_nodes_base/message_definitions.py.
It describes the file format itself. For details on how message-definition
files are found on disk, see Message Definitions.
10.2.1. General format
A message definition is a plain text file. Empty lines are ignored.
Lines starting with # are comments. Inline comments are also allowed:
everything after # on a line is ignored.
A regular field line has this shape:
TYPE FIELD_NAME
Static arrays append a count in square brackets:
TYPE FIELD_NAME[COUNT]
Imported sub-types use define:
define LOCAL_TYPE_NAME as "other/message_definition/name"
Service and event definitions add section markers:
service
request
...
response
...
event
connect
...
call
...
The first non-empty, non-comment line may be one of:
nothing special: a regular message definition
service: a service definition withrequestandresponsesectionsevent: an event definition withconnectandcallsections
If the first non-empty line is service or event, the remaining lines
must follow the corresponding section syntax.
10.2.2. Primary types
The built-in scalar element types accepted by the parser are:
floatorfloat32_tdoubleorfloat64_tcharint8_tuint8_tint16_torshortuint16_tint32_torintuint32_tint64_tuint64_t
Each field is stored as one or more values of the chosen element type.
There is no separate boolean type; use an integer type such as uint8_t
when needed.
10.2.3. Regular message definitions
A regular message definition is just a sequence of field declarations and
optional define statements.
Example:
define pose_t as "my_robot/pose"
uint64_t seq
pose_t pose
double covariance[6*6]
Imported sub-types become usable like built-in types. They can be used as:
a single field, for example
pose_t posea static array, for example
pose_t poses[4]a dynamic field, for example
pose_t* posesin service/event or other dynamic message definitions
10.2.4. Static arrays and multi-dimensional data
Static arrays are written as FIELD_NAME[COUNT]. COUNT is evaluated as a
Python integer expression, so forms such as [12] and [3*4] are accepted.
LN message definitions do not provide dedicated multi-dimensional syntax. Instead, N-D arrays are represented as a flat 1-D array with the product of the dimensions as the count.
Example:
double frame[3*4]
This is the convention used in
share/message_definitions/ln/frame34. For such flattened N-D arrays, LN
uses the standard C row-major convention. In the 3*4 example, the first
index is the row and the second index is the column, and consecutive elements
of one row are adjacent in memory.
For example, a logical matrix element frame[r][c] is stored at:
frame[r * 4 + c]
Use the same row-major convention consistently in publishers, subscribers, service providers, and any generated or handwritten bindings.
10.2.5. Imported sub-types with define
Sub-types are imported with:
define TYPE_NAME as "relative/or/global/message_definition_name"
Rules:
TYPE_NAMEis the local type name used later in the file.The imported path must be written in double quotes.
TYPE_NAMEmust not contain a double quote.The referenced file is looked up first relative to the current message definition file and then through the normal message-definition search path; see Message Definitions.
After a
define, the imported type can be used wherever a primary type can be used, subject to the same static or dynamic rules.
Example:
define value_t as "value"
value_t* values
10.2.6. Services
A service definition starts with service. It can then contain two sections:
requestfor request fieldsresponsefor response fields
Example:
service
request
char* message
response
char* error_message
char* result
Fields declared after request belong to the request payload.
Fields declared after response belong to the response payload.
define statements may appear inside service files and can be used by either
section.
10.2.7. Events
An event definition starts with event. It uses two section markers:
connectfor the subscription/filter partcallfor the emitted event payload
Example:
event
connect
char* event_pattern
char* name_pattern
call
char* event
char* name
Internally, LN parses connect and call like the request and response
parts of a service definition.
10.2.8. Dynamic fields
Dynamic fields are written by appending * to the type name:
char* string
uint8_t* data
pyobject* values
Accepted properties:
*can be used with both primary types and imported sub-types.Arrays of pointer types are not supported. A declaration such as
char* names[4]is rejected.Dynamic fields make the message definition dynamic.
The parser also enforces a length-field convention. A dynamic field named
data uses a companion field named data_len of type uint32_t.
If data_len is not written explicitly, LN inserts it automatically
immediately before data in the parsed field layout. If it already exists
but is not directly before the dynamic field, LN moves it there in the parsed
layout.
That means these two request sections are equivalent:
request
uint8_t* data
request
uint32_t data_len
uint8_t* data
Dynamic fields are the accepted representation for variable-length payloads. They are used heavily in service and event definitions, and the parser also accepts them in other dynamic message definitions. By contrast, the regular fixed-size topic layout is based on non-pointer fields and static arrays.
10.2.9. Field-name restrictions
Field names must be plain identifiers without punctuation. The parser rejects field names containing any of these characters:
; . , + - * / { } ( ) # $ ä ö ü ? ' ` " \
In practice, use simple ASCII names such as count, frame,
error_message, or obj_req_single.
Within one request or regular message, a field name may only be used once. Within one response section, a response field name may also only be used once. Request and response sections are checked independently.
10.2.10. Notes and examples
Examples from the source tree:
share/message_definitions/ln/frame34demonstrates flattened N-D array storage viadouble frame[3*4].share/message_definitions/ln/stringshows a dynamic string payload:char* string.share/message_definitions/ln/string_requestshows a service definition.share/message_definitions/ln/resource_eventshows an event definition.share/message_definitions/tests/time_serviceshows primary types, imported sub-types, static arrays, and dynamic fields in the same file.
If you need the search-path and lookup rules for these files, continue with Message Definitions.