protobuf
Protobuf is a language-independent serialization and deserialization format with code generation for most programming languages and a relatively compact wire (binary) encoded format.
Why?
syntax = "proto3";
package dev.npry.machines.example;
Automatically generates something like this:
# produces -> sensor.pb.h, sensor.pb.c
// sensor.pb.h
typedef struct vec3;
typedef struct imu_reading;
typedef struct temp_hum_reading;
typedef struct sensor_reading;
// cont'd for other structs
Which lets you write code like this:
// main.c
int
Or in Python, you get classes, something like this (API inexact):
# betterproto is preferred (get the beta!)
# ...
# ...
# ...
# ...
# ...
=
=
Or in Rust, Go, Java, JavaScript, C#, C++ -- code generation and bindings exist for every mainstream language, and it means you don't need to rewrite your serialization code everywhere if you need to change something.
But JSON exists, I hear you saying -- yes, but JSON is not compact, efficient, or generally suitable for embedded systems. Any self-describing format (msgpack, BSON, CBOR, RON, etc., etc.) is going to have to pay the overhead at least for string field names, where ProtoBuf does not in the general case.
Similar alternatives include FlatBuffers (also a Google project, more efficient than pb but clunkier) and Cap'nProto (to my knowledge libraries expect a full OS environment / not suitable for embedded).
personal conventions
I typically follow the approach of having one message type per (channel,
direction) tuple, discriminated in function by a oneof
field.
syntax = "proto3";
package dev.npry.machines.example;
// Unit/the empty tuple. "void" in C-style parlance.
Uplink
and Downlink
are also conventional for me when there is a clear
vector direction of communication centrality. "Up" is a universal reference
regardless of if I'm client/server/receiver/transmitter momentarily or
generally. This direction doesn't always exist, but when it does, it's
usually absolute.
I generally do not use protobuf service definitions because code generators don't exist for embedded (to my knowledge).