Simple RPC implementation for Arduino.

https://img.shields.io/github/last-commit/jfjlaros/simpleRPC.svg https://github.com/jfjlaros/simpleRPC/actions/workflows/arduino-package.yml/badge.svg https://readthedocs.org/projects/simplerpc/badge/?version=latest https://img.shields.io/github/release-date/jfjlaros/simpleRPC.svg https://img.shields.io/github/release/jfjlaros/simpleRPC.svg https://www.ardu-badge.com/badge/simpleRPC.svg https://img.shields.io/github/languages/code-size/jfjlaros/simpleRPC.svg https://img.shields.io/github/languages/count/jfjlaros/simpleRPC.svg https://img.shields.io/github/languages/top/jfjlaros/simpleRPC.svg https://img.shields.io/github/license/jfjlaros/simpleRPC.svg

This library provides a simple way to export Arduino functions as remote procedure calls. The exported method definitions are communicated to the host, which is then able to generate an API interface.

Features:

  • For each method, only one line of code is needed for exporting.

  • Automatic parameter- and return type inference.

  • Support for all native C types and strings.

  • Support for arbitrary functions and class methods.

  • Optional function and parameter naming and documentation.

  • Support for PROGMEM’s F() macro to reduce memory footprint.

  • Support for compound data structures like Tuples, Objects (Tuples with internal structure), Vectors and arbitrary combinations of these.

  • Support for reading multidimensional C arrays (e.g., int**).

  • Support for different types of I/O interfaces via plugins, e.g.,

    • Bluetooth.

    • Ethernet (untested).

    • Hardware serial.

    • RS485 serial.

    • Software serial (untested).

    • USB serial.

    • WiFi.

    • Wire (untested).

  • Support for using multiple interfaces at the same time.

The Arduino library is independent of any host implementation, a Python API client library is provided as a reference implementation.

Please see ReadTheDocs for the latest documentation.

Quick start

Export any function e.g., digitalRead() and digitalWrite() using the interface() function.

#include <simpleRPC.h>

void setup() {
  Serial.begin(9600);
}

void loop() {
  interface(Serial, digitalRead, "", digitalWrite, "");
}

These functions are now available on the host under names method0() and method1().

The documentation string can be used to name and describe the method.

interface(
  Serial,
  digitalRead,
    "digital_read: Read digital pin. @pin: Pin number. @return: Pin value.",
  digitalWrite,
    "digital_write: Write to a digital pin. @pin: Pin number. @value: Pin value.");

This is reflected on the host, where the methods are now named digital_read() and digital_write() and where the provided API documentation is also available. In the client reference implementation documentation, contains an example on how this works.

Further reading

Please read section Usage for more information about exporting normal functions, class member functions and documentation conventions.

If you want to create your own host library implementation for other programming languages, the section Protocol should help you on your way.

Introduction

A remote procedure call to an Arduino device is a common way to read sensor values or to send control signals. This library provides a simple way to export any Arduino function, including API documentation.

Motivation

Suppose we have an number of functions that we want to export as remote procedure calls.

int testInt() {
  return 1;
}

float testFloat() {
  return 1.6180339887;
}

int add(int a, int b) {
  return a + b;
}

A common way of making functions available is to map each of the functions to an unique value. The Arduino reads one byte from an I/O device and it uses this to select the appropriated function.

If a function takes parameters, their values need to be read from the I/O device before calling the function. Any return value needs to be written to the I/O device after calling the function.

A typical implementation of such an approach is shown below.

void loop() {
  int iValue, iParamA, iParamB;
  float fValue;

  if (Serial.available()) {
    switch (Serial.read()) {
      case 0x00:
        iValue = testInt();
        Serial.write((byte*)&iValue, 2);
        break;
      case 0x01:
        fValue = testFloat();
        Serial.write((byte*)&fValue, 4);
        break;
      case 0x02:
        Serial.readBytes((char*)&iParamA, 2);
        Serial.readBytes((char*)&iParamB, 2);
        iValue = add(iParamA, iParamB);
        Serial.write((byte*)&iValue, 2);
        break;
    }
  }
}

