In this section we describe the serial protocol.
Every exported method defined using the
interface() function (see the
usage_device section) is assigned a number between 0 and 254 in order of
appearance. The number 0 maps to the first method, the number 1 maps to the
second method, etc.
There are two types of calls to the device: the method discovery call and a remote procedure call. In both cases, communication is initiated by the host by writing one byte to the serial device.
Method discovery is initiated by the host by writing one byte with value
0xff to the serial device.
The device will respond with a header and a list of method descriptions
delimited by an end of string signature (
\0). The list is terminated by an
additional end of line signature. The header format is given in the following
||Protocol version (major, minor, patch).|
Each method description consists of a struct formatted function signature and
a documentation string separated by a
;. The function signature starts with
a struct formatted return type (if any), followed by a
: and a space
delimited list of struct formatted parameter types. The format of the
documentation string is described in the usage_device section.
For our example, the response for the method discovery request will look as follows.
h: h;inc: Increment a value. @a: Value. @return: a + 1.\0 : B;set_led: Set LED brightness. @brightness: Brightness.\0 \0
For more complex objects, like Tuples, Objects and Vectors, some more syntax is needed to communicate their structure to the host.
A Tuple type is encoded as a compound type, e.g.,
hB (a 16-bit integer and
a byte). It can be recognised by the absence of a space between the type
signatures. Note that a concatenated or nested Tuple type can not be recognised
from its signature, e.g.,
hB concatenated with
ff is indistinguishable
An Object type is encoded as a compound type like a Tuple, but its type
signature is enclosed in parentheses
), which makes it possible
to communicate its structure to the host, e.g., the concatenation of
(hB)(ff) and the type signature of a nested Object may look
A Vector type signature is enclosed in brackets
]. So a vector of
16-bit integers will have as type signature
Finally, any arbitrary combination of Tuples, Objects and Vectors can be made,
resulting in type signatures like
[((hB)f)], i.e., a Vector of Objects that
contain a Tuple of which the first element is an other Object
the second element is a float
Remote procedure calls¶
A remote procedure call is initiated by the host by writing one byte to the serial device of which the value maps to one of the exported methods (i.e., 0 maps to the first method, 1 to the second, etc.). If this method takes any parameters, their values are written to the serial device. After the parameter values have been received, the device executes the method and writes its return value (if any) back to the serial device.
All native C types (
double, etc.), Tuples, Objects,
Vectors and any combination of these are currently supported. The host is
responsible for packing and unpacking of the values.
There is currently one built-in function.
|0||ping||Echo a value.||int data: Value.||int: Value of data.|
There does not seem to be any noticeable overhead of the library. We tested the
throughput by calling the
ping() function repeatedly at baud rates ranging
from 600 baud to 115200 baud.
|baud rate||calls per second|
The number of calls per second scales linearly with the baud rate, even at the highest speed, there is no measurable overhead.