Commit 4d512fcd authored by Jan Koniarik's avatar Jan Koniarik
Browse files

added example for protocol lib and generic include header

parent 0063541c
Pipeline #100437 passed with stage
in 1 minute and 6 seconds
#include "emlabcpp/protocol.h"
#include "emlabcpp/protocol/handler.h"
#include "emlabcpp/protocol/streams.h"
#include <iostream>
namespace em = emlabcpp;
int main( int, char*[] )
{
// ---------------------------------------------------------------------------------------
// protocol library allows serialization and deserialization of C++ native types into binary
// messages. The protocol is defined with types from the library and the library provides
// handler that does the conversion based on the definition. The definition is done using
// types and templates and is separated from the actuall serialization and deserialization.
//
// There are two top level types that shall be used: protocol_tuple and
// protocol_command_group. The user should use these as top level type and define the
// protocol in these. They can be nested.
//
// For the examples we define the protocol by definining structures that inherit from the
// protocol definition, this is not necessary and simple aliases to types can be used, these
// however produce lengthy error messages.
//
// For both types we also use syntax sugar in form of type alias members such as
// 'with_items' that make the definition more readable.
// ---------------------------------------------------------------------------------------
// The protocol tuple is defined by endianess of subsequent types and with items that are
// stored in the tuple. The protocol_tuple works with std::tuple as the type that actually
// holds the value. The example definition below defines protocol for converting
// `std::tuple<uint32_t, in16_t, int16_t>` into binary message `protocol_message<8>` of
// size 8.
//
// The structure contains ::value_type and ::message_type aliases.
struct example_tuple
: em::protocol_tuple< em::PROTOCOL_BIG_ENDIAN >::with_items< uint32_t, int16_t, int16_t >
{
};
// Once protocol is defined, it can be used with protocol_handler to do the serialization
// and deserialization.
using example_tuple_handler = em::protocol_handler< example_tuple >;
std::tuple< uint32_t, int16_t, int16_t > tuple_val = { 666, -2, 2 };
em::protocol_message< 8 > tuple_msg = example_tuple_handler::serialize( tuple_val );
// The library has support for streams, these however are stored in separate included file
// and has to be enable by defining EMLABCPP_USE_STREAMS
std::cout << "Message from example_tuple looks like: " << tuple_msg << "\n";
// Deserialization produces either the value on successfull serialization or
// protocol_error_record with information about what failed and on which byte. Note: the
// protocol_error_record is serializable by the library, so you can simply send it in
// report.
em::either< std::tuple< uint32_t, int16_t, int16_t >, em::protocol_error_record >
tuple_either = example_tuple_handler::extract( tuple_msg );
tuple_either.match(
[]( std::tuple< uint32_t, int16_t, int16_t > ) {
std::cout << "Yaaay, protocol deserialized what it serialized \\o/\n";
},
[]( em::protocol_error_record rec ) {
std::cout << "Hupsie, error happend in deserialization: " << rec << "\n";
} );
// ---------------------------------------------------------------------------------------
// command_group models situation of "message contains one out of many commands", where
// command is just specific tuple of types. This produces std::variant of possible commands
// on deserialization and convert said variant to byte message. The first item of each
// command is constant (em::tag) with id of the command. The library decides which command
// is in the message solely based on this id. These however does not have to be ordered as
// seen in the example.
enum protocol_id : uint16_t
{
EXAMPLE_CMD_A = 1,
EXAMPLE_CMD_B = 42,
EXAMPLE_CMD_C = 66,
};
struct example_group
: em::protocol_command_group< em::PROTOCOL_BIG_ENDIAN >::with_commands<
em::protocol_command< EXAMPLE_CMD_A >::with_args< uint32_t >,
em::protocol_command< EXAMPLE_CMD_B >,
em::protocol_command< EXAMPLE_CMD_C >::with_args<
std::array< uint32_t, 4 >,
std::tuple< uint8_t, uint8_t, em::bounded< int16_t, -666, 666 > > > >
{
};
// This command group produces value defined below:
using example_group_value = std::variant<
std::tuple< em::tag< EXAMPLE_CMD_A >, uint32_t >,
std::tuple< em::tag< EXAMPLE_CMD_B > >,
std::tuple<
em::tag< EXAMPLE_CMD_C >,
std::array< uint32_t, 4 >,
std::tuple< uint8_t, uint8_t, em::bounded< int16_t, -666, 666 > > > >;
// To simplify the process of handling the value, the command_group provides make_val static
// method for creating a value of said group, that can be processed.
example_group_value group_val = example_group::make_val< EXAMPLE_CMD_A >( 42u );
// serialization and deserialization works same way as in case of tuple
using example_group_handler = em::protocol_handler< example_group >;
em::protocol_message< 22 > group_msg = example_group_handler::serialize( group_val );
std::cout << "Message from example group looks like: " << group_msg << "\n";
example_group_handler::extract( group_msg )
.match(
[&]( example_group_value ) {
std::cout << "yayyy, group deserialize :) \n";
},
[&]( em::protocol_error_record rec ) {
std::cout << "something went wrong with the group: " << rec << "\n";
} );
}
#include "emlabcpp/protocol/command_group.h"
#include "emlabcpp/protocol/decl.h"
#include "emlabcpp/protocol/tuple.h"
#pragma once
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment