skullc-peripherals/Messaging/Inc/messaging_parser.hpp
Erki b626999684
All checks were successful
continuous-integration/drone/push Build is passing
Messaging: simple and fun packet parser implementation.
2021-03-28 16:43:05 +03:00

132 lines
2.2 KiB
C++

//
// Created by erki on 27.03.21.
//
#ifndef SKULLC_MESSAGING_PARSER_HPP
#define SKULLC_MESSAGING_PARSER_HPP
#include <cstdint>
#include <cstring>
#include <array>
namespace Messaging
{
template<typename P, typename std::size_t N>
class Parser
{
public:
using Packet = P;
const std::size_t buffer_length = N;
Parser()
{
reset();
}
Parser(const Parser&) = delete;
Parser(Parser&&) = delete;
void reset()
{
_state = _State::Preamble;
_expected = sizeof(P::preamble);
_current_pos = 0;
_current_offset = 0;
}
void pushByte(const std::uint8_t byte)
{
if (packetReady())
return;
const std::uint32_t buffer_loc = _current_offset + _current_pos;
switch (_state)
{
case _State::Preamble:
if (byte != P::preamble[_current_pos])
{
reset();
return;
}
[[fallthrough]];
case _State::Length:
case _State::Body:
_buffer[buffer_loc] = byte;
_current_pos++;
break;
default:
break;
}
if (_current_pos == _expected)
{
_setupNextState();
}
}
bool packetReady() const
{
return _state == _State::Done;
}
bool getPacket(Packet& packet) const
{
return packet.deserialize(_buffer.data(), _current_offset);
}
private:
enum class _State : std::uint32_t
{
Preamble,
Length,
Body,
Done
};
std::array<std::uint8_t, N> _buffer;
_State _state = _State::Preamble;
std::uint32_t _current_pos = 0;
std::uint32_t _current_offset = 0;
std::uint32_t _expected = 0;
template<typename T>
T _deserializeLength(const std::uint32_t offset)
{
std::uint8_t* begin = _buffer.data() + offset;
T len(0);
std::memcpy(&len, begin, sizeof(T));
return len;
}
void _setupNextState()
{
switch (_state)
{
case _State::Preamble:
_state = _State::Length;
_expected = sizeof(typename P::length_type);
break;
case _State::Length:
_state = _State::Body;
_expected = _deserializeLength<typename P::length_type>(_current_offset);
break;
case _State::Body:
_state = _State::Done;
break;
default:
break;
}
_current_offset += _current_pos;
_current_pos = 0;
}
};
}
#endif //SKULLC_MESSAGING_PARSER_HPP