Quick start
In this quick start you install Embedded Proto, define a message, generate the code for it and serialize the message in a small program on your PC. It takes about ten minutes. Afterwards, the same code moves to your microcontroller without changes.
We assume you have Python 3.11 or newer and a C++17 compiler installed. Nothing else is required. The protobuf compiler comes with Embedded Proto.
Install Embedded Proto
Create a folder for the project and install Embedded Proto in a virtual environment:
mkdir quick_start
cd quick_start
python -m venv venv
source venv/bin/activate
pip install EmbeddedProtoOn Windows, activate the environment with venv\Scripts\activate. Other ways to install, with uv or as a git submodule, are described on the installation page.
Define a message
You define the structure of your message in a .proto file. Create the folder proto and in it the file reading.proto, with a message holding a sensor reading:
syntax = "proto3";
message Reading
{
uint32 id = 1;
float temperature = 2;
}Generate the code
Next, generate the C++ code for this message:
embeddedproto -I proto --eams_out=generated proto/reading.protoYou now have the file generated/reading.h with the class Reading in it. The class has functions to set, get and clear each variable, and functions to serialize and deserialize the whole message. Have a look at it, the generated code is meant to be read.
Use the message
Create main.cpp. It fills a message, serializes it into a buffer, and deserializes the buffer into a second message. On your microcontroller, the bytes in the buffer would go over the UART, the CAN bus or the radio.
#include <cstdio>
#include "reading.h"
#include <EmbeddedProto/WriteBufferFixedSize.h>
#include <EmbeddedProto/ReadBufferFixedSize.h>
int main()
{
// Fill a message.
Reading reading;
reading.set_id(7);
reading.set_temperature(21.5F);
// Serialize it into a buffer of sixteen bytes.
::EmbeddedProto::WriteBufferFixedSize<16> write_buffer;
::EmbeddedProto::Error status = reading.serialize(write_buffer);
if(::EmbeddedProto::Error::NO_ERRORS != status)
{
return 1;
}
printf("Serialized %u bytes.\n", write_buffer.get_size());
// Pretend the bytes arrived over your communication line.
::EmbeddedProto::ReadBufferFixedSize<16> read_buffer;
for(uint32_t i = 0; i < write_buffer.get_size(); ++i)
{
read_buffer.push(write_buffer.get_data()[i]);
}
// Deserialize the buffer into a second message.
Reading received;
status = received.deserialize(read_buffer);
if(::EmbeddedProto::Error::NO_ERRORS != status)
{
return 1;
}
printf("Reading %u: %.1f degrees.\n", received.get_id(), received.get_temperature());
return 0;
}Two things to notice. Serialization writes into a WriteBufferFixedSize, an array of bytes with the size given as a template parameter. Deserialization reads from a ReadBufferFixedSize. No memory is allocated dynamically anywhere. Both functions return an Error which you check before using the result.
Build and run
The generated code depends on the C++ library of Embedded Proto. The library is header only, and the embeddedproto command tells you where it is. Build the program with the generated folder and the library folder as include paths:
g++ -std=c++17 -I generated -I "$(embeddedproto --cpp-src-location)" main.cpp -o quick_start
./quick_startThe output is:
Serialized 7 bytes.
Reading 7: 21.5 degrees.Seven bytes for two variables. The same data in JSON takes four times as much.
On your microcontroller the same two include paths go into your toolchain. Please note that when your project is linked with a C compiler, as many embedded toolchains do, you have to pass -lstdc++ to the linker. This prevents errors like undefined reference to.
Next steps
On your microcontroller nothing changes. Add the generated folder and the library folder to your project, as described on the installation page, and replace the printf with your communication line. The examples show this on real hardware, for instance a simple UART example.
To learn what the generated code offers for strings, repeated fields, nested messages and more, continue with using a message.