Unpadded¶
Unpadded is a header-only RPC library appropriate for embedded software and compatible with C++11 (with syntactic sugar for C++17).
Unpadded does not require code generation, so it is easy to integrate in any project. It provides compile-time safety mechanisms to avoid silly mistakes while striving for low memory usage.
What Unpadded is good for and what it cannot do¶
This library does not provide ready-to-use RPC support by itself. It does not implement any protocol like I2C, SPI, TCP etc… Therefore, one downside of Unpadded is that you must implement a “driver” for the protocol or peripheral you want to use Unpadded with.
Unpadded is best used with protocol that can handle byte streams easily, such as:
UART configured for sending and receiving 8 bits of data per frame
UNIX pipes
TCP protocol
…
Features¶
Header-only: You can but do not need to use CMake to integrate Unpadded in your own project. Pick the include/ directory, put it anywhere you like inside your project and you are good.
Easy to integrate: The only dependency of Unpadded is the C++ standard library and a standard-compliant C++11 compiler. Some optional dependencies can be enabled to bind Unpadded to Python, but are not required.
Easy to interface with any protocol: Unpadded is not meant to provide protocol implementation right out of the box, because it would be too difficult to support every chip and framework available. Instead, Unpadded provide you with a way to interface it with almost any protocol.
Use C++17 features but is C++11 compatible: This library use some C++17 features in order to improve compilation time and make it easier to use. However, if you are using an old toolchain, you can also use Unpadded with a C++11 compiler
Macro free: If you are compiling with C++17, then Unpadded will not make you use any macro.
Works well with bare-metal application: Unpadded has been designed to work with hardware interrupts.
Optional usage of dynamic allocation: Can’t use dynamic allocation? Then Unpadded will only use the stack. For example, the front page example does not make any dynamic allocation.
Additional tools for implementing protocols for non-programmable devices: Sensors and actuators must sometime be controlled through a communication bus. Unpadded provides you with tools that can be used to implement any communication protocol.
Minimizes the quantity of data sent: Since the signatures of the remotely invocable functions are known at compile-time by both side, Unpadded produces very little information when generating packets.
Allows to serialize any user-provided type: Unpadded natively supports primitive types and arrays of primitive types. Users can define additional serialization rules for any type they want, as long as the number of bytes needed to describe the type is known at compile-time.
`Documentation available <https://starqtius.github.io/Unpadded/>`_: Albeit a bit sloppy for the moment, every part of the public API is documented. The documentation also includes a step-by-step tutorial.
Quick example with Arduino¶
Do note that the Arduino framework is not necessarlily shipped with an implementatio of the standard library, so you might have to provide one yourself if you want to run this example.
In the following example, we have an Arduino board connected through I²C to another Arduino board. The latter is managing a traffic light with its GPIOs.
The project is divided in three files:
shared.hpp
which declares the function that can be called on the callee device;caller.cpp
which implements the behavior of the caller device;callee.cpp
which implements the functions that can be called remotely and the dispatching of the caller requests to the correct function.
caller.cpp¶
#include <Arduino.h>
#include <Wire.h>
#include "shared.hpp"
void setup() {
Wire.begin();
}
void loop() {
auto gkey = keyring.get<Set_Green_Light>();
auto ykey = keyring.get<Set_Yellow_Light>();
auto rkey = keyring.get<Set_Red_Light>();
auto write_byte = [](upd::byte_t x) {
Wire.write(x);
};
Wire.beginTransmission(1);
gkey(true).write_to(write_byte);
delay(500);
Wire.endTransmission();
Wire.beginTransmission(1);
ykey(true).write_to(write_byte);
delay(500);
Wire.endTransmission();
Wire.beginTransmission(1);
rkey(true).write_to(write_byte);
delay(500);
Wire.endTransmission();
Wire.beginTransmission(1);
gkey(false).write_to(write_byte);
delay(500);
Wire.endTransmission();
Wire.beginTransmission(1);
ykey(false).write_to(write_byte);
delay(500);
Wire.endTransmission();
Wire.beginTransmission(1);
rkey(false).write_to(write_byte);
delay(500);
Wire.endTransmission();
}
callee.cpp¶
#include <Arduino.h>
#include <Wire.h>
#include <upd/buffered_dispatcher.hpp>
#include "shared.hpp"
static upd::single_buffered_dispatcher dispatcher{keyring, upd::policy::weak_reference};
void Set_Green_Light(std::uint8_t state) {
digitalWrite(2, state ? HIGH : LOW);
}
void Set_Yellow_Light(std::uint8_t state) {
digitalWrite(3, state ? HIGH : LOW);
}
void Set_Red_Light(std::uint8_t state) {
digitalWrite(4, state ? HIGH : LOW);
}
void setup() {
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
Wire.onReceive([](int n) {
upd::packet_status status;
do {
status = dispatcher.put(Wire.read());
} while(--n && status != upd::packet_status::DROPPED_PACKET);
});
Wire.begin(1);
}
void loop() {}
- Sharing RPC convention
- Implementing caller side
- Implementing callee side
- Basics : fulfiling incoming request with dispatchers
- Hot swapping callbacks
- Storage policy
- API References
dispatcher
dispatcher
dispatcher::signatures_t
dispatcher::index_t
dispatcher::dispatcher()
dispatcher::dispatcher()
dispatcher::operator()()
dispatcher::get_action()
dispatcher::get_index()
dispatcher::replace()
dispatcher::replace()
dispatcher::replace()
dispatcher::operator[]()
dispatcher::operator[]()
dispatcher::size
dispatcher::endianess
dispatcher::signed_mode
dispatcher::make_dispatcher
buffered_dispatcher
buffered_dispatcher
buffered_dispatcher::index_t
buffered_dispatcher::buffered_dispatcher()
buffered_dispatcher::buffered_dispatcher()
buffered_dispatcher::is_loaded()
buffered_dispatcher::read_from()
buffered_dispatcher::put()
buffered_dispatcher::write_to()
buffered_dispatcher::get()
buffered_dispatcher::replace()
buffered_dispatcher::operator()()
buffered_dispatcher::replace()
buffered_dispatcher::replace()
buffered_dispatcher::reply()
buffered_dispatcher::operator[]()
buffered_dispatcher::operator[]()
single_buffered_dispatcher
single_buffered_dispatcher
single_buffered_dispatcher::single_buffered_dispatcher()
single_buffered_dispatcher::single_buffered_dispatcher()
single_buffered_dispatcher::is_loaded()
single_buffered_dispatcher::read_from()
single_buffered_dispatcher::put()
single_buffered_dispatcher::write_to()
single_buffered_dispatcher::get()
single_buffered_dispatcher::operator()()
single_buffered_dispatcher::reply()
single_buffered_dispatcher::buffer_size
single_buffered_dispatcher::make_single_buffered_dispatcher()
double_buffered_dispatcher
double_buffered_dispatcher
double_buffered_dispatcher::double_buffered_dispatcher()
double_buffered_dispatcher::double_buffered_dispatcher()
double_buffered_dispatcher::is_loaded()
double_buffered_dispatcher::read_from()
double_buffered_dispatcher::put()
double_buffered_dispatcher::write_to()
double_buffered_dispatcher::get()
double_buffered_dispatcher::operator()()
double_buffered_dispatcher::reply()
double_buffered_dispatcher::input_buffer_size
double_buffered_dispatcher::output_buffer_size
double_buffered_dispatcher::make_double_buffered_dispatcher()
packet_status
- Policies
- Serialization tools
- Formatting packets with the
upd::tuple
class - Make a view of a part of a tuple or out of an existing buffer using
upd::tuple_view
- Customization points: defining serialization processes for foreign types
- API References
tuple
tuple
tuple::arg_t
tuple::tuple()
tuple::tuple()
tuple::tuple()
tuple::begin()
tuple::begin()
tuple::end()
tuple::end()
tuple::operator[]()
tuple::operator[]()
tuple::src()
tuple::src()
tuple::view()
tuple::view()
tuple::get()
tuple::set()
tuple::invoke()
tuple::size
tuple::storage_endianess
tuple::storage_signed_mode
tuple::make_tuple
tuple::make_tuple()
view_tuple
tuple_view
tuple_view::types_t
tuple_view::sizes_t
tuple_view::arg_t
tuple_view::tuple_view()
tuple_view::begin()
tuple_view::end()
tuple_view::src()
tuple_view::get()
tuple_view::set()
tuple_view::invoke()
tuple_view::size
tuple_view::storage_endianess
tuple_view::storage_signed_mode
tuple_view::make_view()
tuple_view::make_view()
get
set
- Serialization parameters
- Other
- Formatting packets with the
- Extending Unpadded to Python