In this implementation, the methods Serial.write() and Serial.readBytes() are used to encode and decode values.

On the host, the parameter values need to be packed before sending them to the Arduino, Any return value needs to be unpacked. In the following example, we assume that a serial connection is made using the pySerial library. The functions pack and unpack are provided by the struct library.

# Call the testInt() function.
connection.write(pack('B', 0x00))
print(unpack('<h', connection.read(2))[0])

# Call the testFloat() function.
connection.write(pack('B', 0x01))
print(unpack('<f', connection.read(4))[0])

# Call the add() function.
connection.write(pack('B', 0x02))
connection.write(pack('<h', 1))
connection.write(pack('<h', 2))
print(unpack('<h', connection.read(2))[0])

An implementation like the one described above uses very little bandwidth and does not require any heavy external libraries on the Arduino. The downsides of such an approach are clear from the example:

  • Quite a bit of boilerplate code is needed.

  • Changes have to be made on both the device and the host, keeping the implementations in sync may become difficult.

  • A lot of low-level knowledge of the device methods and their types is required.

This is where the simpleRPC library comes in, like the implementation above, it only communicates values but has none of the downsides of an ad hoc protocol.

Installation

Arduino IDE

To install this library in the Arduino IDE, please follow these comprehensive installation instructions.

Arduino CLI

The latest version can be installed with the Arduino CLI interface using the following command.

arduino-cli lib install simpleRPC

Manual installation

Latest release

Navigate to the latest release and either download the .zip or the .tar.gz file and unpack the downloaded archive.

From source

The source is hosted on GitHub, use the following command to install the latest development version.

git clone https://github.com/jfjlaros/simpleRPC.git

Usage

Include the header file to use the simpleRPC library.

#include <simpleRPC.h>

The library provides the interface() function, which is responsible for all communication with the host. To use this function, first initialize the standard Serial class instance to enable communication using the hardware serial interface. This is done using the begin() method in the setup() body.

void setup() {
  Serial.begin(9600);
}

Please see the Plugins section for using other I/O interfaces.

Exporting C functions

Standard C functions are exported as RPC methods by calling the interface() function from the loop() body. This function accepts (function, documentation) pairs as parameters.

Interface function parameters.

parameter

description

0

I/O class instance.

1

Function one.

2

Documentation string of function one.

3

Function two.

4

Documentation string of function two.

A documentation string consists of a list of key-value pairs in the form key: value delimited by the @ character. The first pair in this list is reserved for the RPC method name and its description, all subsequent pairs are used to name and describe parameters or to describe a return value.

Documentation string.

field prefix

key

value

RPC method name.

RPC method description.

@

Parameter name.

Parameter description.

@

return

Return value description.

The documentation string may be incomplete or empty. The following defaults are used for missing keys. All descriptions may be empty.

Default names.

key

default

RPC method name.

method followed by a number, e.g., method0.

Parameter name.

arg followed by a number, e.g., arg0.

return

return

To reduce the memory footprint, the F() macro can be used in the interface() function. This stores the documentation string in program memory instead of SRAM. For more information, see the progmem documentation.

Example

Suppose we want to export a function that sets the brightness of an LED and a function that takes one parameter and returns a value.

void setLed(byte brightness) {
  analogWrite(LED_BUILTIN, brightness);
}

int inc(int a) {
  return a + 1;
}

Exporting these functions goes as follows:

void loop() {
  interface(
    Serial,
    inc, "inc: Increment a value. @a: Value. @return: a + 1.",
    setLed, "set_led: Set LED brightness. @brightness: Brightness.");
}

We can now build and upload the sketch.

The client reference documentation includes an example on how these methods can be accessed from the host.

Exporting class methods

Class methods are different from ordinary functions in the sense that they always operate on an object. This is why both a function pointer and a class instance need to be provided to the interface() function. To facilitate this, the pack() function can be used to combine a class instance and a function pointer before passing them to interface().

For a class instance c of class C, the class method f() can be packed as follows:

pack(&c, &C::f)

The result can be passed to interface().

Example

Suppose we have a library named led which provides the class LED. This class has a method named setBrightness.

#include "led.h"

LED led(LED_BUILTIN);

Exporting this class method goes as follows:

void loop() {
  interface(
    Serial,
    pack(&led, &LED::setBrightness),
      "set_led: Set LED brightness. @brightness: Brightness.");
}

Complex objects

In some cases, basic C types and C strings are not sufficient or convenient. This is why simpleRPC supports higher order objects described in detail in the Tuples and Vectors sections.

Arbitrary combinations of these higher order objects can be made to construct complex objects.

In the following example, we create a 2-dimensional matrix of integers, a Vector of Tuples and a Tuple containing an integer, a Vector and an other Tuple respectively.

Vector<Vector<int> > matrix;

Vector<Tuple<int, char> > v;

Tuple<int, Vector<int>, Tuple<char, long> > t;

These objects can be used as parameters as well as return values. Note that these objects, like any higher order data structure should be passed by reference.

C arrays

Passing a C array as a parameter is supported, but since in general it is not possible to deduce the size or internal structure of an object it is not possible to return a C array. The closely related Vector should be used in this case.

In the following example, an integer C array is passed to a function.

void readArray(int* a) {}

Multidimensional arrays are implemented as NULL terminated arrays of pointers. This allows for structures that do not have a fixed length in any dimension, e.g., a two-dimensional array int** does not have to be rectangular.

Plugins

The library supports I/O plugins in order to enable RPC communication over a range of interfaces. Currently, the following plugins are implemented.

Plugins.

name

description

status

Serial

The standard Arduino Serial interface.

working

SoftwareSerial

The Arduino SoftwareSerial interface.

untested

HalfDuplexStream

RS485 serial interface.

working

EthernetClient

Arduino Ethernet interface.

untested

WiFiClient

Arduino WiFi interface.

working

Wire

I2C / TWI Wire interface.

untested

A plugin inherits from Stream and should override the following methods.

Methods.

name

description

Constructor.

int available()

Number of bytes available for reading.

int read()

Read a single byte or -1 upon error.

int peek()

Preview the next byte.

size_t write(uint8_t)

Write a single byte, return the number of bytes written.

Usually, the I/O plugin is declared as a global object instance in the sketch and initialized in the setup() function. See the RS485 sketch for an example that uses a custom I/O plugin.

Multiple I/O interfaces

It is possible to use multiple I/O interfaces at the same time. This can be done by either serving a different set of methods on each interface or by serving the same set of methods on multiple interfaces.

To serve different methods on each interface, the interface() function is simply used multiple times.

Example

Suppose we have set up two I/O interfaces named Serial and SerialUSB, we serve different methods on each of the interfaces as follows.

void loop() {
  interface(
    Serial,
    inc, F("inc: Increment a value. @a: Value. @return: a + 1."));
  interface(
    SerialUSB,
    setLed, F("set_led: Set LED brightness. @brightness: Brightness."));
}

Alternatively, it is possible to serve the same set of methods on multiple interfaces. This can be done by passing a Tuple of pointers to the interfaces as the first parameter of the interface() function.

Example

Suppose we have set up two I/O interfaces named Serial and SerialUSB, we serve the same methods on both interfaces by grouping pointers to these interfaces with the pack() function as follows.

void loop() {
  interface(
    pack(&Serial, &SerialUSB),
    inc, F("inc: Increment a value. @a: Value. @return: a + 1."));
}

Finally, it is possible to combine both of the strategies described above.

Protocol

In this section we describe the RPC protocol.

Every exported method defined using the interface() function (see the Usage 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 I/O device.

Method discovery

Method discovery is initiated by the host by writing one byte with value 0xff to the I/O 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 string signature. The header format is given in the following table.

Header format.

size

delimiter

value

description

\0

simpleRPC

Protocol identifier.

3

\3\0\0 (example)

Protocol version (major, minor, patch).

1

< or >

Endianness, < for little-endian, > for big-endian.

1

H (example)

Type of size_t, needed for indexing vectors.

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 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 and Vectors, some more syntax is needed to communicate their structure to the host.

A Tuple type is encoded as a compound type enclosed in parentheses ( and ), e.g., (hB) (a 16-bit integer and a byte). The parentheses make it possible to communicate its structure to the host, e.g., the concatenation of (hB) and (ff) is (hB)(ff) and the type signature of a nested Tuple may look like this ((hB)(ff)).

A Vector type signature is enclosed in brackets [ and ]. So a vector of 16-bit integers will have as type signature [h].

Finally, any arbitrary combination of Tuples and Vectors can be made, resulting in type signatures like [((hB)f)], i.e., a Vector of Tuples of which the first element is an other Tuple (hB) and the second element is a float f.

Remote procedure calls

A remote procedure call is initiated by the host by writing one byte to the I/O 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 I/O device. After the parameter values have been received, the device executes the method and writes its return value (if any) back to the I/O device.

All native C types (int, float, double, etc.), Tuples, Vectors and any combination of these are currently supported. The host is responsible for packing and unpacking of the values.

API documentation

RPC interface

#include <simpleRPC.h>

See the Usage section for a full description of the RPC interface.

Functions
template<class ...Ts>
void interface(Stream &io, Ts... args)

RPC interface.

The args parameter pack is a list of pairs (function pointer, documentation). The documentation string can be of type char const*, or the PROGMEM F() macro can be used to reduce memory footprint.

Parameters
  • io – Stream.

  • args – Parameter pairs (function pointer, documentation).

template<class ...Ts, class ...Us>
void interface(Tuple<Ts...> t, Us... args)

Multiple RPC interfaces.

Similar to the standard interface , but with support for multiple I/O interfaces, passed as Tuple t.

See also

interface(Stream&, Ts…)

Parameters
  • tTuple of input / output objects.

  • args – Parameter pairs (function pointer, documentation).

Tuples

#include "tuple.tcc"
Tuples

Tuples can be used to group objects of different types. A Tuple is recursively defined as being either:

  • Empty.

  • A pair (head, tail), where head is of an arbitrary type and tail is an other Tuple.

Initialisation of a Tuple can be done with a brace-initializer-list as follows.

Tuple<int, char> t {10, 'c'};

Element retrieval and assignment is described below in the Helper functions section.

Note that a Tuple, like any higher order data structure, should be passed by reference.

Class definitions
template<class...>
class Tuple

Empty Tuple.

template<class T, class ...Ts>
class Tuple<T, Ts...>

Tuple.

Helper functions

Elements of a Tuple can be retrieved in two ways, either via the head and tail member variables, or using with the get<>() helper function.

int i = t.head;
char c = t.tail.head;

int j = get<0>(t);
char d = get<1>(t)';

Likewise, assignment of an element can be done via its member variables or with the get<>() helper function.

t.head = 11;
t.tail.head = 'd';

get<0>(t) = 11;
get<1>(t) = 'd';

There are additional helper functions available for the creation of Tuples.

The function makeTuple() can be used to create a temporary Tuple to be used in a function call.

function(makeTuple('a', 'b', 10));
Functions
template<size_t k, class ...Ts>
get(Tuple<Ts...> &t)

Get the k-th element of a Tuple.

This can be used for both retrieval as well as assignment.

Parameters

t – A Tuple.

Returns

Reference to the k-th element in t.

template<class ...Ts>
Tuple<Ts...> makeTuple(Ts... args)

Make a Tuple from a parameter pack.

Parameters

args – Values to store in a Tuple.

Returns

Tuple containing args.

Vectors

#include "vector.tcc"

A Vector is a sequence container that implements storage of data elements. The type of the vector is given at initialisation time via a template parameter, e.g., int.

Vector<int> v;
Vector<int> u(12);

In this example, Vector v is of size 0 and u is of size 12. A Vector can also be initialised with a pointer to an allocated block of memory.

Vector<int> v(12, data);

The memory block is freed when the Vector is destroyed. If this is not desirable, an additional flag destroy can be passed to the constructor as follows.

Vector<int> v(12, data, false);

This behaviour can also be changed by manipulating the destroy member variable.

A Vector can be resized using the resize method.

v.resize(20);

The size member variable contains the current size of the Vector.

Element retrieval and assignment is done in the usual way.

int i = v[10];

v[11] = 9;

Note that a Vector, like any higher order data structure, should be passed by reference.

Class definition
template<class T>
class Vector

Generic Vector.

Public Functions

Vector(size_t const)

Create a Vector with size elements.

Parameters

sizeVector size.

template<size_t n>
Vector(T const (&)[n])

Create a Vector with size elements from a C array.

Parameters

arr – C array.

Vector(T*const, size_t const)

Create a Vector with size elements from a block of raw memory.

Parameters
  • ptr – Pointer to data, Vector takes ownership.

  • sizeVector size.

T *data() const

Get the underlying data.

Returns

data.

size_t size() const

Get the number of elements.

Returns

Vector size.

void resize(size_t const)

Set the number of elements.

Parameters

sizeVector size.

void clear()

Clear the contents.

void push_back(T const&)

Add an element to the back.

Parameters

el – Element.

void push_back(T const&&)

Add an element to the back.

Parameters

el – Element.

T pop_back()

Remove an element from the back.

Returns

Element.

Input / output

Convenience functions for reading and writing. A template class I, is used as an abstraction for I/O devices like serial ports, wire interfaces and network interfaces like ethernet. An overview of the required methods of an I/O plugin is described in the plugins section.

Printing
#include "print.tcc"

The following functions take care of serialisation of:

  • Values of basic types.

  • C strings (char[], char*, char const[], char const*).

  • C++ Strings.

  • PROGMEM strings (F() macro).

Finally, a print function that takes an arbitrary amount of parameters is provided for convenience.

Functions
template<class T>
void rpcPrint(Stream &io, T data)

Print a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcPrint(Stream &io, char *data)

Print a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcPrint(Stream &io, char const *data)

Print a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcPrint(Stream &io, String &data)

Print a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcPrint(Stream &io, __FlashStringHelper const *data)

Print a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T, class ...Ts>
void rpcPrint(Stream &io, T data, Ts... args)

Print any number of values.

Parameters
  • io – Stream.

  • data – Value to be printed.

  • args – Remaining values.

Reading

Read functions for deserialisation.

#include "read.tcc"
Functions
template<class T>
void rpcRead(Stream &io, T *data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T>
inline void rpcRead(Stream &io, T const *data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcRead(Stream &io, char **data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcRead(Stream &io, char const **data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcRead(Stream &io, String *data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T>
void rpcRead(Stream &io, Vector<T> *data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T>
void rpcRead(Stream &io, T **data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T, size_t n>
void rpcRead(Stream &io, Array<T, n> *data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T>
void rpcRead(Stream &io, T const **data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T>
void rpcRead(Stream &io, T ***data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

template<class ...Ts>
void rpcRead(Stream &io, Tuple<Ts...> *data)

Read a value from an stream.

Parameters
  • io – Stream.

  • data – Data.

Writing

Write functions for serialisation.

#include "read.tcc"
Functions
template<class T>
void rpcWrite(Stream &io, T *data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcWrite(Stream &io, char **data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcWrite(Stream &io, char const **data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

inline void rpcWrite(Stream &io, String *data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T>
void rpcWrite(Stream &io, Vector<T> *data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

template<class T, size_t n>
void rpcWrite(Stream &io, Array<T, n> *data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

template<class ...Ts>
void rpcWrite(Stream &io, Tuple<Ts...> *data)

Write a value to a stream.

Parameters
  • io – Stream.

  • data – Data.

Types

#include "types.tcc"

Get a struct formatted representation of the type of a value.

Type encoding examples.

type

encoding

description

bool

?

Boolean.

unsigned long int

L

Unsigned integer.

char const*

s

String.

Tuple<int, signed char, unsigned long>

ibL

Tuple (no internal structure).

Object<Object<char, int>, unsigned long>

((ci)L)

Object (internal structure is preserved).

Vector<int>

[i]

Vector.

Functions
inline void rpcTypeOf(Stream &io, bool)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, char)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, signed char)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, unsigned char)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, short int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, unsigned short int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, long int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, unsigned long int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, long long int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, unsigned long long int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, float)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, String&)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, char*)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, char const*)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, int)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void rpcTypeOf(Stream &io, double)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

template<class ...Ts>
void rpcTypeOf_(Stream &io, Tuple<Ts...> &t)

Get the types of all members of a Tuple.

Parameters
  • io – Stream.

  • tTuple.

template<class T>
void rpcTypeOf(Stream &io, Vector<T>&)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

template<class T, size_t n>
void rpcTypeOf(Stream &io, Array<T, n>&)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

template<class T>
void rpcTypeOf(Stream &io, T*)

Type encoding.

Parameters
  • io – Stream.

  • - – Value.

inline void hardwareDefs(Stream &io)

Determine endianness and type of size_t.

Parameters

io – Stream.

Function Signatures

#include "signature.tcc"
Function signature examples.

signature

encoding

description

short int f(char, float)

h: c f

Function that returns a value.

void f(char, float)

: c f

Function that does not return a value.

void f(Tuple<int, char>&, float)

: ic f

A Tuple parameter.

Object<int, char> f(float)

(ic): f

Returning an Object.

int f(Vector<signed char>&, int)

i: [b] i

A Vector parameter.

Functions
template<class T, class ...Ts>
void signature(Stream &io, T (*)(Ts...))

Get the signature of a function.

Parameters
  • io – Stream.

  • - – Function pointer.

Returns

Function signature.

template<class T, class C, class ...Ts>
void signature(Stream &io, T (C::*)(Ts...))

Get the signature of a function.

Parameters
  • io – Stream.

  • - – Function pointer.

Returns

Function signature.

template<class ...Ts>
void signature(Stream &io, void (*f)(Ts...))

Get the signature of a function.

Parameters
  • io – Stream.

  • - – Function pointer.

Returns

Function signature.

template<class C, class ...Ts>
void signature(Stream &io, void (C::*)(Ts...))

Get the signature of a function.

Parameters
  • io – Stream.

  • - – Function pointer.

Returns

Function signature.

RPC function calls

#include "rpcCall.tcc"
Functions
template<class T, class ...Ts>
void rpcCall(Stream &io, T (*f)(Ts...))

Call a function.

Parameter values for f are read from io, after which f is called. Any return value is written back to io.

Parameters
  • io – Stream.

  • f – Function pointer.

template<class C, class P, class T, class ...Ts>
void rpcCall(Stream &io, Tuple<C*, T (P::*)(Ts...)> t)

Call a class method.

See also

rpcCall(Stream&, T (*)(Ts…))

Parameters
  • io – Stream.

  • tTuple consisting of a pointer to a class instance and a pointer to a class method.

Deleting objects

#include "del.tcc"
Functions
template<class T>
void rpcDel(T*)

Delete a value.

Parameters

data – Data.

template<class T>
void rpcDel(T **data)

Delete a value.

Parameters

data – Data.

template<class T>
void rpcDel(T const **data)

Delete a value.

Parameters

data – Data.

template<class T>
void rpcDel(T ***data)

Delete a value.

Parameters

data – Data.

template<class T>
void rpcDel(T const ***data)

Delete a value.

Parameters

data – Data.

template<class ...Ts>
void rpcDel(Tuple<Ts...> *data)

Delete a value.

Parameters

data – Data.

Contributors

Find out who contributed:

git shortlog -s -e