5namespace robust_frame {
7constexpr size_t kMinUnescapedSize = 2;
9constexpr uint8_t kFrameHeader = 0xAA;
10constexpr uint8_t kFrameFooter = 0x55;
11constexpr uint8_t kEscapeChar = 0xDB;
12constexpr uint8_t kXorEscape = 0x20;
14constexpr bool CheckXorOperator() {
15 return ((kFrameHeader ^ kXorEscape) != kFrameHeader && (kFrameHeader ^ kXorEscape) != kFrameFooter && (kFrameHeader ^ kXorEscape) != kEscapeChar) &&
16 ((kFrameFooter ^ kXorEscape) != kFrameHeader && (kFrameFooter ^ kXorEscape) != kFrameFooter && (kFrameFooter ^ kXorEscape) != kEscapeChar) &&
17 ((kEscapeChar ^ kXorEscape) != kFrameHeader && (kEscapeChar ^ kXorEscape) != kFrameFooter && (kEscapeChar ^ kXorEscape) != kEscapeChar);
20static_assert(CheckXorOperator(),
"XOR operator 0x20 is not safe");
24 : max_payload_size_(max_payload_size + 1), callback_(callback), user_data_(user_data), buffer_(new uint8_t[max_payload_size_]) {
33 case State::kSyncHeader: {
34 if (
byte == kFrameHeader) {
36 state_ = State::kCollectPayload;
40 case State::kCollectPayload: {
41 if (
byte == kFrameFooter) {
42 if (buffer_len_ >= kMinUnescapedSize &&
crc8::Calculate(buffer_,
static_cast<size_t>(buffer_len_ - 1)) == buffer_[buffer_len_ - 1]) {
44 callback_(buffer_, user_data_);
48 }
else if (
byte == kEscapeChar) {
49 state_ = State::kUnescape;
50 }
else if (
byte == kFrameHeader || buffer_len_ == max_payload_size_) {
53 }
else if (buffer_len_ < max_payload_size_) {
54 buffer_[buffer_len_++] = byte;
60 case State::kUnescape: {
61 const uint8_t unescaped =
byte ^ kXorEscape;
62 if (unescaped != kFrameHeader && unescaped != kFrameFooter && unescaped != kEscapeChar) {
65 }
else if (buffer_len_ < max_payload_size_) {
66 buffer_[buffer_len_++] = unescaped;
67 state_ = State::kCollectPayload;
81 state_ = State::kSyncHeader;
void(*)(const uint8_t *data, void *user_data) FrameCallback
Frame parse callback function type.
~Parser()
Destructor. Frees the internally allocated buffer.
Parser(const size_t max_payload_size, FrameCallback callback, void *user_data)
Constructor. Dynamically allocates the internal buffer based on the maximum payload size.
void Feed(const uint8_t byte)
Core state machine for processing a single byte.
uint8_t Calculate(const uint8_t *data, const size_t size)
Calculate the CRC-8 checksum of data (SAE J1850 standard).