diff --git a/src/struct_frame/boilerplate/c/basic_frame.h b/src/struct_frame/boilerplate/c/basic_frame.h new file mode 100644 index 00000000..25ad9b47 --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame.h @@ -0,0 +1,205 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrame Frame Format + *===========================================================================*/ + +/* BasicFrame constants */ +#define BASIC_FRAME_START_BYTE1 0x90 +#define BASIC_FRAME_START_BYTE2 0x91 +#define BASIC_FRAME_HEADER_SIZE 3 /* start_byte1 + start_byte2 + msg_id */ +#define BASIC_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define BASIC_FRAME_OVERHEAD (BASIC_FRAME_HEADER_SIZE + BASIC_FRAME_FOOTER_SIZE) + +/* BasicFrame parser states */ +typedef enum basic_frame_parser_state { + BASIC_FRAME_LOOKING_FOR_START1 = 0, + BASIC_FRAME_LOOKING_FOR_START2 = 1, + BASIC_FRAME_GETTING_MSG_ID = 2, + BASIC_FRAME_GETTING_PAYLOAD = 3 +} basic_frame_parser_state_t; + +/* BasicFrame parser state structure */ +typedef struct basic_frame_parser { + basic_frame_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_parser_t; + +/* BasicFrame encode buffer structure */ +typedef struct basic_frame_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_encode_buffer_t; + +/** + * Initialize a BasicFrame parser + */ +static inline void basic_frame_parser_init(basic_frame_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrame parser state + */ +static inline void basic_frame_parser_reset(basic_frame_parser_t* parser) { + parser->state = BASIC_FRAME_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with BasicFrame format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_parse_byte(basic_frame_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = BASIC_FRAME_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_LOOKING_FOR_START1; + } + } else { + parser->state = BASIC_FRAME_LOOKING_FOR_START1; + } + } + break; + + case BASIC_FRAME_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - BASIC_FRAME_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 2, msg_length + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + BASIC_FRAME_HEADER_SIZE; + } + parser->state = BASIC_FRAME_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrame format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_START_BYTE1; + buffer[1] = BASIC_FRAME_START_BYTE2; + buffer[2] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1); + buffer[BASIC_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrame packet in a buffer + */ +static inline frame_msg_info_t basic_frame_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/basic_frame_no_crc.h b/src/struct_frame/boilerplate/c/basic_frame_no_crc.h new file mode 100644 index 00000000..c445a0f3 --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame_no_crc.h @@ -0,0 +1,189 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrameNoCrc Frame Format + *===========================================================================*/ + +/* BasicFrameNoCrc constants */ +#define BASIC_FRAME_NO_CRC_START_BYTE1 0x90 +#define BASIC_FRAME_NO_CRC_START_BYTE2 0x95 +#define BASIC_FRAME_NO_CRC_HEADER_SIZE 3 /* start_byte1 + start_byte2 + msg_id */ +#define BASIC_FRAME_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define BASIC_FRAME_NO_CRC_OVERHEAD (BASIC_FRAME_NO_CRC_HEADER_SIZE + BASIC_FRAME_NO_CRC_FOOTER_SIZE) + +/* BasicFrameNoCrc parser states */ +typedef enum basic_frame_no_crc_parser_state { + BASIC_FRAME_NO_CRC_LOOKING_FOR_START1 = 0, + BASIC_FRAME_NO_CRC_LOOKING_FOR_START2 = 1, + BASIC_FRAME_NO_CRC_GETTING_MSG_ID = 2, + BASIC_FRAME_NO_CRC_GETTING_PAYLOAD = 3 +} basic_frame_no_crc_parser_state_t; + +/* BasicFrameNoCrc parser state structure */ +typedef struct basic_frame_no_crc_parser { + basic_frame_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_no_crc_parser_t; + +/* BasicFrameNoCrc encode buffer structure */ +typedef struct basic_frame_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_no_crc_encode_buffer_t; + +/** + * Initialize a BasicFrameNoCrc parser + */ +static inline void basic_frame_no_crc_parser_init(basic_frame_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrameNoCrc parser state + */ +static inline void basic_frame_no_crc_parser_reset(basic_frame_no_crc_parser_t* parser) { + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with BasicFrameNoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_no_crc_parse_byte(basic_frame_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_NO_CRC_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_NO_CRC_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_NO_CRC_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_NO_CRC_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; + } + } else { + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; + } + } + break; + + case BASIC_FRAME_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - BASIC_FRAME_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE; + parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrameNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_NO_CRC_START_BYTE1; + buffer[1] = BASIC_FRAME_NO_CRC_START_BYTE2; + buffer[2] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete BasicFrameNoCrc packet in a buffer + */ +static inline frame_msg_info_t basic_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_NO_CRC_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_NO_CRC_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_NO_CRC_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/basic_frame_with_len.h b/src/struct_frame/boilerplate/c/basic_frame_with_len.h new file mode 100644 index 00000000..8b93c9c7 --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame_with_len.h @@ -0,0 +1,209 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrameWithLen Frame Format + *===========================================================================*/ + +/* BasicFrameWithLen constants */ +#define BASIC_FRAME_WITH_LEN_START_BYTE1 0x90 +#define BASIC_FRAME_WITH_LEN_START_BYTE2 0x92 +#define BASIC_FRAME_WITH_LEN_HEADER_SIZE 4 /* start_byte1 + start_byte2 + msg_id + length(1) */ +#define BASIC_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define BASIC_FRAME_WITH_LEN_OVERHEAD (BASIC_FRAME_WITH_LEN_HEADER_SIZE + BASIC_FRAME_WITH_LEN_FOOTER_SIZE) + +/* BasicFrameWithLen parser states */ +typedef enum basic_frame_with_len_parser_state { + BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1 = 0, + BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2 = 1, + BASIC_FRAME_WITH_LEN_GETTING_MSG_ID = 2, + BASIC_FRAME_WITH_LEN_GETTING_LENGTH = 3, + BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD = 4 +} basic_frame_with_len_parser_state_t; + +/* BasicFrameWithLen parser state structure */ +typedef struct basic_frame_with_len_parser { + basic_frame_with_len_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_with_len_parser_t; + +/* BasicFrameWithLen encode buffer structure */ +typedef struct basic_frame_with_len_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_with_len_encode_buffer_t; + +/** + * Initialize a BasicFrameWithLen parser + */ +static inline void basic_frame_with_len_parser_init(basic_frame_with_len_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrameWithLen parser state + */ +static inline void basic_frame_with_len_parser_reset(basic_frame_with_len_parser_t* parser) { + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with BasicFrameWithLen format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_with_len_parse_byte(basic_frame_with_len_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_WITH_LEN_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_WITH_LEN_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_LEN_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = BASIC_FRAME_WITH_LEN_GETTING_LENGTH; + break; + + case BASIC_FRAME_WITH_LEN_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = BASIC_FRAME_WITH_LEN_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - BASIC_FRAME_WITH_LEN_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 2, msg_length + 1 + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE; + } + parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrameWithLen format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1 + 1); + buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLen packet in a buffer + */ +static inline frame_msg_info_t basic_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_WITH_LEN_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_WITH_LEN_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_WITH_LEN_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_WITH_LEN_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/basic_frame_with_len16.h b/src/struct_frame/boilerplate/c/basic_frame_with_len16.h new file mode 100644 index 00000000..24292554 --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame_with_len16.h @@ -0,0 +1,216 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrameWithLen16 Frame Format + *===========================================================================*/ + +/* BasicFrameWithLen16 constants */ +#define BASIC_FRAME_WITH_LEN16_START_BYTE1 0x90 +#define BASIC_FRAME_WITH_LEN16_START_BYTE2 0x93 +#define BASIC_FRAME_WITH_LEN16_HEADER_SIZE 5 /* start_byte1 + start_byte2 + msg_id + length(2) */ +#define BASIC_FRAME_WITH_LEN16_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define BASIC_FRAME_WITH_LEN16_OVERHEAD (BASIC_FRAME_WITH_LEN16_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_FOOTER_SIZE) + +/* BasicFrameWithLen16 parser states */ +typedef enum basic_frame_with_len16_parser_state { + BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1 = 0, + BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2 = 1, + BASIC_FRAME_WITH_LEN16_GETTING_MSG_ID = 2, + BASIC_FRAME_WITH_LEN16_GETTING_LENGTH = 3, + BASIC_FRAME_WITH_LEN16_GETTING_PAYLOAD = 4 +} basic_frame_with_len16_parser_state_t; + +/* BasicFrameWithLen16 parser state structure */ +typedef struct basic_frame_with_len16_parser { + basic_frame_with_len16_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + uint8_t length_lo; /* Low byte for 16-bit length */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_with_len16_parser_t; + +/* BasicFrameWithLen16 encode buffer structure */ +typedef struct basic_frame_with_len16_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_with_len16_encode_buffer_t; + +/** + * Initialize a BasicFrameWithLen16 parser + */ +static inline void basic_frame_with_len16_parser_init(basic_frame_with_len16_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->length_lo = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrameWithLen16 parser state + */ +static inline void basic_frame_with_len16_parser_reset(basic_frame_with_len16_parser_t* parser) { + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with BasicFrameWithLen16 format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_with_len16_parse_byte(basic_frame_with_len16_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_WITH_LEN16_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_LEN16_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = BASIC_FRAME_WITH_LEN16_GETTING_LENGTH; + break; + + case BASIC_FRAME_WITH_LEN16_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + if (parser->buffer_index == 4) { + parser->length_lo = byte; + } else { + parser->msg_length = parser->length_lo | ((size_t)byte << 8); + parser->packet_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_WITH_LEN16_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; + } + } + break; + + case BASIC_FRAME_WITH_LEN16_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - BASIC_FRAME_WITH_LEN16_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 2, msg_length + 1 + 2); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE; + } + parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrameWithLen16 format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_WITH_LEN16_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN16_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = (uint8_t)(msg_size & 0xFF); + buffer[4] = (uint8_t)((msg_size >> 8) & 0xFF); + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1 + 2); + buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLen16 packet in a buffer + */ +static inline frame_msg_info_t basic_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_WITH_LEN16_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_WITH_LEN16_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_WITH_LEN16_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_WITH_LEN16_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1 + 2); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/basic_frame_with_len16_no_crc.h b/src/struct_frame/boilerplate/c/basic_frame_with_len16_no_crc.h new file mode 100644 index 00000000..7827dae9 --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame_with_len16_no_crc.h @@ -0,0 +1,200 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrameWithLen16NoCrc Frame Format + *===========================================================================*/ + +/* BasicFrameWithLen16NoCrc constants */ +#define BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1 0x90 +#define BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2 0x97 +#define BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE 5 /* start_byte1 + start_byte2 + msg_id + length(2) */ +#define BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD (BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE) + +/* BasicFrameWithLen16NoCrc parser states */ +typedef enum basic_frame_with_len16_no_crc_parser_state { + BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1 = 0, + BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2 = 1, + BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID = 2, + BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH = 3, + BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD = 4 +} basic_frame_with_len16_no_crc_parser_state_t; + +/* BasicFrameWithLen16NoCrc parser state structure */ +typedef struct basic_frame_with_len16_no_crc_parser { + basic_frame_with_len16_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + uint8_t length_lo; /* Low byte for 16-bit length */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_with_len16_no_crc_parser_t; + +/* BasicFrameWithLen16NoCrc encode buffer structure */ +typedef struct basic_frame_with_len16_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_with_len16_no_crc_encode_buffer_t; + +/** + * Initialize a BasicFrameWithLen16NoCrc parser + */ +static inline void basic_frame_with_len16_no_crc_parser_init(basic_frame_with_len16_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->length_lo = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrameWithLen16NoCrc parser state + */ +static inline void basic_frame_with_len16_no_crc_parser_reset(basic_frame_with_len16_no_crc_parser_t* parser) { + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with BasicFrameWithLen16NoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_with_len16_no_crc_parse_byte(basic_frame_with_len16_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH; + break; + + case BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + if (parser->buffer_index == 4) { + parser->length_lo = byte; + } else { + parser->msg_length = parser->length_lo | ((size_t)byte << 8); + parser->packet_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; + } + } + break; + + case BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; + parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrameWithLen16NoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = (uint8_t)(msg_size & 0xFF); + buffer[4] = (uint8_t)((msg_size >> 8) & 0xFF); + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLen16NoCrc packet in a buffer + */ +static inline frame_msg_info_t basic_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/basic_frame_with_len_no_crc.h b/src/struct_frame/boilerplate/c/basic_frame_with_len_no_crc.h new file mode 100644 index 00000000..7c1dbb5d --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame_with_len_no_crc.h @@ -0,0 +1,193 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrameWithLenNoCrc Frame Format + *===========================================================================*/ + +/* BasicFrameWithLenNoCrc constants */ +#define BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1 0x90 +#define BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2 0x96 +#define BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE 4 /* start_byte1 + start_byte2 + msg_id + length(1) */ +#define BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD (BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE) + +/* BasicFrameWithLenNoCrc parser states */ +typedef enum basic_frame_with_len_no_crc_parser_state { + BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1 = 0, + BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2 = 1, + BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID = 2, + BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH = 3, + BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD = 4 +} basic_frame_with_len_no_crc_parser_state_t; + +/* BasicFrameWithLenNoCrc parser state structure */ +typedef struct basic_frame_with_len_no_crc_parser { + basic_frame_with_len_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_with_len_no_crc_parser_t; + +/* BasicFrameWithLenNoCrc encode buffer structure */ +typedef struct basic_frame_with_len_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_with_len_no_crc_encode_buffer_t; + +/** + * Initialize a BasicFrameWithLenNoCrc parser + */ +static inline void basic_frame_with_len_no_crc_parser_init(basic_frame_with_len_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrameWithLenNoCrc parser state + */ +static inline void basic_frame_with_len_no_crc_parser_reset(basic_frame_with_len_no_crc_parser_t* parser) { + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with BasicFrameWithLenNoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_with_len_no_crc_parse_byte(basic_frame_with_len_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH; + break; + + case BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; + parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrameWithLenNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLenNoCrc packet in a buffer + */ +static inline frame_msg_info_t basic_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/basic_frame_with_sys_comp.h b/src/struct_frame/boilerplate/c/basic_frame_with_sys_comp.h new file mode 100644 index 00000000..3a14d937 --- /dev/null +++ b/src/struct_frame/boilerplate/c/basic_frame_with_sys_comp.h @@ -0,0 +1,205 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * BasicFrameWithSysComp Frame Format + *===========================================================================*/ + +/* BasicFrameWithSysComp constants */ +#define BASIC_FRAME_WITH_SYS_COMP_START_BYTE1 0x90 +#define BASIC_FRAME_WITH_SYS_COMP_START_BYTE2 0x94 +#define BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE 3 /* start_byte1 + start_byte2 + msg_id */ +#define BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define BASIC_FRAME_WITH_SYS_COMP_OVERHEAD (BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE) + +/* BasicFrameWithSysComp parser states */ +typedef enum basic_frame_with_sys_comp_parser_state { + BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1 = 0, + BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2 = 1, + BASIC_FRAME_WITH_SYS_COMP_GETTING_MSG_ID = 2, + BASIC_FRAME_WITH_SYS_COMP_GETTING_PAYLOAD = 3 +} basic_frame_with_sys_comp_parser_state_t; + +/* BasicFrameWithSysComp parser state structure */ +typedef struct basic_frame_with_sys_comp_parser { + basic_frame_with_sys_comp_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} basic_frame_with_sys_comp_parser_t; + +/* BasicFrameWithSysComp encode buffer structure */ +typedef struct basic_frame_with_sys_comp_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} basic_frame_with_sys_comp_encode_buffer_t; + +/** + * Initialize a BasicFrameWithSysComp parser + */ +static inline void basic_frame_with_sys_comp_parser_init(basic_frame_with_sys_comp_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset BasicFrameWithSysComp parser state + */ +static inline void basic_frame_with_sys_comp_parser_reset(basic_frame_with_sys_comp_parser_t* parser) { + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with BasicFrameWithSysComp format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t basic_frame_with_sys_comp_parse_byte(basic_frame_with_sys_comp_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1: + if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2; + } + break; + + case BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2: + if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = BASIC_FRAME_WITH_SYS_COMP_GETTING_MSG_ID; + } else if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2; + } else { + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; + } + break; + + case BASIC_FRAME_WITH_SYS_COMP_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = BASIC_FRAME_WITH_SYS_COMP_GETTING_PAYLOAD; + } else { + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; + } + } else { + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; + } + } + break; + + case BASIC_FRAME_WITH_SYS_COMP_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 2, msg_length + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE; + } + parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with BasicFrameWithSysComp format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t basic_frame_with_sys_comp_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE2; + buffer[2] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1); + buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrameWithSysComp packet in a buffer + */ +static inline frame_msg_info_t basic_frame_with_sys_comp_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < BASIC_FRAME_WITH_SYS_COMP_OVERHEAD) { + return result; + } + + if (buffer[0] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { + return result; + } + if (buffer[1] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) { + return result; + } + + size_t msg_length = length - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/frame_base.h b/src/struct_frame/boilerplate/c/frame_base.h new file mode 100644 index 00000000..ab54be3b --- /dev/null +++ b/src/struct_frame/boilerplate/c/frame_base.h @@ -0,0 +1,64 @@ +/* Automatically generated frame parser base utilities */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include +#include +#include +#include + +/* Frame format type enumeration */ +typedef enum FrameFormatType { + FRAME_FORMAT_MINIMAL_FRAME = 0, + FRAME_FORMAT_BASIC_FRAME = 1, + FRAME_FORMAT_BASIC_FRAME_NO_CRC = 2, + FRAME_FORMAT_TINY_FRAME = 3, + FRAME_FORMAT_TINY_FRAME_NO_CRC = 4, + FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN = 5, + FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN_NO_CRC = 6, + FRAME_FORMAT_BASIC_FRAME_WITH_LEN = 7, + FRAME_FORMAT_BASIC_FRAME_WITH_LEN_NO_CRC = 8, + FRAME_FORMAT_TINY_FRAME_WITH_LEN = 9, + FRAME_FORMAT_TINY_FRAME_WITH_LEN_NO_CRC = 10, + FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN16 = 11, + FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12, + FRAME_FORMAT_BASIC_FRAME_WITH_LEN16 = 13, + FRAME_FORMAT_BASIC_FRAME_WITH_LEN16_NO_CRC = 14, + FRAME_FORMAT_TINY_FRAME_WITH_LEN16 = 15, + FRAME_FORMAT_TINY_FRAME_WITH_LEN16_NO_CRC = 16, + FRAME_FORMAT_BASIC_FRAME_WITH_SYS_COMP = 17, + FRAME_FORMAT_UBX_FRAME = 18, + FRAME_FORMAT_MAVLINK_V1_FRAME = 19, + FRAME_FORMAT_MAVLINK_V2_FRAME = 20, + FRAME_FORMAT_FRAME_FORMAT_CONFIG = 21, +} FrameFormatType; + +/*=========================================================================== + * Checksum Calculation + *===========================================================================*/ + +typedef struct frame_checksum { + uint8_t byte1; + uint8_t byte2; +} frame_checksum_t; + +/** + * Calculate Fletcher-16 checksum over the given data + */ +static inline frame_checksum_t frame_fletcher_checksum(const uint8_t* data, size_t length) { + frame_checksum_t ck = {0, 0}; + for (size_t i = 0; i < length; i++) { + ck.byte1 = (uint8_t)(ck.byte1 + data[i]); + ck.byte2 = (uint8_t)(ck.byte2 + ck.byte1); + } + return ck; +} + +/* Parse result */ +typedef struct frame_msg_info { + bool valid; + uint8_t msg_id; + size_t msg_len; + uint8_t* msg_data; +} frame_msg_info_t; diff --git a/src/struct_frame/boilerplate/c/frame_format_config.h b/src/struct_frame/boilerplate/c/frame_format_config.h new file mode 100644 index 00000000..0ed59a2d --- /dev/null +++ b/src/struct_frame/boilerplate/c/frame_format_config.h @@ -0,0 +1,205 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * FrameFormatConfig Frame Format + *===========================================================================*/ + +/* FrameFormatConfig constants */ +#define FRAME_FORMAT_CONFIG_START_BYTE1 0x90 +#define FRAME_FORMAT_CONFIG_START_BYTE2 0x91 +#define FRAME_FORMAT_CONFIG_HEADER_SIZE 2 /* start_byte1 + start_byte2 + msg_id */ +#define FRAME_FORMAT_CONFIG_FOOTER_SIZE 1 /* crc(1 bytes) */ +#define FRAME_FORMAT_CONFIG_OVERHEAD (FRAME_FORMAT_CONFIG_HEADER_SIZE + FRAME_FORMAT_CONFIG_FOOTER_SIZE) + +/* FrameFormatConfig parser states */ +typedef enum frame_format_config_parser_state { + FRAME_FORMAT_CONFIG_LOOKING_FOR_START1 = 0, + FRAME_FORMAT_CONFIG_LOOKING_FOR_START2 = 1, + FRAME_FORMAT_CONFIG_GETTING_MSG_ID = 2, + FRAME_FORMAT_CONFIG_GETTING_PAYLOAD = 3 +} frame_format_config_parser_state_t; + +/* FrameFormatConfig parser state structure */ +typedef struct frame_format_config_parser { + frame_format_config_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} frame_format_config_parser_t; + +/* FrameFormatConfig encode buffer structure */ +typedef struct frame_format_config_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} frame_format_config_encode_buffer_t; + +/** + * Initialize a FrameFormatConfig parser + */ +static inline void frame_format_config_parser_init(frame_format_config_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset FrameFormatConfig parser state + */ +static inline void frame_format_config_parser_reset(frame_format_config_parser_t* parser) { + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with FrameFormatConfig format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t frame_format_config_parse_byte(frame_format_config_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case FRAME_FORMAT_CONFIG_LOOKING_FOR_START1: + if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START2; + } + break; + + case FRAME_FORMAT_CONFIG_LOOKING_FOR_START2: + if (byte == FRAME_FORMAT_CONFIG_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = FRAME_FORMAT_CONFIG_GETTING_MSG_ID; + } else if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START2; + } else { + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; + } + break; + + case FRAME_FORMAT_CONFIG_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = FRAME_FORMAT_CONFIG_GETTING_PAYLOAD; + } else { + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; + } + } else { + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; + } + } + break; + + case FRAME_FORMAT_CONFIG_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - FRAME_FORMAT_CONFIG_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 2, msg_length + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE; + } + parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with FrameFormatConfig format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t frame_format_config_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = FRAME_FORMAT_CONFIG_START_BYTE1; + buffer[1] = FRAME_FORMAT_CONFIG_START_BYTE2; + buffer[2] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1); + buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size] = ck.byte1; + buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete FrameFormatConfig packet in a buffer + */ +static inline frame_msg_info_t frame_format_config_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < FRAME_FORMAT_CONFIG_OVERHEAD) { + return result; + } + + if (buffer[0] != FRAME_FORMAT_CONFIG_START_BYTE1) { + return result; + } + if (buffer[1] != FRAME_FORMAT_CONFIG_START_BYTE2) { + return result; + } + + size_t msg_length = length - FRAME_FORMAT_CONFIG_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/frame_parsers.h b/src/struct_frame/boilerplate/c/frame_parsers.h new file mode 100644 index 00000000..5f5db21d --- /dev/null +++ b/src/struct_frame/boilerplate/c/frame_parsers.h @@ -0,0 +1,31 @@ +/* Automatically generated frame parser main header */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +/* Base utilities */ +#include "frame_base.h" + +/* Individual frame format parsers */ +#include "minimal_frame.h" +#include "basic_frame.h" +#include "basic_frame_no_crc.h" +#include "tiny_frame.h" +#include "tiny_frame_no_crc.h" +#include "minimal_frame_with_len.h" +#include "minimal_frame_with_len_no_crc.h" +#include "basic_frame_with_len.h" +#include "basic_frame_with_len_no_crc.h" +#include "tiny_frame_with_len.h" +#include "tiny_frame_with_len_no_crc.h" +#include "minimal_frame_with_len16.h" +#include "minimal_frame_with_len16_no_crc.h" +#include "basic_frame_with_len16.h" +#include "basic_frame_with_len16_no_crc.h" +#include "tiny_frame_with_len16.h" +#include "tiny_frame_with_len16_no_crc.h" +#include "basic_frame_with_sys_comp.h" +#include "ubx_frame.h" +#include "mavlink_v1_frame.h" +#include "mavlink_v2_frame.h" +#include "frame_format_config.h" diff --git a/src/struct_frame/boilerplate/c/frame_parsers_gen.h b/src/struct_frame/boilerplate/c/frame_parsers_gen.h deleted file mode 100644 index 7eb7127a..00000000 --- a/src/struct_frame/boilerplate/c/frame_parsers_gen.h +++ /dev/null @@ -1,4087 +0,0 @@ -/* Automatically generated frame parser header */ -/* Generated by 0.0.1 at Wed Dec 3 09:37:56 2025. */ - -#pragma once - -#include -#include -#include -#include - -/* Frame format type enumeration */ -typedef enum FrameFormatType { - FRAME_FORMAT_MINIMAL_FRAME = 0, - FRAME_FORMAT_BASIC_FRAME = 1, - FRAME_FORMAT_BASIC_FRAME_NO_CRC = 2, - FRAME_FORMAT_TINY_FRAME = 3, - FRAME_FORMAT_TINY_FRAME_NO_CRC = 4, - FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN = 5, - FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN_NO_CRC = 6, - FRAME_FORMAT_BASIC_FRAME_WITH_LEN = 7, - FRAME_FORMAT_BASIC_FRAME_WITH_LEN_NO_CRC = 8, - FRAME_FORMAT_TINY_FRAME_WITH_LEN = 9, - FRAME_FORMAT_TINY_FRAME_WITH_LEN_NO_CRC = 10, - FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN16 = 11, - FRAME_FORMAT_MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12, - FRAME_FORMAT_BASIC_FRAME_WITH_LEN16 = 13, - FRAME_FORMAT_BASIC_FRAME_WITH_LEN16_NO_CRC = 14, - FRAME_FORMAT_TINY_FRAME_WITH_LEN16 = 15, - FRAME_FORMAT_TINY_FRAME_WITH_LEN16_NO_CRC = 16, - FRAME_FORMAT_BASIC_FRAME_WITH_SYS_COMP = 17, - FRAME_FORMAT_UBX_FRAME = 18, - FRAME_FORMAT_MAVLINK_V1_FRAME = 19, - FRAME_FORMAT_MAVLINK_V2_FRAME = 20, - FRAME_FORMAT_FRAME_FORMAT_CONFIG = 21, -} FrameFormatType; - -/*=========================================================================== - * Checksum Calculation - *===========================================================================*/ - -typedef struct frame_checksum { - uint8_t byte1; - uint8_t byte2; -} frame_checksum_t; - -/** - * Calculate Fletcher-16 checksum over the given data - */ -static inline frame_checksum_t frame_fletcher_checksum(const uint8_t* data, size_t length) { - frame_checksum_t ck = {0, 0}; - for (size_t i = 0; i < length; i++) { - ck.byte1 = (uint8_t)(ck.byte1 + data[i]); - ck.byte2 = (uint8_t)(ck.byte2 + ck.byte1); - } - return ck; -} - -/* Parse result */ -typedef struct frame_msg_info { - bool valid; - uint8_t msg_id; - size_t msg_len; - uint8_t* msg_data; -} frame_msg_info_t; - -/*=========================================================================== - * MinimalFrame Frame Format - *===========================================================================*/ - -/* MinimalFrame constants */ -#define MINIMAL_FRAME_HEADER_SIZE 1 /* msg_id */ -#define MINIMAL_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define MINIMAL_FRAME_OVERHEAD (MINIMAL_FRAME_HEADER_SIZE + MINIMAL_FRAME_FOOTER_SIZE) - -/* MinimalFrame parser states */ -typedef enum minimal_frame_parser_state { - MINIMAL_FRAME_GETTING_MSG_ID = 0, - MINIMAL_FRAME_GETTING_PAYLOAD = 1 -} minimal_frame_parser_state_t; - -/* MinimalFrame parser state structure */ -typedef struct minimal_frame_parser { - minimal_frame_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} minimal_frame_parser_t; - -/* MinimalFrame encode buffer structure */ -typedef struct minimal_frame_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} minimal_frame_encode_buffer_t; - -/** - * Initialize a MinimalFrame parser - */ -static inline void minimal_frame_parser_init(minimal_frame_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MINIMAL_FRAME_GETTING_MSG_ID; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MinimalFrame parser state - */ -static inline void minimal_frame_parser_reset(minimal_frame_parser_t* parser) { - parser->state = MINIMAL_FRAME_GETTING_MSG_ID; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with MinimalFrame format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t minimal_frame_parse_byte(minimal_frame_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MINIMAL_FRAME_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = MINIMAL_FRAME_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MINIMAL_FRAME_GETTING_PAYLOAD; - } else { - parser->state = MINIMAL_FRAME_GETTING_MSG_ID; - } - } else { - parser->state = MINIMAL_FRAME_GETTING_MSG_ID; - } - } - break; - - case MINIMAL_FRAME_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - MINIMAL_FRAME_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 0, msg_length + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + MINIMAL_FRAME_HEADER_SIZE; - } - parser->state = MINIMAL_FRAME_GETTING_MSG_ID; - } - break; - } - - return result; -} - -/** - * Encode a message with MinimalFrame format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t minimal_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MINIMAL_FRAME_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_size + 1); - buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MinimalFrame packet in a buffer - */ -static inline frame_msg_info_t minimal_frame_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MINIMAL_FRAME_OVERHEAD) { - return result; - } - - - size_t msg_length = length - MINIMAL_FRAME_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * BasicFrame Frame Format - *===========================================================================*/ - -/* BasicFrame constants */ -#define BASIC_FRAME_START_BYTE1 0x90 -#define BASIC_FRAME_START_BYTE2 0x91 -#define BASIC_FRAME_HEADER_SIZE 3 /* start_byte1 + start_byte2 + msg_id */ -#define BASIC_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define BASIC_FRAME_OVERHEAD (BASIC_FRAME_HEADER_SIZE + BASIC_FRAME_FOOTER_SIZE) - -/* BasicFrame parser states */ -typedef enum basic_frame_parser_state { - BASIC_FRAME_LOOKING_FOR_START1 = 0, - BASIC_FRAME_LOOKING_FOR_START2 = 1, - BASIC_FRAME_GETTING_MSG_ID = 2, - BASIC_FRAME_GETTING_PAYLOAD = 3 -} basic_frame_parser_state_t; - -/* BasicFrame parser state structure */ -typedef struct basic_frame_parser { - basic_frame_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_parser_t; - -/* BasicFrame encode buffer structure */ -typedef struct basic_frame_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_encode_buffer_t; - -/** - * Initialize a BasicFrame parser - */ -static inline void basic_frame_parser_init(basic_frame_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrame parser state - */ -static inline void basic_frame_parser_reset(basic_frame_parser_t* parser) { - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with BasicFrame format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_parse_byte(basic_frame_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = BASIC_FRAME_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - } else { - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - } - break; - - case BASIC_FRAME_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - BASIC_FRAME_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 2, msg_length + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + BASIC_FRAME_HEADER_SIZE; - } - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrame format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_START_BYTE1; - buffer[1] = BASIC_FRAME_START_BYTE2; - buffer[2] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1); - buffer[BASIC_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrame packet in a buffer - */ -static inline frame_msg_info_t basic_frame_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * BasicFrameNoCrc Frame Format - *===========================================================================*/ - -/* BasicFrameNoCrc constants */ -#define BASIC_FRAME_NO_CRC_START_BYTE1 0x90 -#define BASIC_FRAME_NO_CRC_START_BYTE2 0x95 -#define BASIC_FRAME_NO_CRC_HEADER_SIZE 3 /* start_byte1 + start_byte2 + msg_id */ -#define BASIC_FRAME_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define BASIC_FRAME_NO_CRC_OVERHEAD (BASIC_FRAME_NO_CRC_HEADER_SIZE + BASIC_FRAME_NO_CRC_FOOTER_SIZE) - -/* BasicFrameNoCrc parser states */ -typedef enum basic_frame_no_crc_parser_state { - BASIC_FRAME_NO_CRC_LOOKING_FOR_START1 = 0, - BASIC_FRAME_NO_CRC_LOOKING_FOR_START2 = 1, - BASIC_FRAME_NO_CRC_GETTING_MSG_ID = 2, - BASIC_FRAME_NO_CRC_GETTING_PAYLOAD = 3 -} basic_frame_no_crc_parser_state_t; - -/* BasicFrameNoCrc parser state structure */ -typedef struct basic_frame_no_crc_parser { - basic_frame_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_no_crc_parser_t; - -/* BasicFrameNoCrc encode buffer structure */ -typedef struct basic_frame_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_no_crc_encode_buffer_t; - -/** - * Initialize a BasicFrameNoCrc parser - */ -static inline void basic_frame_no_crc_parser_init(basic_frame_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrameNoCrc parser state - */ -static inline void basic_frame_no_crc_parser_reset(basic_frame_no_crc_parser_t* parser) { - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with BasicFrameNoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_no_crc_parse_byte(basic_frame_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_NO_CRC_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_NO_CRC_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_NO_CRC_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_NO_CRC_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; - } - } else { - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; - } - } - break; - - case BASIC_FRAME_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - BASIC_FRAME_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE; - parser->state = BASIC_FRAME_NO_CRC_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrameNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_NO_CRC_START_BYTE1; - buffer[1] = BASIC_FRAME_NO_CRC_START_BYTE2; - buffer[2] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete BasicFrameNoCrc packet in a buffer - */ -static inline frame_msg_info_t basic_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_NO_CRC_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_NO_CRC_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_NO_CRC_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * TinyFrame Frame Format - *===========================================================================*/ - -/* TinyFrame constants */ -#define TINY_FRAME_START_BYTE 0x70 -#define TINY_FRAME_HEADER_SIZE 2 /* start_byte + msg_id */ -#define TINY_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define TINY_FRAME_OVERHEAD (TINY_FRAME_HEADER_SIZE + TINY_FRAME_FOOTER_SIZE) - -/* TinyFrame parser states */ -typedef enum tiny_frame_parser_state { - TINY_FRAME_LOOKING_FOR_START = 0, - TINY_FRAME_GETTING_MSG_ID = 1, - TINY_FRAME_GETTING_PAYLOAD = 2 -} tiny_frame_parser_state_t; - -/* TinyFrame parser state structure */ -typedef struct tiny_frame_parser { - tiny_frame_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} tiny_frame_parser_t; - -/* TinyFrame encode buffer structure */ -typedef struct tiny_frame_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} tiny_frame_encode_buffer_t; - -/** - * Initialize a TinyFrame parser - */ -static inline void tiny_frame_parser_init(tiny_frame_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = TINY_FRAME_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset TinyFrame parser state - */ -static inline void tiny_frame_parser_reset(tiny_frame_parser_t* parser) { - parser->state = TINY_FRAME_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with TinyFrame format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t tiny_frame_parse_byte(tiny_frame_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case TINY_FRAME_LOOKING_FOR_START: - if (byte == TINY_FRAME_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = TINY_FRAME_GETTING_MSG_ID; - } - break; - - case TINY_FRAME_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = TINY_FRAME_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = TINY_FRAME_GETTING_PAYLOAD; - } else { - parser->state = TINY_FRAME_LOOKING_FOR_START; - } - } else { - parser->state = TINY_FRAME_LOOKING_FOR_START; - } - } - break; - - case TINY_FRAME_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - TINY_FRAME_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 1, msg_length + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + TINY_FRAME_HEADER_SIZE; - } - parser->state = TINY_FRAME_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with TinyFrame format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t tiny_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = TINY_FRAME_START_BYTE; - buffer[1] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + TINY_FRAME_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1); - buffer[TINY_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[TINY_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete TinyFrame packet in a buffer - */ -static inline frame_msg_info_t tiny_frame_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < TINY_FRAME_OVERHEAD) { - return result; - } - - if (buffer[0] != TINY_FRAME_START_BYTE) { - return result; - } - - size_t msg_length = length - TINY_FRAME_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + TINY_FRAME_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * TinyFrameNoCrc Frame Format - *===========================================================================*/ - -/* TinyFrameNoCrc constants */ -#define TINY_FRAME_NO_CRC_START_BYTE 0x72 -#define TINY_FRAME_NO_CRC_HEADER_SIZE 2 /* start_byte + msg_id */ -#define TINY_FRAME_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define TINY_FRAME_NO_CRC_OVERHEAD (TINY_FRAME_NO_CRC_HEADER_SIZE + TINY_FRAME_NO_CRC_FOOTER_SIZE) - -/* TinyFrameNoCrc parser states */ -typedef enum tiny_frame_no_crc_parser_state { - TINY_FRAME_NO_CRC_LOOKING_FOR_START = 0, - TINY_FRAME_NO_CRC_GETTING_MSG_ID = 1, - TINY_FRAME_NO_CRC_GETTING_PAYLOAD = 2 -} tiny_frame_no_crc_parser_state_t; - -/* TinyFrameNoCrc parser state structure */ -typedef struct tiny_frame_no_crc_parser { - tiny_frame_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} tiny_frame_no_crc_parser_t; - -/* TinyFrameNoCrc encode buffer structure */ -typedef struct tiny_frame_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} tiny_frame_no_crc_encode_buffer_t; - -/** - * Initialize a TinyFrameNoCrc parser - */ -static inline void tiny_frame_no_crc_parser_init(tiny_frame_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset TinyFrameNoCrc parser state - */ -static inline void tiny_frame_no_crc_parser_reset(tiny_frame_no_crc_parser_t* parser) { - parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with TinyFrameNoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t tiny_frame_no_crc_parse_byte(tiny_frame_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case TINY_FRAME_NO_CRC_LOOKING_FOR_START: - if (byte == TINY_FRAME_NO_CRC_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = TINY_FRAME_NO_CRC_GETTING_MSG_ID; - } - break; - - case TINY_FRAME_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = TINY_FRAME_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; - } - } else { - parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; - } - } - break; - - case TINY_FRAME_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - TINY_FRAME_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + TINY_FRAME_NO_CRC_HEADER_SIZE; - parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with TinyFrameNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t tiny_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = TINY_FRAME_NO_CRC_START_BYTE; - buffer[1] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete TinyFrameNoCrc packet in a buffer - */ -static inline frame_msg_info_t tiny_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < TINY_FRAME_NO_CRC_OVERHEAD) { - return result; - } - - if (buffer[0] != TINY_FRAME_NO_CRC_START_BYTE) { - return result; - } - - size_t msg_length = length - TINY_FRAME_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * MinimalFrameWithLen Frame Format - *===========================================================================*/ - -/* MinimalFrameWithLen constants */ -#define MINIMAL_FRAME_WITH_LEN_HEADER_SIZE 2 /* msg_id + length(1) */ -#define MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define MINIMAL_FRAME_WITH_LEN_OVERHEAD (MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE) - -/* MinimalFrameWithLen parser states */ -typedef enum minimal_frame_with_len_parser_state { - MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID = 0, - MINIMAL_FRAME_WITH_LEN_GETTING_LENGTH = 1, - MINIMAL_FRAME_WITH_LEN_GETTING_PAYLOAD = 2 -} minimal_frame_with_len_parser_state_t; - -/* MinimalFrameWithLen parser state structure */ -typedef struct minimal_frame_with_len_parser { - minimal_frame_with_len_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} minimal_frame_with_len_parser_t; - -/* MinimalFrameWithLen encode buffer structure */ -typedef struct minimal_frame_with_len_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} minimal_frame_with_len_encode_buffer_t; - -/** - * Initialize a MinimalFrameWithLen parser - */ -static inline void minimal_frame_with_len_parser_init(minimal_frame_with_len_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MinimalFrameWithLen parser state - */ -static inline void minimal_frame_with_len_parser_reset(minimal_frame_with_len_parser_t* parser) { - parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with MinimalFrameWithLen format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t minimal_frame_with_len_parse_byte(minimal_frame_with_len_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_LENGTH; - break; - - case MINIMAL_FRAME_WITH_LEN_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_PAYLOAD; - } else { - parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; - } - break; - - case MINIMAL_FRAME_WITH_LEN_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - MINIMAL_FRAME_WITH_LEN_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 0, msg_length + 1 + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE; - } - parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; - } - break; - } - - return result; -} - -/** - * Encode a message with MinimalFrameWithLen format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t minimal_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = msg_id; - buffer[1] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_size + 1 + 1); - buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLen packet in a buffer - */ -static inline frame_msg_info_t minimal_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MINIMAL_FRAME_WITH_LEN_OVERHEAD) { - return result; - } - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * MinimalFrameWithLenNoCrc Frame Format - *===========================================================================*/ - -/* MinimalFrameWithLenNoCrc constants */ -#define MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE 2 /* msg_id + length(1) */ -#define MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD (MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE) - -/* MinimalFrameWithLenNoCrc parser states */ -typedef enum minimal_frame_with_len_no_crc_parser_state { - MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID = 0, - MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH = 1, - MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD = 2 -} minimal_frame_with_len_no_crc_parser_state_t; - -/* MinimalFrameWithLenNoCrc parser state structure */ -typedef struct minimal_frame_with_len_no_crc_parser { - minimal_frame_with_len_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} minimal_frame_with_len_no_crc_parser_t; - -/* MinimalFrameWithLenNoCrc encode buffer structure */ -typedef struct minimal_frame_with_len_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} minimal_frame_with_len_no_crc_encode_buffer_t; - -/** - * Initialize a MinimalFrameWithLenNoCrc parser - */ -static inline void minimal_frame_with_len_no_crc_parser_init(minimal_frame_with_len_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MinimalFrameWithLenNoCrc parser state - */ -static inline void minimal_frame_with_len_no_crc_parser_reset(minimal_frame_with_len_no_crc_parser_t* parser) { - parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with MinimalFrameWithLenNoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t minimal_frame_with_len_no_crc_parse_byte(minimal_frame_with_len_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH; - break; - - case MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; - } - break; - - case MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; - parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; - } - break; - } - - return result; -} - -/** - * Encode a message with MinimalFrameWithLenNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t minimal_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = msg_id; - buffer[1] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLenNoCrc packet in a buffer - */ -static inline frame_msg_info_t minimal_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD) { - return result; - } - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * BasicFrameWithLen Frame Format - *===========================================================================*/ - -/* BasicFrameWithLen constants */ -#define BASIC_FRAME_WITH_LEN_START_BYTE1 0x90 -#define BASIC_FRAME_WITH_LEN_START_BYTE2 0x92 -#define BASIC_FRAME_WITH_LEN_HEADER_SIZE 4 /* start_byte1 + start_byte2 + msg_id + length(1) */ -#define BASIC_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define BASIC_FRAME_WITH_LEN_OVERHEAD (BASIC_FRAME_WITH_LEN_HEADER_SIZE + BASIC_FRAME_WITH_LEN_FOOTER_SIZE) - -/* BasicFrameWithLen parser states */ -typedef enum basic_frame_with_len_parser_state { - BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1 = 0, - BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2 = 1, - BASIC_FRAME_WITH_LEN_GETTING_MSG_ID = 2, - BASIC_FRAME_WITH_LEN_GETTING_LENGTH = 3, - BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD = 4 -} basic_frame_with_len_parser_state_t; - -/* BasicFrameWithLen parser state structure */ -typedef struct basic_frame_with_len_parser { - basic_frame_with_len_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_with_len_parser_t; - -/* BasicFrameWithLen encode buffer structure */ -typedef struct basic_frame_with_len_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_with_len_encode_buffer_t; - -/** - * Initialize a BasicFrameWithLen parser - */ -static inline void basic_frame_with_len_parser_init(basic_frame_with_len_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrameWithLen parser state - */ -static inline void basic_frame_with_len_parser_reset(basic_frame_with_len_parser_t* parser) { - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with BasicFrameWithLen format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_with_len_parse_byte(basic_frame_with_len_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_WITH_LEN_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_WITH_LEN_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = BASIC_FRAME_WITH_LEN_GETTING_LENGTH; - break; - - case BASIC_FRAME_WITH_LEN_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = BASIC_FRAME_WITH_LEN_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - BASIC_FRAME_WITH_LEN_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 2, msg_length + 1 + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE; - } - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrameWithLen format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1 + 1); - buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLen packet in a buffer - */ -static inline frame_msg_info_t basic_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_WITH_LEN_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_WITH_LEN_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_WITH_LEN_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_WITH_LEN_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * BasicFrameWithLenNoCrc Frame Format - *===========================================================================*/ - -/* BasicFrameWithLenNoCrc constants */ -#define BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1 0x90 -#define BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2 0x96 -#define BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE 4 /* start_byte1 + start_byte2 + msg_id + length(1) */ -#define BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD (BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE) - -/* BasicFrameWithLenNoCrc parser states */ -typedef enum basic_frame_with_len_no_crc_parser_state { - BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1 = 0, - BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2 = 1, - BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID = 2, - BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH = 3, - BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD = 4 -} basic_frame_with_len_no_crc_parser_state_t; - -/* BasicFrameWithLenNoCrc parser state structure */ -typedef struct basic_frame_with_len_no_crc_parser { - basic_frame_with_len_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_with_len_no_crc_parser_t; - -/* BasicFrameWithLenNoCrc encode buffer structure */ -typedef struct basic_frame_with_len_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_with_len_no_crc_encode_buffer_t; - -/** - * Initialize a BasicFrameWithLenNoCrc parser - */ -static inline void basic_frame_with_len_no_crc_parser_init(basic_frame_with_len_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrameWithLenNoCrc parser state - */ -static inline void basic_frame_with_len_no_crc_parser_reset(basic_frame_with_len_no_crc_parser_t* parser) { - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with BasicFrameWithLenNoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_with_len_no_crc_parse_byte(basic_frame_with_len_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH; - break; - - case BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; - parser->state = BASIC_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrameWithLenNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLenNoCrc packet in a buffer - */ -static inline frame_msg_info_t basic_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * TinyFrameWithLen Frame Format - *===========================================================================*/ - -/* TinyFrameWithLen constants */ -#define TINY_FRAME_WITH_LEN_START_BYTE 0x71 -#define TINY_FRAME_WITH_LEN_HEADER_SIZE 3 /* start_byte + msg_id + length(1) */ -#define TINY_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define TINY_FRAME_WITH_LEN_OVERHEAD (TINY_FRAME_WITH_LEN_HEADER_SIZE + TINY_FRAME_WITH_LEN_FOOTER_SIZE) - -/* TinyFrameWithLen parser states */ -typedef enum tiny_frame_with_len_parser_state { - TINY_FRAME_WITH_LEN_LOOKING_FOR_START = 0, - TINY_FRAME_WITH_LEN_GETTING_MSG_ID = 1, - TINY_FRAME_WITH_LEN_GETTING_LENGTH = 2, - TINY_FRAME_WITH_LEN_GETTING_PAYLOAD = 3 -} tiny_frame_with_len_parser_state_t; - -/* TinyFrameWithLen parser state structure */ -typedef struct tiny_frame_with_len_parser { - tiny_frame_with_len_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} tiny_frame_with_len_parser_t; - -/* TinyFrameWithLen encode buffer structure */ -typedef struct tiny_frame_with_len_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} tiny_frame_with_len_encode_buffer_t; - -/** - * Initialize a TinyFrameWithLen parser - */ -static inline void tiny_frame_with_len_parser_init(tiny_frame_with_len_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset TinyFrameWithLen parser state - */ -static inline void tiny_frame_with_len_parser_reset(tiny_frame_with_len_parser_t* parser) { - parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with TinyFrameWithLen format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t tiny_frame_with_len_parse_byte(tiny_frame_with_len_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case TINY_FRAME_WITH_LEN_LOOKING_FOR_START: - if (byte == TINY_FRAME_WITH_LEN_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = TINY_FRAME_WITH_LEN_GETTING_MSG_ID; - } - break; - - case TINY_FRAME_WITH_LEN_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = TINY_FRAME_WITH_LEN_GETTING_LENGTH; - break; - - case TINY_FRAME_WITH_LEN_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = TINY_FRAME_WITH_LEN_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = TINY_FRAME_WITH_LEN_GETTING_PAYLOAD; - } else { - parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; - } - break; - - case TINY_FRAME_WITH_LEN_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - TINY_FRAME_WITH_LEN_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 1, msg_length + 1 + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE; - } - parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with TinyFrameWithLen format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t tiny_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = TINY_FRAME_WITH_LEN_START_BYTE; - buffer[1] = msg_id; - buffer[2] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 1); - buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLen packet in a buffer - */ -static inline frame_msg_info_t tiny_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < TINY_FRAME_WITH_LEN_OVERHEAD) { - return result; - } - - if (buffer[0] != TINY_FRAME_WITH_LEN_START_BYTE) { - return result; - } - - size_t msg_length = length - TINY_FRAME_WITH_LEN_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * TinyFrameWithLenNoCrc Frame Format - *===========================================================================*/ - -/* TinyFrameWithLenNoCrc constants */ -#define TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE 0x73 -#define TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE 3 /* start_byte + msg_id + length(1) */ -#define TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD (TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE) - -/* TinyFrameWithLenNoCrc parser states */ -typedef enum tiny_frame_with_len_no_crc_parser_state { - TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START = 0, - TINY_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID = 1, - TINY_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH = 2, - TINY_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD = 3 -} tiny_frame_with_len_no_crc_parser_state_t; - -/* TinyFrameWithLenNoCrc parser state structure */ -typedef struct tiny_frame_with_len_no_crc_parser { - tiny_frame_with_len_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} tiny_frame_with_len_no_crc_parser_t; - -/* TinyFrameWithLenNoCrc encode buffer structure */ -typedef struct tiny_frame_with_len_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} tiny_frame_with_len_no_crc_encode_buffer_t; - -/** - * Initialize a TinyFrameWithLenNoCrc parser - */ -static inline void tiny_frame_with_len_no_crc_parser_init(tiny_frame_with_len_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset TinyFrameWithLenNoCrc parser state - */ -static inline void tiny_frame_with_len_no_crc_parser_reset(tiny_frame_with_len_no_crc_parser_t* parser) { - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with TinyFrameWithLenNoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t tiny_frame_with_len_no_crc_parse_byte(tiny_frame_with_len_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START: - if (byte == TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; - } - break; - - case TINY_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH; - break; - - case TINY_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; - } - break; - - case TINY_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; - parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with TinyFrameWithLenNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t tiny_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE; - buffer[1] = msg_id; - buffer[2] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLenNoCrc packet in a buffer - */ -static inline frame_msg_info_t tiny_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD) { - return result; - } - - if (buffer[0] != TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) { - return result; - } - - size_t msg_length = length - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * MinimalFrameWithLen16 Frame Format - *===========================================================================*/ - -/* MinimalFrameWithLen16 constants */ -#define MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE 3 /* msg_id + length(2) */ -#define MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define MINIMAL_FRAME_WITH_LEN16_OVERHEAD (MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE) - -/* MinimalFrameWithLen16 parser states */ -typedef enum minimal_frame_with_len16_parser_state { - MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID = 0, - MINIMAL_FRAME_WITH_LEN16_GETTING_LENGTH = 1, - MINIMAL_FRAME_WITH_LEN16_GETTING_PAYLOAD = 2 -} minimal_frame_with_len16_parser_state_t; - -/* MinimalFrameWithLen16 parser state structure */ -typedef struct minimal_frame_with_len16_parser { - minimal_frame_with_len16_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - uint8_t length_lo; /* Low byte for 16-bit length */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} minimal_frame_with_len16_parser_t; - -/* MinimalFrameWithLen16 encode buffer structure */ -typedef struct minimal_frame_with_len16_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} minimal_frame_with_len16_encode_buffer_t; - -/** - * Initialize a MinimalFrameWithLen16 parser - */ -static inline void minimal_frame_with_len16_parser_init(minimal_frame_with_len16_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->length_lo = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MinimalFrameWithLen16 parser state - */ -static inline void minimal_frame_with_len16_parser_reset(minimal_frame_with_len16_parser_t* parser) { - parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with MinimalFrameWithLen16 format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t minimal_frame_with_len16_parse_byte(minimal_frame_with_len16_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_LENGTH; - break; - - case MINIMAL_FRAME_WITH_LEN16_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - if (parser->buffer_index == 2) { - parser->length_lo = byte; - } else { - parser->msg_length = parser->length_lo | ((size_t)byte << 8); - parser->packet_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_PAYLOAD; - } else { - parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; - } - } - break; - - case MINIMAL_FRAME_WITH_LEN16_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 0, msg_length + 1 + 2); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE; - } - parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; - } - break; - } - - return result; -} - -/** - * Encode a message with MinimalFrameWithLen16 format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t minimal_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = msg_id; - buffer[1] = (uint8_t)(msg_size & 0xFF); - buffer[2] = (uint8_t)((msg_size >> 8) & 0xFF); - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_size + 1 + 2); - buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLen16 packet in a buffer - */ -static inline frame_msg_info_t minimal_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MINIMAL_FRAME_WITH_LEN16_OVERHEAD) { - return result; - } - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_length + 1 + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * MinimalFrameWithLen16NoCrc Frame Format - *===========================================================================*/ - -/* MinimalFrameWithLen16NoCrc constants */ -#define MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE 3 /* msg_id + length(2) */ -#define MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD (MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE) - -/* MinimalFrameWithLen16NoCrc parser states */ -typedef enum minimal_frame_with_len16_no_crc_parser_state { - MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID = 0, - MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH = 1, - MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD = 2 -} minimal_frame_with_len16_no_crc_parser_state_t; - -/* MinimalFrameWithLen16NoCrc parser state structure */ -typedef struct minimal_frame_with_len16_no_crc_parser { - minimal_frame_with_len16_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - uint8_t length_lo; /* Low byte for 16-bit length */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} minimal_frame_with_len16_no_crc_parser_t; - -/* MinimalFrameWithLen16NoCrc encode buffer structure */ -typedef struct minimal_frame_with_len16_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} minimal_frame_with_len16_no_crc_encode_buffer_t; - -/** - * Initialize a MinimalFrameWithLen16NoCrc parser - */ -static inline void minimal_frame_with_len16_no_crc_parser_init(minimal_frame_with_len16_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->length_lo = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MinimalFrameWithLen16NoCrc parser state - */ -static inline void minimal_frame_with_len16_no_crc_parser_reset(minimal_frame_with_len16_no_crc_parser_t* parser) { - parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with MinimalFrameWithLen16NoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t minimal_frame_with_len16_no_crc_parse_byte(minimal_frame_with_len16_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH; - break; - - case MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - if (parser->buffer_index == 2) { - parser->length_lo = byte; - } else { - parser->msg_length = parser->length_lo | ((size_t)byte << 8); - parser->packet_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; - } - } - break; - - case MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; - parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; - } - break; - } - - return result; -} - -/** - * Encode a message with MinimalFrameWithLen16NoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t minimal_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = msg_id; - buffer[1] = (uint8_t)(msg_size & 0xFF); - buffer[2] = (uint8_t)((msg_size >> 8) & 0xFF); - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer - */ -static inline frame_msg_info_t minimal_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) { - return result; - } - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * BasicFrameWithLen16 Frame Format - *===========================================================================*/ - -/* BasicFrameWithLen16 constants */ -#define BASIC_FRAME_WITH_LEN16_START_BYTE1 0x90 -#define BASIC_FRAME_WITH_LEN16_START_BYTE2 0x93 -#define BASIC_FRAME_WITH_LEN16_HEADER_SIZE 5 /* start_byte1 + start_byte2 + msg_id + length(2) */ -#define BASIC_FRAME_WITH_LEN16_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define BASIC_FRAME_WITH_LEN16_OVERHEAD (BASIC_FRAME_WITH_LEN16_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_FOOTER_SIZE) - -/* BasicFrameWithLen16 parser states */ -typedef enum basic_frame_with_len16_parser_state { - BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1 = 0, - BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2 = 1, - BASIC_FRAME_WITH_LEN16_GETTING_MSG_ID = 2, - BASIC_FRAME_WITH_LEN16_GETTING_LENGTH = 3, - BASIC_FRAME_WITH_LEN16_GETTING_PAYLOAD = 4 -} basic_frame_with_len16_parser_state_t; - -/* BasicFrameWithLen16 parser state structure */ -typedef struct basic_frame_with_len16_parser { - basic_frame_with_len16_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - uint8_t length_lo; /* Low byte for 16-bit length */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_with_len16_parser_t; - -/* BasicFrameWithLen16 encode buffer structure */ -typedef struct basic_frame_with_len16_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_with_len16_encode_buffer_t; - -/** - * Initialize a BasicFrameWithLen16 parser - */ -static inline void basic_frame_with_len16_parser_init(basic_frame_with_len16_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->length_lo = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrameWithLen16 parser state - */ -static inline void basic_frame_with_len16_parser_reset(basic_frame_with_len16_parser_t* parser) { - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with BasicFrameWithLen16 format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_with_len16_parse_byte(basic_frame_with_len16_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_WITH_LEN16_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN16_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = BASIC_FRAME_WITH_LEN16_GETTING_LENGTH; - break; - - case BASIC_FRAME_WITH_LEN16_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - if (parser->buffer_index == 4) { - parser->length_lo = byte; - } else { - parser->msg_length = parser->length_lo | ((size_t)byte << 8); - parser->packet_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_WITH_LEN16_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; - } - } - break; - - case BASIC_FRAME_WITH_LEN16_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - BASIC_FRAME_WITH_LEN16_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 2, msg_length + 1 + 2); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE; - } - parser->state = BASIC_FRAME_WITH_LEN16_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrameWithLen16 format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_WITH_LEN16_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN16_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = (uint8_t)(msg_size & 0xFF); - buffer[4] = (uint8_t)((msg_size >> 8) & 0xFF); - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1 + 2); - buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLen16 packet in a buffer - */ -static inline frame_msg_info_t basic_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_WITH_LEN16_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_WITH_LEN16_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_WITH_LEN16_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_WITH_LEN16_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1 + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * BasicFrameWithLen16NoCrc Frame Format - *===========================================================================*/ - -/* BasicFrameWithLen16NoCrc constants */ -#define BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1 0x90 -#define BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2 0x97 -#define BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE 5 /* start_byte1 + start_byte2 + msg_id + length(2) */ -#define BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD (BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE) - -/* BasicFrameWithLen16NoCrc parser states */ -typedef enum basic_frame_with_len16_no_crc_parser_state { - BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1 = 0, - BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2 = 1, - BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID = 2, - BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH = 3, - BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD = 4 -} basic_frame_with_len16_no_crc_parser_state_t; - -/* BasicFrameWithLen16NoCrc parser state structure */ -typedef struct basic_frame_with_len16_no_crc_parser { - basic_frame_with_len16_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - uint8_t length_lo; /* Low byte for 16-bit length */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_with_len16_no_crc_parser_t; - -/* BasicFrameWithLen16NoCrc encode buffer structure */ -typedef struct basic_frame_with_len16_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_with_len16_no_crc_encode_buffer_t; - -/** - * Initialize a BasicFrameWithLen16NoCrc parser - */ -static inline void basic_frame_with_len16_no_crc_parser_init(basic_frame_with_len16_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->length_lo = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrameWithLen16NoCrc parser state - */ -static inline void basic_frame_with_len16_no_crc_parser_reset(basic_frame_with_len16_no_crc_parser_t* parser) { - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with BasicFrameWithLen16NoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_with_len16_no_crc_parse_byte(basic_frame_with_len16_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH; - break; - - case BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - if (parser->buffer_index == 4) { - parser->length_lo = byte; - } else { - parser->msg_length = parser->length_lo | ((size_t)byte << 8); - parser->packet_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; - } - } - break; - - case BASIC_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; - parser->state = BASIC_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrameWithLen16NoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = (uint8_t)(msg_size & 0xFF); - buffer[4] = (uint8_t)((msg_size >> 8) & 0xFF); - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLen16NoCrc packet in a buffer - */ -static inline frame_msg_info_t basic_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * TinyFrameWithLen16 Frame Format - *===========================================================================*/ - -/* TinyFrameWithLen16 constants */ -#define TINY_FRAME_WITH_LEN16_START_BYTE 0x74 -#define TINY_FRAME_WITH_LEN16_HEADER_SIZE 4 /* start_byte + msg_id + length(2) */ -#define TINY_FRAME_WITH_LEN16_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define TINY_FRAME_WITH_LEN16_OVERHEAD (TINY_FRAME_WITH_LEN16_HEADER_SIZE + TINY_FRAME_WITH_LEN16_FOOTER_SIZE) - -/* TinyFrameWithLen16 parser states */ -typedef enum tiny_frame_with_len16_parser_state { - TINY_FRAME_WITH_LEN16_LOOKING_FOR_START = 0, - TINY_FRAME_WITH_LEN16_GETTING_MSG_ID = 1, - TINY_FRAME_WITH_LEN16_GETTING_LENGTH = 2, - TINY_FRAME_WITH_LEN16_GETTING_PAYLOAD = 3 -} tiny_frame_with_len16_parser_state_t; - -/* TinyFrameWithLen16 parser state structure */ -typedef struct tiny_frame_with_len16_parser { - tiny_frame_with_len16_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - uint8_t length_lo; /* Low byte for 16-bit length */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} tiny_frame_with_len16_parser_t; - -/* TinyFrameWithLen16 encode buffer structure */ -typedef struct tiny_frame_with_len16_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} tiny_frame_with_len16_encode_buffer_t; - -/** - * Initialize a TinyFrameWithLen16 parser - */ -static inline void tiny_frame_with_len16_parser_init(tiny_frame_with_len16_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->length_lo = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset TinyFrameWithLen16 parser state - */ -static inline void tiny_frame_with_len16_parser_reset(tiny_frame_with_len16_parser_t* parser) { - parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with TinyFrameWithLen16 format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t tiny_frame_with_len16_parse_byte(tiny_frame_with_len16_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case TINY_FRAME_WITH_LEN16_LOOKING_FOR_START: - if (byte == TINY_FRAME_WITH_LEN16_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = TINY_FRAME_WITH_LEN16_GETTING_MSG_ID; - } - break; - - case TINY_FRAME_WITH_LEN16_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = TINY_FRAME_WITH_LEN16_GETTING_LENGTH; - break; - - case TINY_FRAME_WITH_LEN16_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - if (parser->buffer_index == 3) { - parser->length_lo = byte; - } else { - parser->msg_length = parser->length_lo | ((size_t)byte << 8); - parser->packet_size = TINY_FRAME_WITH_LEN16_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = TINY_FRAME_WITH_LEN16_GETTING_PAYLOAD; - } else { - parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; - } - } - break; - - case TINY_FRAME_WITH_LEN16_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - TINY_FRAME_WITH_LEN16_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 1, msg_length + 1 + 2); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE; - } - parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with TinyFrameWithLen16 format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t tiny_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = TINY_FRAME_WITH_LEN16_START_BYTE; - buffer[1] = msg_id; - buffer[2] = (uint8_t)(msg_size & 0xFF); - buffer[3] = (uint8_t)((msg_size >> 8) & 0xFF); - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 2); - buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLen16 packet in a buffer - */ -static inline frame_msg_info_t tiny_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < TINY_FRAME_WITH_LEN16_OVERHEAD) { - return result; - } - - if (buffer[0] != TINY_FRAME_WITH_LEN16_START_BYTE) { - return result; - } - - size_t msg_length = length - TINY_FRAME_WITH_LEN16_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * TinyFrameWithLen16NoCrc Frame Format - *===========================================================================*/ - -/* TinyFrameWithLen16NoCrc constants */ -#define TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE 0x75 -#define TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE 4 /* start_byte + msg_id + length(2) */ -#define TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE 0 /* no footer */ -#define TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD (TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE) - -/* TinyFrameWithLen16NoCrc parser states */ -typedef enum tiny_frame_with_len16_no_crc_parser_state { - TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START = 0, - TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID = 1, - TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH = 2, - TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD = 3 -} tiny_frame_with_len16_no_crc_parser_state_t; - -/* TinyFrameWithLen16NoCrc parser state structure */ -typedef struct tiny_frame_with_len16_no_crc_parser { - tiny_frame_with_len16_no_crc_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - uint8_t length_lo; /* Low byte for 16-bit length */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} tiny_frame_with_len16_no_crc_parser_t; - -/* TinyFrameWithLen16NoCrc encode buffer structure */ -typedef struct tiny_frame_with_len16_no_crc_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} tiny_frame_with_len16_no_crc_encode_buffer_t; - -/** - * Initialize a TinyFrameWithLen16NoCrc parser - */ -static inline void tiny_frame_with_len16_no_crc_parser_init(tiny_frame_with_len16_no_crc_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->length_lo = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset TinyFrameWithLen16NoCrc parser state - */ -static inline void tiny_frame_with_len16_no_crc_parser_reset(tiny_frame_with_len16_no_crc_parser_t* parser) { - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with TinyFrameWithLen16NoCrc format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t tiny_frame_with_len16_no_crc_parse_byte(tiny_frame_with_len16_no_crc_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START: - if (byte == TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; - } - break; - - case TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH; - break; - - case TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - if (parser->buffer_index == 3) { - parser->length_lo = byte; - } else { - parser->msg_length = parser->length_lo | ((size_t)byte << 8); - parser->packet_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD; - } else { - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; - } - } - break; - - case TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = parser->packet_size - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; - parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with TinyFrameWithLen16NoCrc format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t tiny_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE; - buffer[1] = msg_id; - buffer[2] = (uint8_t)(msg_size & 0xFF); - buffer[3] = (uint8_t)((msg_size >> 8) & 0xFF); - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLen16NoCrc packet in a buffer - */ -static inline frame_msg_info_t tiny_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) { - return result; - } - - if (buffer[0] != TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) { - return result; - } - - size_t msg_length = length - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); - - return result; -} - - -/*=========================================================================== - * BasicFrameWithSysComp Frame Format - *===========================================================================*/ - -/* BasicFrameWithSysComp constants */ -#define BASIC_FRAME_WITH_SYS_COMP_START_BYTE1 0x90 -#define BASIC_FRAME_WITH_SYS_COMP_START_BYTE2 0x94 -#define BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE 3 /* start_byte1 + start_byte2 + msg_id */ -#define BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define BASIC_FRAME_WITH_SYS_COMP_OVERHEAD (BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE) - -/* BasicFrameWithSysComp parser states */ -typedef enum basic_frame_with_sys_comp_parser_state { - BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1 = 0, - BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2 = 1, - BASIC_FRAME_WITH_SYS_COMP_GETTING_MSG_ID = 2, - BASIC_FRAME_WITH_SYS_COMP_GETTING_PAYLOAD = 3 -} basic_frame_with_sys_comp_parser_state_t; - -/* BasicFrameWithSysComp parser state structure */ -typedef struct basic_frame_with_sys_comp_parser { - basic_frame_with_sys_comp_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_with_sys_comp_parser_t; - -/* BasicFrameWithSysComp encode buffer structure */ -typedef struct basic_frame_with_sys_comp_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} basic_frame_with_sys_comp_encode_buffer_t; - -/** - * Initialize a BasicFrameWithSysComp parser - */ -static inline void basic_frame_with_sys_comp_parser_init(basic_frame_with_sys_comp_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset BasicFrameWithSysComp parser state - */ -static inline void basic_frame_with_sys_comp_parser_reset(basic_frame_with_sys_comp_parser_t* parser) { - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with BasicFrameWithSysComp format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t basic_frame_with_sys_comp_parse_byte(basic_frame_with_sys_comp_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1: - if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2; - } - break; - - case BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2: - if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = BASIC_FRAME_WITH_SYS_COMP_GETTING_MSG_ID; - } else if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START2; - } else { - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_SYS_COMP_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_WITH_SYS_COMP_GETTING_PAYLOAD; - } else { - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; - } - } else { - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; - } - } - break; - - case BASIC_FRAME_WITH_SYS_COMP_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 2, msg_length + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE; - } - parser->state = BASIC_FRAME_WITH_SYS_COMP_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with BasicFrameWithSysComp format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t basic_frame_with_sys_comp_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE2; - buffer[2] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1); - buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrameWithSysComp packet in a buffer - */ -static inline frame_msg_info_t basic_frame_with_sys_comp_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_WITH_SYS_COMP_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { - return result; - } - if (buffer[1] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * UbxFrame Frame Format - *===========================================================================*/ - -/* UbxFrame constants */ -#define UBX_FRAME_START_BYTE1 0xB5 -#define UBX_FRAME_START_BYTE2 0x62 -#define UBX_FRAME_HEADER_SIZE 5 /* sync1 + sync2 + msg_id + length(1) */ -#define UBX_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define UBX_FRAME_OVERHEAD (UBX_FRAME_HEADER_SIZE + UBX_FRAME_FOOTER_SIZE) - -/* UbxFrame parser states */ -typedef enum ubx_frame_parser_state { - UBX_FRAME_LOOKING_FOR_START1 = 0, - UBX_FRAME_LOOKING_FOR_START2 = 1, - UBX_FRAME_GETTING_MSG_ID = 2, - UBX_FRAME_GETTING_LENGTH = 3, - UBX_FRAME_GETTING_PAYLOAD = 4 -} ubx_frame_parser_state_t; - -/* UbxFrame parser state structure */ -typedef struct ubx_frame_parser { - ubx_frame_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} ubx_frame_parser_t; - -/* UbxFrame encode buffer structure */ -typedef struct ubx_frame_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} ubx_frame_encode_buffer_t; - -/** - * Initialize a UbxFrame parser - */ -static inline void ubx_frame_parser_init(ubx_frame_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = UBX_FRAME_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset UbxFrame parser state - */ -static inline void ubx_frame_parser_reset(ubx_frame_parser_t* parser) { - parser->state = UBX_FRAME_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with UbxFrame format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t ubx_frame_parse_byte(ubx_frame_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case UBX_FRAME_LOOKING_FOR_START1: - if (byte == UBX_FRAME_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = UBX_FRAME_LOOKING_FOR_START2; - } - break; - - case UBX_FRAME_LOOKING_FOR_START2: - if (byte == UBX_FRAME_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = UBX_FRAME_GETTING_MSG_ID; - } else if (byte == UBX_FRAME_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = UBX_FRAME_LOOKING_FOR_START2; - } else { - parser->state = UBX_FRAME_LOOKING_FOR_START1; - } - break; - - case UBX_FRAME_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = UBX_FRAME_GETTING_LENGTH; - break; - - case UBX_FRAME_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = UBX_FRAME_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = UBX_FRAME_GETTING_PAYLOAD; - } else { - parser->state = UBX_FRAME_LOOKING_FOR_START1; - } - break; - - case UBX_FRAME_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - UBX_FRAME_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 2, msg_length + 1 + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + UBX_FRAME_HEADER_SIZE; - } - parser->state = UBX_FRAME_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with UbxFrame format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t ubx_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = UBX_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = UBX_FRAME_START_BYTE1; - buffer[1] = UBX_FRAME_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + UBX_FRAME_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1 + 1); - buffer[UBX_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[UBX_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete UbxFrame packet in a buffer - */ -static inline frame_msg_info_t ubx_frame_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < UBX_FRAME_OVERHEAD) { - return result; - } - - if (buffer[0] != UBX_FRAME_START_BYTE1) { - return result; - } - if (buffer[1] != UBX_FRAME_START_BYTE2) { - return result; - } - - size_t msg_length = length - UBX_FRAME_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + UBX_FRAME_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * MavlinkV1Frame Frame Format - *===========================================================================*/ - -/* MavlinkV1Frame constants */ -#define MAVLINK_V1_FRAME_START_BYTE 0xFE -#define MAVLINK_V1_FRAME_HEADER_SIZE 3 /* stx + msg_id + length(1) */ -#define MAVLINK_V1_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define MAVLINK_V1_FRAME_OVERHEAD (MAVLINK_V1_FRAME_HEADER_SIZE + MAVLINK_V1_FRAME_FOOTER_SIZE) - -/* MavlinkV1Frame parser states */ -typedef enum mavlink_v1_frame_parser_state { - MAVLINK_V1_FRAME_LOOKING_FOR_START = 0, - MAVLINK_V1_FRAME_GETTING_MSG_ID = 1, - MAVLINK_V1_FRAME_GETTING_LENGTH = 2, - MAVLINK_V1_FRAME_GETTING_PAYLOAD = 3 -} mavlink_v1_frame_parser_state_t; - -/* MavlinkV1Frame parser state structure */ -typedef struct mavlink_v1_frame_parser { - mavlink_v1_frame_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} mavlink_v1_frame_parser_t; - -/* MavlinkV1Frame encode buffer structure */ -typedef struct mavlink_v1_frame_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} mavlink_v1_frame_encode_buffer_t; - -/** - * Initialize a MavlinkV1Frame parser - */ -static inline void mavlink_v1_frame_parser_init(mavlink_v1_frame_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MavlinkV1Frame parser state - */ -static inline void mavlink_v1_frame_parser_reset(mavlink_v1_frame_parser_t* parser) { - parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with MavlinkV1Frame format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t mavlink_v1_frame_parse_byte(mavlink_v1_frame_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MAVLINK_V1_FRAME_LOOKING_FOR_START: - if (byte == MAVLINK_V1_FRAME_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = MAVLINK_V1_FRAME_GETTING_MSG_ID; - } - break; - - case MAVLINK_V1_FRAME_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = MAVLINK_V1_FRAME_GETTING_LENGTH; - break; - - case MAVLINK_V1_FRAME_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = MAVLINK_V1_FRAME_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MAVLINK_V1_FRAME_GETTING_PAYLOAD; - } else { - parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; - } - break; - - case MAVLINK_V1_FRAME_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - MAVLINK_V1_FRAME_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 1, msg_length + 1 + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + MAVLINK_V1_FRAME_HEADER_SIZE; - } - parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with MavlinkV1Frame format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t mavlink_v1_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MAVLINK_V1_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = MAVLINK_V1_FRAME_START_BYTE; - buffer[1] = msg_id; - buffer[2] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MAVLINK_V1_FRAME_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 1); - buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MavlinkV1Frame packet in a buffer - */ -static inline frame_msg_info_t mavlink_v1_frame_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MAVLINK_V1_FRAME_OVERHEAD) { - return result; - } - - if (buffer[0] != MAVLINK_V1_FRAME_START_BYTE) { - return result; - } - - size_t msg_length = length - MAVLINK_V1_FRAME_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MAVLINK_V1_FRAME_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * MavlinkV2Frame Frame Format - *===========================================================================*/ - -/* MavlinkV2Frame constants */ -#define MAVLINK_V2_FRAME_START_BYTE 0xFD -#define MAVLINK_V2_FRAME_HEADER_SIZE 5 /* stx + msg_id + length(1) */ -#define MAVLINK_V2_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ -#define MAVLINK_V2_FRAME_OVERHEAD (MAVLINK_V2_FRAME_HEADER_SIZE + MAVLINK_V2_FRAME_FOOTER_SIZE) - -/* MavlinkV2Frame parser states */ -typedef enum mavlink_v2_frame_parser_state { - MAVLINK_V2_FRAME_LOOKING_FOR_START = 0, - MAVLINK_V2_FRAME_GETTING_MSG_ID = 1, - MAVLINK_V2_FRAME_GETTING_LENGTH = 2, - MAVLINK_V2_FRAME_GETTING_PAYLOAD = 3 -} mavlink_v2_frame_parser_state_t; - -/* MavlinkV2Frame parser state structure */ -typedef struct mavlink_v2_frame_parser { - mavlink_v2_frame_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - size_t msg_length; /* From length field */ - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} mavlink_v2_frame_parser_t; - -/* MavlinkV2Frame encode buffer structure */ -typedef struct mavlink_v2_frame_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} mavlink_v2_frame_encode_buffer_t; - -/** - * Initialize a MavlinkV2Frame parser - */ -static inline void mavlink_v2_frame_parser_init(mavlink_v2_frame_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset MavlinkV2Frame parser state - */ -static inline void mavlink_v2_frame_parser_reset(mavlink_v2_frame_parser_t* parser) { - parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->msg_length = 0; -} - -/** - * Parse a single byte with MavlinkV2Frame format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t mavlink_v2_frame_parse_byte(mavlink_v2_frame_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case MAVLINK_V2_FRAME_LOOKING_FOR_START: - if (byte == MAVLINK_V2_FRAME_START_BYTE) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = MAVLINK_V2_FRAME_GETTING_MSG_ID; - } - break; - - case MAVLINK_V2_FRAME_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - parser->state = MAVLINK_V2_FRAME_GETTING_LENGTH; - break; - - case MAVLINK_V2_FRAME_GETTING_LENGTH: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_length = byte; - parser->packet_size = MAVLINK_V2_FRAME_OVERHEAD + parser->msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = MAVLINK_V2_FRAME_GETTING_PAYLOAD; - } else { - parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; - } - break; - - case MAVLINK_V2_FRAME_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - MAVLINK_V2_FRAME_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 1, msg_length + 1 + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + MAVLINK_V2_FRAME_HEADER_SIZE; - } - parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; - } - break; - } - - return result; -} - -/** - * Encode a message with MavlinkV2Frame format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t mavlink_v2_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MAVLINK_V2_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = MAVLINK_V2_FRAME_START_BYTE; - buffer[1] = msg_id; - buffer[2] = (uint8_t)msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + MAVLINK_V2_FRAME_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 1); - buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MavlinkV2Frame packet in a buffer - */ -static inline frame_msg_info_t mavlink_v2_frame_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < MAVLINK_V2_FRAME_OVERHEAD) { - return result; - } - - if (buffer[0] != MAVLINK_V2_FRAME_START_BYTE) { - return result; - } - - size_t msg_length = length - MAVLINK_V2_FRAME_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + MAVLINK_V2_FRAME_HEADER_SIZE); - } - - return result; -} - - -/*=========================================================================== - * FrameFormatConfig Frame Format - *===========================================================================*/ - -/* FrameFormatConfig constants */ -#define FRAME_FORMAT_CONFIG_START_BYTE1 0x90 -#define FRAME_FORMAT_CONFIG_START_BYTE2 0x91 -#define FRAME_FORMAT_CONFIG_HEADER_SIZE 2 /* start_byte1 + start_byte2 + msg_id */ -#define FRAME_FORMAT_CONFIG_FOOTER_SIZE 1 /* crc(1 bytes) */ -#define FRAME_FORMAT_CONFIG_OVERHEAD (FRAME_FORMAT_CONFIG_HEADER_SIZE + FRAME_FORMAT_CONFIG_FOOTER_SIZE) - -/* FrameFormatConfig parser states */ -typedef enum frame_format_config_parser_state { - FRAME_FORMAT_CONFIG_LOOKING_FOR_START1 = 0, - FRAME_FORMAT_CONFIG_LOOKING_FOR_START2 = 1, - FRAME_FORMAT_CONFIG_GETTING_MSG_ID = 2, - FRAME_FORMAT_CONFIG_GETTING_PAYLOAD = 3 -} frame_format_config_parser_state_t; - -/* FrameFormatConfig parser state structure */ -typedef struct frame_format_config_parser { - frame_format_config_parser_state_t state; - uint8_t* buffer; - size_t buffer_max_size; - size_t buffer_index; - size_t packet_size; - uint8_t msg_id; - /* User-provided function to get message length from msg_id (for non-length frames) */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} frame_format_config_parser_t; - -/* FrameFormatConfig encode buffer structure */ -typedef struct frame_format_config_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - size_t reserved_msg_size; -} frame_format_config_encode_buffer_t; - -/** - * Initialize a FrameFormatConfig parser - */ -static inline void frame_format_config_parser_init(frame_format_config_parser_t* parser, - uint8_t* buffer, size_t buffer_size, - bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; - parser->buffer = buffer; - parser->buffer_max_size = buffer_size; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; - parser->get_msg_length = get_msg_length; -} - -/** - * Reset FrameFormatConfig parser state - */ -static inline void frame_format_config_parser_reset(frame_format_config_parser_t* parser) { - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; - parser->buffer_index = 0; - parser->packet_size = 0; - parser->msg_id = 0; -} - -/** - * Parse a single byte with FrameFormatConfig format - * Returns frame_msg_info_t with valid=true when a complete valid message is received - */ -static inline frame_msg_info_t frame_format_config_parse_byte(frame_format_config_parser_t* parser, uint8_t byte) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - switch (parser->state) { - case FRAME_FORMAT_CONFIG_LOOKING_FOR_START1: - if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START2; - } - break; - - case FRAME_FORMAT_CONFIG_LOOKING_FOR_START2: - if (byte == FRAME_FORMAT_CONFIG_START_BYTE2) { - parser->buffer[1] = byte; - parser->buffer_index = 2; - parser->state = FRAME_FORMAT_CONFIG_GETTING_MSG_ID; - } else if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { - parser->buffer[0] = byte; - parser->buffer_index = 1; - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START2; - } else { - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; - } - break; - - case FRAME_FORMAT_CONFIG_GETTING_MSG_ID: - parser->buffer[parser->buffer_index++] = byte; - parser->msg_id = byte; - { - size_t msg_length = 0; - if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { - parser->packet_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_length; - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = FRAME_FORMAT_CONFIG_GETTING_PAYLOAD; - } else { - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; - } - } else { - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; - } - } - break; - - case FRAME_FORMAT_CONFIG_GETTING_PAYLOAD: - if (parser->buffer_index < parser->buffer_max_size) { - parser->buffer[parser->buffer_index++] = byte; - } - - if (parser->buffer_index >= parser->packet_size) { - /* Validate checksum */ - size_t msg_length = parser->packet_size - FRAME_FORMAT_CONFIG_OVERHEAD; - frame_checksum_t ck = frame_fletcher_checksum( - parser->buffer + 2, msg_length + 1); - - if (ck.byte1 == parser->buffer[parser->packet_size - 2] && - ck.byte2 == parser->buffer[parser->packet_size - 1]) { - result.valid = true; - result.msg_id = parser->msg_id; - result.msg_len = msg_length; - result.msg_data = parser->buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE; - } - parser->state = FRAME_FORMAT_CONFIG_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Encode a message with FrameFormatConfig format - * Returns the number of bytes written, or 0 on failure - */ -static inline size_t frame_format_config_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - buffer[0] = FRAME_FORMAT_CONFIG_START_BYTE1; - buffer[1] = FRAME_FORMAT_CONFIG_START_BYTE2; - buffer[2] = msg_id; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1); - buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size] = ck.byte1; - buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete FrameFormatConfig packet in a buffer - */ -static inline frame_msg_info_t frame_format_config_validate_packet(const uint8_t* buffer, size_t length) { - frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < FRAME_FORMAT_CONFIG_OVERHEAD) { - return result; - } - - if (buffer[0] != FRAME_FORMAT_CONFIG_START_BYTE1) { - return result; - } - if (buffer[1] != FRAME_FORMAT_CONFIG_START_BYTE2) { - return result; - } - - size_t msg_length = length - FRAME_FORMAT_CONFIG_OVERHEAD; - - /* Validate checksum */ - frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = (uint8_t*)(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE); - } - - return result; -} - - diff --git a/src/struct_frame/boilerplate/c/mavlink_v1_frame.h b/src/struct_frame/boilerplate/c/mavlink_v1_frame.h new file mode 100644 index 00000000..a359ae8b --- /dev/null +++ b/src/struct_frame/boilerplate/c/mavlink_v1_frame.h @@ -0,0 +1,189 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MavlinkV1Frame Frame Format + *===========================================================================*/ + +/* MavlinkV1Frame constants */ +#define MAVLINK_V1_FRAME_START_BYTE 0xFE +#define MAVLINK_V1_FRAME_HEADER_SIZE 3 /* stx + msg_id + length(1) */ +#define MAVLINK_V1_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define MAVLINK_V1_FRAME_OVERHEAD (MAVLINK_V1_FRAME_HEADER_SIZE + MAVLINK_V1_FRAME_FOOTER_SIZE) + +/* MavlinkV1Frame parser states */ +typedef enum mavlink_v1_frame_parser_state { + MAVLINK_V1_FRAME_LOOKING_FOR_START = 0, + MAVLINK_V1_FRAME_GETTING_MSG_ID = 1, + MAVLINK_V1_FRAME_GETTING_LENGTH = 2, + MAVLINK_V1_FRAME_GETTING_PAYLOAD = 3 +} mavlink_v1_frame_parser_state_t; + +/* MavlinkV1Frame parser state structure */ +typedef struct mavlink_v1_frame_parser { + mavlink_v1_frame_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} mavlink_v1_frame_parser_t; + +/* MavlinkV1Frame encode buffer structure */ +typedef struct mavlink_v1_frame_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} mavlink_v1_frame_encode_buffer_t; + +/** + * Initialize a MavlinkV1Frame parser + */ +static inline void mavlink_v1_frame_parser_init(mavlink_v1_frame_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MavlinkV1Frame parser state + */ +static inline void mavlink_v1_frame_parser_reset(mavlink_v1_frame_parser_t* parser) { + parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with MavlinkV1Frame format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t mavlink_v1_frame_parse_byte(mavlink_v1_frame_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MAVLINK_V1_FRAME_LOOKING_FOR_START: + if (byte == MAVLINK_V1_FRAME_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = MAVLINK_V1_FRAME_GETTING_MSG_ID; + } + break; + + case MAVLINK_V1_FRAME_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = MAVLINK_V1_FRAME_GETTING_LENGTH; + break; + + case MAVLINK_V1_FRAME_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = MAVLINK_V1_FRAME_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MAVLINK_V1_FRAME_GETTING_PAYLOAD; + } else { + parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; + } + break; + + case MAVLINK_V1_FRAME_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - MAVLINK_V1_FRAME_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 1, msg_length + 1 + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + MAVLINK_V1_FRAME_HEADER_SIZE; + } + parser->state = MAVLINK_V1_FRAME_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with MavlinkV1Frame format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t mavlink_v1_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MAVLINK_V1_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = MAVLINK_V1_FRAME_START_BYTE; + buffer[1] = msg_id; + buffer[2] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MAVLINK_V1_FRAME_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 1); + buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MavlinkV1Frame packet in a buffer + */ +static inline frame_msg_info_t mavlink_v1_frame_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MAVLINK_V1_FRAME_OVERHEAD) { + return result; + } + + if (buffer[0] != MAVLINK_V1_FRAME_START_BYTE) { + return result; + } + + size_t msg_length = length - MAVLINK_V1_FRAME_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MAVLINK_V1_FRAME_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/mavlink_v2_frame.h b/src/struct_frame/boilerplate/c/mavlink_v2_frame.h new file mode 100644 index 00000000..73c05c03 --- /dev/null +++ b/src/struct_frame/boilerplate/c/mavlink_v2_frame.h @@ -0,0 +1,189 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MavlinkV2Frame Frame Format + *===========================================================================*/ + +/* MavlinkV2Frame constants */ +#define MAVLINK_V2_FRAME_START_BYTE 0xFD +#define MAVLINK_V2_FRAME_HEADER_SIZE 5 /* stx + msg_id + length(1) */ +#define MAVLINK_V2_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define MAVLINK_V2_FRAME_OVERHEAD (MAVLINK_V2_FRAME_HEADER_SIZE + MAVLINK_V2_FRAME_FOOTER_SIZE) + +/* MavlinkV2Frame parser states */ +typedef enum mavlink_v2_frame_parser_state { + MAVLINK_V2_FRAME_LOOKING_FOR_START = 0, + MAVLINK_V2_FRAME_GETTING_MSG_ID = 1, + MAVLINK_V2_FRAME_GETTING_LENGTH = 2, + MAVLINK_V2_FRAME_GETTING_PAYLOAD = 3 +} mavlink_v2_frame_parser_state_t; + +/* MavlinkV2Frame parser state structure */ +typedef struct mavlink_v2_frame_parser { + mavlink_v2_frame_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} mavlink_v2_frame_parser_t; + +/* MavlinkV2Frame encode buffer structure */ +typedef struct mavlink_v2_frame_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} mavlink_v2_frame_encode_buffer_t; + +/** + * Initialize a MavlinkV2Frame parser + */ +static inline void mavlink_v2_frame_parser_init(mavlink_v2_frame_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MavlinkV2Frame parser state + */ +static inline void mavlink_v2_frame_parser_reset(mavlink_v2_frame_parser_t* parser) { + parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with MavlinkV2Frame format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t mavlink_v2_frame_parse_byte(mavlink_v2_frame_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MAVLINK_V2_FRAME_LOOKING_FOR_START: + if (byte == MAVLINK_V2_FRAME_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = MAVLINK_V2_FRAME_GETTING_MSG_ID; + } + break; + + case MAVLINK_V2_FRAME_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = MAVLINK_V2_FRAME_GETTING_LENGTH; + break; + + case MAVLINK_V2_FRAME_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = MAVLINK_V2_FRAME_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MAVLINK_V2_FRAME_GETTING_PAYLOAD; + } else { + parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; + } + break; + + case MAVLINK_V2_FRAME_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - MAVLINK_V2_FRAME_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 1, msg_length + 1 + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + MAVLINK_V2_FRAME_HEADER_SIZE; + } + parser->state = MAVLINK_V2_FRAME_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with MavlinkV2Frame format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t mavlink_v2_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MAVLINK_V2_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = MAVLINK_V2_FRAME_START_BYTE; + buffer[1] = msg_id; + buffer[2] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MAVLINK_V2_FRAME_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 1); + buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MavlinkV2Frame packet in a buffer + */ +static inline frame_msg_info_t mavlink_v2_frame_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MAVLINK_V2_FRAME_OVERHEAD) { + return result; + } + + if (buffer[0] != MAVLINK_V2_FRAME_START_BYTE) { + return result; + } + + size_t msg_length = length - MAVLINK_V2_FRAME_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MAVLINK_V2_FRAME_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/minimal_frame.h b/src/struct_frame/boilerplate/c/minimal_frame.h new file mode 100644 index 00000000..1e827448 --- /dev/null +++ b/src/struct_frame/boilerplate/c/minimal_frame.h @@ -0,0 +1,171 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MinimalFrame Frame Format + *===========================================================================*/ + +/* MinimalFrame constants */ +#define MINIMAL_FRAME_HEADER_SIZE 1 /* msg_id */ +#define MINIMAL_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define MINIMAL_FRAME_OVERHEAD (MINIMAL_FRAME_HEADER_SIZE + MINIMAL_FRAME_FOOTER_SIZE) + +/* MinimalFrame parser states */ +typedef enum minimal_frame_parser_state { + MINIMAL_FRAME_GETTING_MSG_ID = 0, + MINIMAL_FRAME_GETTING_PAYLOAD = 1 +} minimal_frame_parser_state_t; + +/* MinimalFrame parser state structure */ +typedef struct minimal_frame_parser { + minimal_frame_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} minimal_frame_parser_t; + +/* MinimalFrame encode buffer structure */ +typedef struct minimal_frame_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} minimal_frame_encode_buffer_t; + +/** + * Initialize a MinimalFrame parser + */ +static inline void minimal_frame_parser_init(minimal_frame_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MINIMAL_FRAME_GETTING_MSG_ID; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MinimalFrame parser state + */ +static inline void minimal_frame_parser_reset(minimal_frame_parser_t* parser) { + parser->state = MINIMAL_FRAME_GETTING_MSG_ID; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with MinimalFrame format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t minimal_frame_parse_byte(minimal_frame_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MINIMAL_FRAME_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = MINIMAL_FRAME_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MINIMAL_FRAME_GETTING_PAYLOAD; + } else { + parser->state = MINIMAL_FRAME_GETTING_MSG_ID; + } + } else { + parser->state = MINIMAL_FRAME_GETTING_MSG_ID; + } + } + break; + + case MINIMAL_FRAME_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - MINIMAL_FRAME_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 0, msg_length + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + MINIMAL_FRAME_HEADER_SIZE; + } + parser->state = MINIMAL_FRAME_GETTING_MSG_ID; + } + break; + } + + return result; +} + +/** + * Encode a message with MinimalFrame format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t minimal_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MINIMAL_FRAME_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_size + 1); + buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MinimalFrame packet in a buffer + */ +static inline frame_msg_info_t minimal_frame_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MINIMAL_FRAME_OVERHEAD) { + return result; + } + + + size_t msg_length = length - MINIMAL_FRAME_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/minimal_frame_with_len.h b/src/struct_frame/boilerplate/c/minimal_frame_with_len.h new file mode 100644 index 00000000..189105ac --- /dev/null +++ b/src/struct_frame/boilerplate/c/minimal_frame_with_len.h @@ -0,0 +1,175 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MinimalFrameWithLen Frame Format + *===========================================================================*/ + +/* MinimalFrameWithLen constants */ +#define MINIMAL_FRAME_WITH_LEN_HEADER_SIZE 2 /* msg_id + length(1) */ +#define MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define MINIMAL_FRAME_WITH_LEN_OVERHEAD (MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE) + +/* MinimalFrameWithLen parser states */ +typedef enum minimal_frame_with_len_parser_state { + MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID = 0, + MINIMAL_FRAME_WITH_LEN_GETTING_LENGTH = 1, + MINIMAL_FRAME_WITH_LEN_GETTING_PAYLOAD = 2 +} minimal_frame_with_len_parser_state_t; + +/* MinimalFrameWithLen parser state structure */ +typedef struct minimal_frame_with_len_parser { + minimal_frame_with_len_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} minimal_frame_with_len_parser_t; + +/* MinimalFrameWithLen encode buffer structure */ +typedef struct minimal_frame_with_len_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} minimal_frame_with_len_encode_buffer_t; + +/** + * Initialize a MinimalFrameWithLen parser + */ +static inline void minimal_frame_with_len_parser_init(minimal_frame_with_len_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MinimalFrameWithLen parser state + */ +static inline void minimal_frame_with_len_parser_reset(minimal_frame_with_len_parser_t* parser) { + parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with MinimalFrameWithLen format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t minimal_frame_with_len_parse_byte(minimal_frame_with_len_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_LENGTH; + break; + + case MINIMAL_FRAME_WITH_LEN_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_PAYLOAD; + } else { + parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; + } + break; + + case MINIMAL_FRAME_WITH_LEN_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - MINIMAL_FRAME_WITH_LEN_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 0, msg_length + 1 + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE; + } + parser->state = MINIMAL_FRAME_WITH_LEN_GETTING_MSG_ID; + } + break; + } + + return result; +} + +/** + * Encode a message with MinimalFrameWithLen format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t minimal_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = msg_id; + buffer[1] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_size + 1 + 1); + buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLen packet in a buffer + */ +static inline frame_msg_info_t minimal_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MINIMAL_FRAME_WITH_LEN_OVERHEAD) { + return result; + } + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/minimal_frame_with_len16.h b/src/struct_frame/boilerplate/c/minimal_frame_with_len16.h new file mode 100644 index 00000000..f2fffe72 --- /dev/null +++ b/src/struct_frame/boilerplate/c/minimal_frame_with_len16.h @@ -0,0 +1,182 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MinimalFrameWithLen16 Frame Format + *===========================================================================*/ + +/* MinimalFrameWithLen16 constants */ +#define MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE 3 /* msg_id + length(2) */ +#define MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define MINIMAL_FRAME_WITH_LEN16_OVERHEAD (MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE) + +/* MinimalFrameWithLen16 parser states */ +typedef enum minimal_frame_with_len16_parser_state { + MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID = 0, + MINIMAL_FRAME_WITH_LEN16_GETTING_LENGTH = 1, + MINIMAL_FRAME_WITH_LEN16_GETTING_PAYLOAD = 2 +} minimal_frame_with_len16_parser_state_t; + +/* MinimalFrameWithLen16 parser state structure */ +typedef struct minimal_frame_with_len16_parser { + minimal_frame_with_len16_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + uint8_t length_lo; /* Low byte for 16-bit length */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} minimal_frame_with_len16_parser_t; + +/* MinimalFrameWithLen16 encode buffer structure */ +typedef struct minimal_frame_with_len16_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} minimal_frame_with_len16_encode_buffer_t; + +/** + * Initialize a MinimalFrameWithLen16 parser + */ +static inline void minimal_frame_with_len16_parser_init(minimal_frame_with_len16_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->length_lo = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MinimalFrameWithLen16 parser state + */ +static inline void minimal_frame_with_len16_parser_reset(minimal_frame_with_len16_parser_t* parser) { + parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with MinimalFrameWithLen16 format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t minimal_frame_with_len16_parse_byte(minimal_frame_with_len16_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_LENGTH; + break; + + case MINIMAL_FRAME_WITH_LEN16_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + if (parser->buffer_index == 2) { + parser->length_lo = byte; + } else { + parser->msg_length = parser->length_lo | ((size_t)byte << 8); + parser->packet_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_PAYLOAD; + } else { + parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; + } + } + break; + + case MINIMAL_FRAME_WITH_LEN16_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 0, msg_length + 1 + 2); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE; + } + parser->state = MINIMAL_FRAME_WITH_LEN16_GETTING_MSG_ID; + } + break; + } + + return result; +} + +/** + * Encode a message with MinimalFrameWithLen16 format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t minimal_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = msg_id; + buffer[1] = (uint8_t)(msg_size & 0xFF); + buffer[2] = (uint8_t)((msg_size >> 8) & 0xFF); + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_size + 1 + 2); + buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLen16 packet in a buffer + */ +static inline frame_msg_info_t minimal_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MINIMAL_FRAME_WITH_LEN16_OVERHEAD) { + return result; + } + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 0, msg_length + 1 + 2); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/minimal_frame_with_len16_no_crc.h b/src/struct_frame/boilerplate/c/minimal_frame_with_len16_no_crc.h new file mode 100644 index 00000000..6ddcdaa8 --- /dev/null +++ b/src/struct_frame/boilerplate/c/minimal_frame_with_len16_no_crc.h @@ -0,0 +1,166 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MinimalFrameWithLen16NoCrc Frame Format + *===========================================================================*/ + +/* MinimalFrameWithLen16NoCrc constants */ +#define MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE 3 /* msg_id + length(2) */ +#define MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD (MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE) + +/* MinimalFrameWithLen16NoCrc parser states */ +typedef enum minimal_frame_with_len16_no_crc_parser_state { + MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID = 0, + MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH = 1, + MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD = 2 +} minimal_frame_with_len16_no_crc_parser_state_t; + +/* MinimalFrameWithLen16NoCrc parser state structure */ +typedef struct minimal_frame_with_len16_no_crc_parser { + minimal_frame_with_len16_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + uint8_t length_lo; /* Low byte for 16-bit length */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} minimal_frame_with_len16_no_crc_parser_t; + +/* MinimalFrameWithLen16NoCrc encode buffer structure */ +typedef struct minimal_frame_with_len16_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} minimal_frame_with_len16_no_crc_encode_buffer_t; + +/** + * Initialize a MinimalFrameWithLen16NoCrc parser + */ +static inline void minimal_frame_with_len16_no_crc_parser_init(minimal_frame_with_len16_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->length_lo = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MinimalFrameWithLen16NoCrc parser state + */ +static inline void minimal_frame_with_len16_no_crc_parser_reset(minimal_frame_with_len16_no_crc_parser_t* parser) { + parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with MinimalFrameWithLen16NoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t minimal_frame_with_len16_no_crc_parse_byte(minimal_frame_with_len16_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH; + break; + + case MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + if (parser->buffer_index == 2) { + parser->length_lo = byte; + } else { + parser->msg_length = parser->length_lo | ((size_t)byte << 8); + parser->packet_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; + } + } + break; + + case MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; + parser->state = MINIMAL_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; + } + break; + } + + return result; +} + +/** + * Encode a message with MinimalFrameWithLen16NoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t minimal_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = msg_id; + buffer[1] = (uint8_t)(msg_size & 0xFF); + buffer[2] = (uint8_t)((msg_size >> 8) & 0xFF); + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer + */ +static inline frame_msg_info_t minimal_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) { + return result; + } + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/minimal_frame_with_len_no_crc.h b/src/struct_frame/boilerplate/c/minimal_frame_with_len_no_crc.h new file mode 100644 index 00000000..970420c9 --- /dev/null +++ b/src/struct_frame/boilerplate/c/minimal_frame_with_len_no_crc.h @@ -0,0 +1,159 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * MinimalFrameWithLenNoCrc Frame Format + *===========================================================================*/ + +/* MinimalFrameWithLenNoCrc constants */ +#define MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE 2 /* msg_id + length(1) */ +#define MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD (MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE) + +/* MinimalFrameWithLenNoCrc parser states */ +typedef enum minimal_frame_with_len_no_crc_parser_state { + MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID = 0, + MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH = 1, + MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD = 2 +} minimal_frame_with_len_no_crc_parser_state_t; + +/* MinimalFrameWithLenNoCrc parser state structure */ +typedef struct minimal_frame_with_len_no_crc_parser { + minimal_frame_with_len_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} minimal_frame_with_len_no_crc_parser_t; + +/* MinimalFrameWithLenNoCrc encode buffer structure */ +typedef struct minimal_frame_with_len_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} minimal_frame_with_len_no_crc_encode_buffer_t; + +/** + * Initialize a MinimalFrameWithLenNoCrc parser + */ +static inline void minimal_frame_with_len_no_crc_parser_init(minimal_frame_with_len_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset MinimalFrameWithLenNoCrc parser state + */ +static inline void minimal_frame_with_len_no_crc_parser_reset(minimal_frame_with_len_no_crc_parser_t* parser) { + parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with MinimalFrameWithLenNoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t minimal_frame_with_len_no_crc_parse_byte(minimal_frame_with_len_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH; + break; + + case MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; + } + break; + + case MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; + parser->state = MINIMAL_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; + } + break; + } + + return result; +} + +/** + * Encode a message with MinimalFrameWithLenNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t minimal_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = msg_id; + buffer[1] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLenNoCrc packet in a buffer + */ +static inline frame_msg_info_t minimal_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD) { + return result; + } + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/tiny_frame.h b/src/struct_frame/boilerplate/c/tiny_frame.h new file mode 100644 index 00000000..6963f65a --- /dev/null +++ b/src/struct_frame/boilerplate/c/tiny_frame.h @@ -0,0 +1,185 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * TinyFrame Frame Format + *===========================================================================*/ + +/* TinyFrame constants */ +#define TINY_FRAME_START_BYTE 0x70 +#define TINY_FRAME_HEADER_SIZE 2 /* start_byte + msg_id */ +#define TINY_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define TINY_FRAME_OVERHEAD (TINY_FRAME_HEADER_SIZE + TINY_FRAME_FOOTER_SIZE) + +/* TinyFrame parser states */ +typedef enum tiny_frame_parser_state { + TINY_FRAME_LOOKING_FOR_START = 0, + TINY_FRAME_GETTING_MSG_ID = 1, + TINY_FRAME_GETTING_PAYLOAD = 2 +} tiny_frame_parser_state_t; + +/* TinyFrame parser state structure */ +typedef struct tiny_frame_parser { + tiny_frame_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} tiny_frame_parser_t; + +/* TinyFrame encode buffer structure */ +typedef struct tiny_frame_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} tiny_frame_encode_buffer_t; + +/** + * Initialize a TinyFrame parser + */ +static inline void tiny_frame_parser_init(tiny_frame_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = TINY_FRAME_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset TinyFrame parser state + */ +static inline void tiny_frame_parser_reset(tiny_frame_parser_t* parser) { + parser->state = TINY_FRAME_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with TinyFrame format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t tiny_frame_parse_byte(tiny_frame_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case TINY_FRAME_LOOKING_FOR_START: + if (byte == TINY_FRAME_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = TINY_FRAME_GETTING_MSG_ID; + } + break; + + case TINY_FRAME_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = TINY_FRAME_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = TINY_FRAME_GETTING_PAYLOAD; + } else { + parser->state = TINY_FRAME_LOOKING_FOR_START; + } + } else { + parser->state = TINY_FRAME_LOOKING_FOR_START; + } + } + break; + + case TINY_FRAME_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - TINY_FRAME_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 1, msg_length + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + TINY_FRAME_HEADER_SIZE; + } + parser->state = TINY_FRAME_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with TinyFrame format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t tiny_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = TINY_FRAME_START_BYTE; + buffer[1] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + TINY_FRAME_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1); + buffer[TINY_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[TINY_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete TinyFrame packet in a buffer + */ +static inline frame_msg_info_t tiny_frame_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < TINY_FRAME_OVERHEAD) { + return result; + } + + if (buffer[0] != TINY_FRAME_START_BYTE) { + return result; + } + + size_t msg_length = length - TINY_FRAME_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + TINY_FRAME_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/tiny_frame_no_crc.h b/src/struct_frame/boilerplate/c/tiny_frame_no_crc.h new file mode 100644 index 00000000..bc6e2711 --- /dev/null +++ b/src/struct_frame/boilerplate/c/tiny_frame_no_crc.h @@ -0,0 +1,169 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * TinyFrameNoCrc Frame Format + *===========================================================================*/ + +/* TinyFrameNoCrc constants */ +#define TINY_FRAME_NO_CRC_START_BYTE 0x72 +#define TINY_FRAME_NO_CRC_HEADER_SIZE 2 /* start_byte + msg_id */ +#define TINY_FRAME_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define TINY_FRAME_NO_CRC_OVERHEAD (TINY_FRAME_NO_CRC_HEADER_SIZE + TINY_FRAME_NO_CRC_FOOTER_SIZE) + +/* TinyFrameNoCrc parser states */ +typedef enum tiny_frame_no_crc_parser_state { + TINY_FRAME_NO_CRC_LOOKING_FOR_START = 0, + TINY_FRAME_NO_CRC_GETTING_MSG_ID = 1, + TINY_FRAME_NO_CRC_GETTING_PAYLOAD = 2 +} tiny_frame_no_crc_parser_state_t; + +/* TinyFrameNoCrc parser state structure */ +typedef struct tiny_frame_no_crc_parser { + tiny_frame_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} tiny_frame_no_crc_parser_t; + +/* TinyFrameNoCrc encode buffer structure */ +typedef struct tiny_frame_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} tiny_frame_no_crc_encode_buffer_t; + +/** + * Initialize a TinyFrameNoCrc parser + */ +static inline void tiny_frame_no_crc_parser_init(tiny_frame_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset TinyFrameNoCrc parser state + */ +static inline void tiny_frame_no_crc_parser_reset(tiny_frame_no_crc_parser_t* parser) { + parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; +} + +/** + * Parse a single byte with TinyFrameNoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t tiny_frame_no_crc_parse_byte(tiny_frame_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case TINY_FRAME_NO_CRC_LOOKING_FOR_START: + if (byte == TINY_FRAME_NO_CRC_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = TINY_FRAME_NO_CRC_GETTING_MSG_ID; + } + break; + + case TINY_FRAME_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + { + size_t msg_length = 0; + if (parser->get_msg_length && parser->get_msg_length(byte, &msg_length)) { + parser->packet_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = TINY_FRAME_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; + } + } else { + parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; + } + } + break; + + case TINY_FRAME_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - TINY_FRAME_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + TINY_FRAME_NO_CRC_HEADER_SIZE; + parser->state = TINY_FRAME_NO_CRC_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with TinyFrameNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t tiny_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = TINY_FRAME_NO_CRC_START_BYTE; + buffer[1] = msg_id; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete TinyFrameNoCrc packet in a buffer + */ +static inline frame_msg_info_t tiny_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < TINY_FRAME_NO_CRC_OVERHEAD) { + return result; + } + + if (buffer[0] != TINY_FRAME_NO_CRC_START_BYTE) { + return result; + } + + size_t msg_length = length - TINY_FRAME_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/tiny_frame_with_len.h b/src/struct_frame/boilerplate/c/tiny_frame_with_len.h new file mode 100644 index 00000000..046de60a --- /dev/null +++ b/src/struct_frame/boilerplate/c/tiny_frame_with_len.h @@ -0,0 +1,189 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * TinyFrameWithLen Frame Format + *===========================================================================*/ + +/* TinyFrameWithLen constants */ +#define TINY_FRAME_WITH_LEN_START_BYTE 0x71 +#define TINY_FRAME_WITH_LEN_HEADER_SIZE 3 /* start_byte + msg_id + length(1) */ +#define TINY_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define TINY_FRAME_WITH_LEN_OVERHEAD (TINY_FRAME_WITH_LEN_HEADER_SIZE + TINY_FRAME_WITH_LEN_FOOTER_SIZE) + +/* TinyFrameWithLen parser states */ +typedef enum tiny_frame_with_len_parser_state { + TINY_FRAME_WITH_LEN_LOOKING_FOR_START = 0, + TINY_FRAME_WITH_LEN_GETTING_MSG_ID = 1, + TINY_FRAME_WITH_LEN_GETTING_LENGTH = 2, + TINY_FRAME_WITH_LEN_GETTING_PAYLOAD = 3 +} tiny_frame_with_len_parser_state_t; + +/* TinyFrameWithLen parser state structure */ +typedef struct tiny_frame_with_len_parser { + tiny_frame_with_len_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} tiny_frame_with_len_parser_t; + +/* TinyFrameWithLen encode buffer structure */ +typedef struct tiny_frame_with_len_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} tiny_frame_with_len_encode_buffer_t; + +/** + * Initialize a TinyFrameWithLen parser + */ +static inline void tiny_frame_with_len_parser_init(tiny_frame_with_len_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset TinyFrameWithLen parser state + */ +static inline void tiny_frame_with_len_parser_reset(tiny_frame_with_len_parser_t* parser) { + parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with TinyFrameWithLen format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t tiny_frame_with_len_parse_byte(tiny_frame_with_len_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case TINY_FRAME_WITH_LEN_LOOKING_FOR_START: + if (byte == TINY_FRAME_WITH_LEN_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = TINY_FRAME_WITH_LEN_GETTING_MSG_ID; + } + break; + + case TINY_FRAME_WITH_LEN_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = TINY_FRAME_WITH_LEN_GETTING_LENGTH; + break; + + case TINY_FRAME_WITH_LEN_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = TINY_FRAME_WITH_LEN_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = TINY_FRAME_WITH_LEN_GETTING_PAYLOAD; + } else { + parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; + } + break; + + case TINY_FRAME_WITH_LEN_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - TINY_FRAME_WITH_LEN_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 1, msg_length + 1 + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE; + } + parser->state = TINY_FRAME_WITH_LEN_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with TinyFrameWithLen format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t tiny_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = TINY_FRAME_WITH_LEN_START_BYTE; + buffer[1] = msg_id; + buffer[2] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 1); + buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLen packet in a buffer + */ +static inline frame_msg_info_t tiny_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < TINY_FRAME_WITH_LEN_OVERHEAD) { + return result; + } + + if (buffer[0] != TINY_FRAME_WITH_LEN_START_BYTE) { + return result; + } + + size_t msg_length = length - TINY_FRAME_WITH_LEN_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/tiny_frame_with_len16.h b/src/struct_frame/boilerplate/c/tiny_frame_with_len16.h new file mode 100644 index 00000000..9b8335df --- /dev/null +++ b/src/struct_frame/boilerplate/c/tiny_frame_with_len16.h @@ -0,0 +1,196 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * TinyFrameWithLen16 Frame Format + *===========================================================================*/ + +/* TinyFrameWithLen16 constants */ +#define TINY_FRAME_WITH_LEN16_START_BYTE 0x74 +#define TINY_FRAME_WITH_LEN16_HEADER_SIZE 4 /* start_byte + msg_id + length(2) */ +#define TINY_FRAME_WITH_LEN16_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define TINY_FRAME_WITH_LEN16_OVERHEAD (TINY_FRAME_WITH_LEN16_HEADER_SIZE + TINY_FRAME_WITH_LEN16_FOOTER_SIZE) + +/* TinyFrameWithLen16 parser states */ +typedef enum tiny_frame_with_len16_parser_state { + TINY_FRAME_WITH_LEN16_LOOKING_FOR_START = 0, + TINY_FRAME_WITH_LEN16_GETTING_MSG_ID = 1, + TINY_FRAME_WITH_LEN16_GETTING_LENGTH = 2, + TINY_FRAME_WITH_LEN16_GETTING_PAYLOAD = 3 +} tiny_frame_with_len16_parser_state_t; + +/* TinyFrameWithLen16 parser state structure */ +typedef struct tiny_frame_with_len16_parser { + tiny_frame_with_len16_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + uint8_t length_lo; /* Low byte for 16-bit length */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} tiny_frame_with_len16_parser_t; + +/* TinyFrameWithLen16 encode buffer structure */ +typedef struct tiny_frame_with_len16_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} tiny_frame_with_len16_encode_buffer_t; + +/** + * Initialize a TinyFrameWithLen16 parser + */ +static inline void tiny_frame_with_len16_parser_init(tiny_frame_with_len16_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->length_lo = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset TinyFrameWithLen16 parser state + */ +static inline void tiny_frame_with_len16_parser_reset(tiny_frame_with_len16_parser_t* parser) { + parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with TinyFrameWithLen16 format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t tiny_frame_with_len16_parse_byte(tiny_frame_with_len16_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case TINY_FRAME_WITH_LEN16_LOOKING_FOR_START: + if (byte == TINY_FRAME_WITH_LEN16_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = TINY_FRAME_WITH_LEN16_GETTING_MSG_ID; + } + break; + + case TINY_FRAME_WITH_LEN16_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = TINY_FRAME_WITH_LEN16_GETTING_LENGTH; + break; + + case TINY_FRAME_WITH_LEN16_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + if (parser->buffer_index == 3) { + parser->length_lo = byte; + } else { + parser->msg_length = parser->length_lo | ((size_t)byte << 8); + parser->packet_size = TINY_FRAME_WITH_LEN16_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = TINY_FRAME_WITH_LEN16_GETTING_PAYLOAD; + } else { + parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; + } + } + break; + + case TINY_FRAME_WITH_LEN16_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - TINY_FRAME_WITH_LEN16_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 1, msg_length + 1 + 2); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE; + } + parser->state = TINY_FRAME_WITH_LEN16_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with TinyFrameWithLen16 format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t tiny_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = TINY_FRAME_WITH_LEN16_START_BYTE; + buffer[1] = msg_id; + buffer[2] = (uint8_t)(msg_size & 0xFF); + buffer[3] = (uint8_t)((msg_size >> 8) & 0xFF); + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_size + 1 + 2); + buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLen16 packet in a buffer + */ +static inline frame_msg_info_t tiny_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < TINY_FRAME_WITH_LEN16_OVERHEAD) { + return result; + } + + if (buffer[0] != TINY_FRAME_WITH_LEN16_START_BYTE) { + return result; + } + + size_t msg_length = length - TINY_FRAME_WITH_LEN16_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 1, msg_length + 1 + 2); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/tiny_frame_with_len16_no_crc.h b/src/struct_frame/boilerplate/c/tiny_frame_with_len16_no_crc.h new file mode 100644 index 00000000..32324b1f --- /dev/null +++ b/src/struct_frame/boilerplate/c/tiny_frame_with_len16_no_crc.h @@ -0,0 +1,180 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * TinyFrameWithLen16NoCrc Frame Format + *===========================================================================*/ + +/* TinyFrameWithLen16NoCrc constants */ +#define TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE 0x75 +#define TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE 4 /* start_byte + msg_id + length(2) */ +#define TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD (TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE) + +/* TinyFrameWithLen16NoCrc parser states */ +typedef enum tiny_frame_with_len16_no_crc_parser_state { + TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START = 0, + TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID = 1, + TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH = 2, + TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD = 3 +} tiny_frame_with_len16_no_crc_parser_state_t; + +/* TinyFrameWithLen16NoCrc parser state structure */ +typedef struct tiny_frame_with_len16_no_crc_parser { + tiny_frame_with_len16_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + uint8_t length_lo; /* Low byte for 16-bit length */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} tiny_frame_with_len16_no_crc_parser_t; + +/* TinyFrameWithLen16NoCrc encode buffer structure */ +typedef struct tiny_frame_with_len16_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} tiny_frame_with_len16_no_crc_encode_buffer_t; + +/** + * Initialize a TinyFrameWithLen16NoCrc parser + */ +static inline void tiny_frame_with_len16_no_crc_parser_init(tiny_frame_with_len16_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->length_lo = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset TinyFrameWithLen16NoCrc parser state + */ +static inline void tiny_frame_with_len16_no_crc_parser_reset(tiny_frame_with_len16_no_crc_parser_t* parser) { + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with TinyFrameWithLen16NoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t tiny_frame_with_len16_no_crc_parse_byte(tiny_frame_with_len16_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START: + if (byte == TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID; + } + break; + + case TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH; + break; + + case TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + if (parser->buffer_index == 3) { + parser->length_lo = byte; + } else { + parser->msg_length = parser->length_lo | ((size_t)byte << 8); + parser->packet_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; + } + } + break; + + case TINY_FRAME_WITH_LEN16_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; + parser->state = TINY_FRAME_WITH_LEN16_NO_CRC_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with TinyFrameWithLen16NoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t tiny_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE; + buffer[1] = msg_id; + buffer[2] = (uint8_t)(msg_size & 0xFF); + buffer[3] = (uint8_t)((msg_size >> 8) & 0xFF); + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLen16NoCrc packet in a buffer + */ +static inline frame_msg_info_t tiny_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) { + return result; + } + + if (buffer[0] != TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) { + return result; + } + + size_t msg_length = length - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/tiny_frame_with_len_no_crc.h b/src/struct_frame/boilerplate/c/tiny_frame_with_len_no_crc.h new file mode 100644 index 00000000..8404e082 --- /dev/null +++ b/src/struct_frame/boilerplate/c/tiny_frame_with_len_no_crc.h @@ -0,0 +1,173 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * TinyFrameWithLenNoCrc Frame Format + *===========================================================================*/ + +/* TinyFrameWithLenNoCrc constants */ +#define TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE 0x73 +#define TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE 3 /* start_byte + msg_id + length(1) */ +#define TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE 0 /* no footer */ +#define TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD (TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE) + +/* TinyFrameWithLenNoCrc parser states */ +typedef enum tiny_frame_with_len_no_crc_parser_state { + TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START = 0, + TINY_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID = 1, + TINY_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH = 2, + TINY_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD = 3 +} tiny_frame_with_len_no_crc_parser_state_t; + +/* TinyFrameWithLenNoCrc parser state structure */ +typedef struct tiny_frame_with_len_no_crc_parser { + tiny_frame_with_len_no_crc_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} tiny_frame_with_len_no_crc_parser_t; + +/* TinyFrameWithLenNoCrc encode buffer structure */ +typedef struct tiny_frame_with_len_no_crc_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} tiny_frame_with_len_no_crc_encode_buffer_t; + +/** + * Initialize a TinyFrameWithLenNoCrc parser + */ +static inline void tiny_frame_with_len_no_crc_parser_init(tiny_frame_with_len_no_crc_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset TinyFrameWithLenNoCrc parser state + */ +static inline void tiny_frame_with_len_no_crc_parser_reset(tiny_frame_with_len_no_crc_parser_t* parser) { + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with TinyFrameWithLenNoCrc format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t tiny_frame_with_len_no_crc_parse_byte(tiny_frame_with_len_no_crc_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START: + if (byte == TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID; + } + break; + + case TINY_FRAME_WITH_LEN_NO_CRC_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH; + break; + + case TINY_FRAME_WITH_LEN_NO_CRC_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD; + } else { + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; + } + break; + + case TINY_FRAME_WITH_LEN_NO_CRC_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = parser->packet_size - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + result.msg_data = parser->buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; + parser->state = TINY_FRAME_WITH_LEN_NO_CRC_LOOKING_FOR_START; + } + break; + } + + return result; +} + +/** + * Encode a message with TinyFrameWithLenNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t tiny_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE; + buffer[1] = msg_id; + buffer[2] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLenNoCrc packet in a buffer + */ +static inline frame_msg_info_t tiny_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD) { + return result; + } + + if (buffer[0] != TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) { + return result; + } + + size_t msg_length = length - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); + + return result; +} + diff --git a/src/struct_frame/boilerplate/c/ubx_frame.h b/src/struct_frame/boilerplate/c/ubx_frame.h new file mode 100644 index 00000000..4006db69 --- /dev/null +++ b/src/struct_frame/boilerplate/c/ubx_frame.h @@ -0,0 +1,209 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.h" + +/*=========================================================================== + * UbxFrame Frame Format + *===========================================================================*/ + +/* UbxFrame constants */ +#define UBX_FRAME_START_BYTE1 0xB5 +#define UBX_FRAME_START_BYTE2 0x62 +#define UBX_FRAME_HEADER_SIZE 5 /* sync1 + sync2 + msg_id + length(1) */ +#define UBX_FRAME_FOOTER_SIZE 2 /* crc(2 bytes) */ +#define UBX_FRAME_OVERHEAD (UBX_FRAME_HEADER_SIZE + UBX_FRAME_FOOTER_SIZE) + +/* UbxFrame parser states */ +typedef enum ubx_frame_parser_state { + UBX_FRAME_LOOKING_FOR_START1 = 0, + UBX_FRAME_LOOKING_FOR_START2 = 1, + UBX_FRAME_GETTING_MSG_ID = 2, + UBX_FRAME_GETTING_LENGTH = 3, + UBX_FRAME_GETTING_PAYLOAD = 4 +} ubx_frame_parser_state_t; + +/* UbxFrame parser state structure */ +typedef struct ubx_frame_parser { + ubx_frame_parser_state_t state; + uint8_t* buffer; + size_t buffer_max_size; + size_t buffer_index; + size_t packet_size; + uint8_t msg_id; + size_t msg_length; /* From length field */ + /* User-provided function to get message length from msg_id (for non-length frames) */ + bool (*get_msg_length)(uint8_t msg_id, size_t* length); +} ubx_frame_parser_t; + +/* UbxFrame encode buffer structure */ +typedef struct ubx_frame_encode_buffer { + uint8_t* data; + size_t max_size; + size_t size; + bool in_progress; + size_t reserved_msg_size; +} ubx_frame_encode_buffer_t; + +/** + * Initialize a UbxFrame parser + */ +static inline void ubx_frame_parser_init(ubx_frame_parser_t* parser, + uint8_t* buffer, size_t buffer_size, + bool (*get_msg_length)(uint8_t msg_id, size_t* length)) { + parser->state = UBX_FRAME_LOOKING_FOR_START1; + parser->buffer = buffer; + parser->buffer_max_size = buffer_size; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; + parser->get_msg_length = get_msg_length; +} + +/** + * Reset UbxFrame parser state + */ +static inline void ubx_frame_parser_reset(ubx_frame_parser_t* parser) { + parser->state = UBX_FRAME_LOOKING_FOR_START1; + parser->buffer_index = 0; + parser->packet_size = 0; + parser->msg_id = 0; + parser->msg_length = 0; +} + +/** + * Parse a single byte with UbxFrame format + * Returns frame_msg_info_t with valid=true when a complete valid message is received + */ +static inline frame_msg_info_t ubx_frame_parse_byte(ubx_frame_parser_t* parser, uint8_t byte) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + switch (parser->state) { + case UBX_FRAME_LOOKING_FOR_START1: + if (byte == UBX_FRAME_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = UBX_FRAME_LOOKING_FOR_START2; + } + break; + + case UBX_FRAME_LOOKING_FOR_START2: + if (byte == UBX_FRAME_START_BYTE2) { + parser->buffer[1] = byte; + parser->buffer_index = 2; + parser->state = UBX_FRAME_GETTING_MSG_ID; + } else if (byte == UBX_FRAME_START_BYTE1) { + parser->buffer[0] = byte; + parser->buffer_index = 1; + parser->state = UBX_FRAME_LOOKING_FOR_START2; + } else { + parser->state = UBX_FRAME_LOOKING_FOR_START1; + } + break; + + case UBX_FRAME_GETTING_MSG_ID: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_id = byte; + parser->state = UBX_FRAME_GETTING_LENGTH; + break; + + case UBX_FRAME_GETTING_LENGTH: + parser->buffer[parser->buffer_index++] = byte; + parser->msg_length = byte; + parser->packet_size = UBX_FRAME_OVERHEAD + parser->msg_length; + if (parser->packet_size <= parser->buffer_max_size) { + parser->state = UBX_FRAME_GETTING_PAYLOAD; + } else { + parser->state = UBX_FRAME_LOOKING_FOR_START1; + } + break; + + case UBX_FRAME_GETTING_PAYLOAD: + if (parser->buffer_index < parser->buffer_max_size) { + parser->buffer[parser->buffer_index++] = byte; + } + + if (parser->buffer_index >= parser->packet_size) { + /* Validate checksum */ + size_t msg_length = parser->packet_size - UBX_FRAME_OVERHEAD; + frame_checksum_t ck = frame_fletcher_checksum( + parser->buffer + 2, msg_length + 1 + 1); + + if (ck.byte1 == parser->buffer[parser->packet_size - 2] && + ck.byte2 == parser->buffer[parser->packet_size - 1]) { + result.valid = true; + result.msg_id = parser->msg_id; + result.msg_len = msg_length; + result.msg_data = parser->buffer + UBX_FRAME_HEADER_SIZE; + } + parser->state = UBX_FRAME_LOOKING_FOR_START1; + } + break; + } + + return result; +} + +/** + * Encode a message with UbxFrame format + * Returns the number of bytes written, or 0 on failure + */ +static inline size_t ubx_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = UBX_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) { + return 0; + } + + buffer[0] = UBX_FRAME_START_BYTE1; + buffer[1] = UBX_FRAME_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = (uint8_t)msg_size; + + /* Write message data */ + if (msg_size > 0 && msg != NULL) { + memcpy(buffer + UBX_FRAME_HEADER_SIZE, msg, msg_size); + } + + /* Calculate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_size + 1 + 1); + buffer[UBX_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[UBX_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete UbxFrame packet in a buffer + */ +static inline frame_msg_info_t ubx_frame_validate_packet(const uint8_t* buffer, size_t length) { + frame_msg_info_t result = {false, 0, 0, NULL}; + + if (length < UBX_FRAME_OVERHEAD) { + return result; + } + + if (buffer[0] != UBX_FRAME_START_BYTE1) { + return result; + } + if (buffer[1] != UBX_FRAME_START_BYTE2) { + return result; + } + + size_t msg_length = length - UBX_FRAME_OVERHEAD; + + /* Validate checksum */ + frame_checksum_t ck = frame_fletcher_checksum(buffer + 2, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = (uint8_t*)(buffer + UBX_FRAME_HEADER_SIZE); + } + + return result; +} + diff --git a/src/struct_frame/boilerplate/cpp/BasicFrame.hpp b/src/struct_frame/boilerplate/cpp/BasicFrame.hpp new file mode 100644 index 00000000..b6f630e1 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrame.hpp @@ -0,0 +1,238 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrame Frame Format +// ============================================================================= + +enum class BasicFrameParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingPayload = 3 +}; + +// BasicFrame constants +constexpr uint8_t BASIC_FRAME_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_START_BYTE2 = 0x91; +constexpr size_t BASIC_FRAME_HEADER_SIZE = 3; +constexpr size_t BASIC_FRAME_FOOTER_SIZE = 2; +constexpr size_t BASIC_FRAME_OVERHEAD = BASIC_FRAME_HEADER_SIZE + BASIC_FRAME_FOOTER_SIZE; + +/** + * BasicFrame Encode Buffer + */ +class BasicFrameEncodeBuffer { +public: + BasicFrameEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_START_BYTE1; + packet_start[1] = BASIC_FRAME_START_BYTE2; + packet_start[2] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1); + packet_start[BASIC_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[BASIC_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrame Frame Parser + */ +class BasicFrameParser { +public: + using MsgLengthCallback = std::function; + + BasicFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameParserState::LookingForStart1: + if (byte == BASIC_FRAME_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameParserState::LookingForStart2; + } + break; + + case BasicFrameParserState::LookingForStart2: + if (byte == BASIC_FRAME_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameParserState::LookingForStart2; + } else { + state_ = BasicFrameParserState::LookingForStart1; + } + break; + + case BasicFrameParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = BASIC_FRAME_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameParserState::GettingPayload; + } else { + state_ = BasicFrameParserState::LookingForStart1; + } + } else { + state_ = BasicFrameParserState::LookingForStart1; + } + break; + } + + case BasicFrameParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - BASIC_FRAME_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + BASIC_FRAME_HEADER_SIZE; + } + state_ = BasicFrameParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrame format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_START_BYTE1; + buffer[1] = BASIC_FRAME_START_BYTE2; + buffer[2] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1); + buffer[BASIC_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrame packet in a buffer + */ +inline FrameMsgInfo basic_frame_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/BasicFrameNoCrc.hpp b/src/struct_frame/boilerplate/cpp/BasicFrameNoCrc.hpp new file mode 100644 index 00000000..5db15d2e --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrameNoCrc.hpp @@ -0,0 +1,221 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrameNoCrc Frame Format +// ============================================================================= + +enum class BasicFrameNoCrcParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingPayload = 3 +}; + +// BasicFrameNoCrc constants +constexpr uint8_t BASIC_FRAME_NO_CRC_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_NO_CRC_START_BYTE2 = 0x95; +constexpr size_t BASIC_FRAME_NO_CRC_HEADER_SIZE = 3; +constexpr size_t BASIC_FRAME_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t BASIC_FRAME_NO_CRC_OVERHEAD = BASIC_FRAME_NO_CRC_HEADER_SIZE + BASIC_FRAME_NO_CRC_FOOTER_SIZE; + +/** + * BasicFrameNoCrc Encode Buffer + */ +class BasicFrameNoCrcEncodeBuffer { +public: + BasicFrameNoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_NO_CRC_START_BYTE1; + packet_start[1] = BASIC_FRAME_NO_CRC_START_BYTE2; + packet_start[2] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrameNoCrc Frame Parser + */ +class BasicFrameNoCrcParser { +public: + using MsgLengthCallback = std::function; + + BasicFrameNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameNoCrcParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameNoCrcParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameNoCrcParserState::LookingForStart1: + if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameNoCrcParserState::LookingForStart2; + } + break; + + case BasicFrameNoCrcParserState::LookingForStart2: + if (byte == BASIC_FRAME_NO_CRC_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameNoCrcParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameNoCrcParserState::LookingForStart2; + } else { + state_ = BasicFrameNoCrcParserState::LookingForStart1; + } + break; + + case BasicFrameNoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = BASIC_FRAME_NO_CRC_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameNoCrcParserState::GettingPayload; + } else { + state_ = BasicFrameNoCrcParserState::LookingForStart1; + } + } else { + state_ = BasicFrameNoCrcParserState::LookingForStart1; + } + break; + } + + case BasicFrameNoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - BASIC_FRAME_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + BASIC_FRAME_NO_CRC_HEADER_SIZE; + state_ = BasicFrameNoCrcParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameNoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrameNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_NO_CRC_START_BYTE1; + buffer[1] = BASIC_FRAME_NO_CRC_START_BYTE2; + buffer[2] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete BasicFrameNoCrc packet in a buffer + */ +inline FrameMsgInfo basic_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_NO_CRC_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_NO_CRC_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_NO_CRC_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/BasicFrameWithLen.hpp b/src/struct_frame/boilerplate/cpp/BasicFrameWithLen.hpp new file mode 100644 index 00000000..c19e81dc --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrameWithLen.hpp @@ -0,0 +1,246 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrameWithLen Frame Format +// ============================================================================= + +enum class BasicFrameWithLenParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingLength = 3, + GettingPayload = 4 +}; + +// BasicFrameWithLen constants +constexpr uint8_t BASIC_FRAME_WITH_LEN_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_WITH_LEN_START_BYTE2 = 0x92; +constexpr size_t BASIC_FRAME_WITH_LEN_HEADER_SIZE = 4; +constexpr size_t BASIC_FRAME_WITH_LEN_FOOTER_SIZE = 2; +constexpr size_t BASIC_FRAME_WITH_LEN_OVERHEAD = BASIC_FRAME_WITH_LEN_HEADER_SIZE + BASIC_FRAME_WITH_LEN_FOOTER_SIZE; +constexpr size_t BASIC_FRAME_WITH_LEN_LENGTH_BYTES = 1; + +/** + * BasicFrameWithLen Encode Buffer + */ +class BasicFrameWithLenEncodeBuffer { +public: + BasicFrameWithLenEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; + packet_start[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; + packet_start[2] = msg_id; + packet_start[3] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1 + 1); + packet_start[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrameWithLen Frame Parser + */ +class BasicFrameWithLenParser { +public: + using MsgLengthCallback = std::function; + + BasicFrameWithLenParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameWithLenParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameWithLenParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameWithLenParserState::LookingForStart1: + if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLenParserState::LookingForStart2; + } + break; + + case BasicFrameWithLenParserState::LookingForStart2: + if (byte == BASIC_FRAME_WITH_LEN_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameWithLenParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLenParserState::LookingForStart2; + } else { + state_ = BasicFrameWithLenParserState::LookingForStart1; + } + break; + + case BasicFrameWithLenParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = BasicFrameWithLenParserState::GettingLength; + break; + } + + case BasicFrameWithLenParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameWithLenParserState::GettingPayload; + } else { + state_ = BasicFrameWithLenParserState::LookingForStart1; + } + break; + + case BasicFrameWithLenParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - BASIC_FRAME_WITH_LEN_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1 + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN_HEADER_SIZE; + } + state_ = BasicFrameWithLenParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameWithLenParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrameWithLen format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1 + 1); + buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLen packet in a buffer + */ +inline FrameMsgInfo basic_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_WITH_LEN_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_WITH_LEN_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_WITH_LEN_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_WITH_LEN_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/BasicFrameWithLen16.hpp b/src/struct_frame/boilerplate/cpp/BasicFrameWithLen16.hpp new file mode 100644 index 00000000..329b66ae --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrameWithLen16.hpp @@ -0,0 +1,254 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrameWithLen16 Frame Format +// ============================================================================= + +enum class BasicFrameWithLen16ParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingLength = 3, + GettingPayload = 4 +}; + +// BasicFrameWithLen16 constants +constexpr uint8_t BASIC_FRAME_WITH_LEN16_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_WITH_LEN16_START_BYTE2 = 0x93; +constexpr size_t BASIC_FRAME_WITH_LEN16_HEADER_SIZE = 5; +constexpr size_t BASIC_FRAME_WITH_LEN16_FOOTER_SIZE = 2; +constexpr size_t BASIC_FRAME_WITH_LEN16_OVERHEAD = BASIC_FRAME_WITH_LEN16_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_FOOTER_SIZE; +constexpr size_t BASIC_FRAME_WITH_LEN16_LENGTH_BYTES = 2; + +/** + * BasicFrameWithLen16 Encode Buffer + */ +class BasicFrameWithLen16EncodeBuffer { +public: + BasicFrameWithLen16EncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_WITH_LEN16_START_BYTE1; + packet_start[1] = BASIC_FRAME_WITH_LEN16_START_BYTE2; + packet_start[2] = msg_id; + packet_start[3] = static_cast(msg_size & 0xFF); + packet_start[4] = static_cast((msg_size >> 8) & 0xFF); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1 + 2); + packet_start[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrameWithLen16 Frame Parser + */ +class BasicFrameWithLen16Parser { +public: + using MsgLengthCallback = std::function; + + BasicFrameWithLen16Parser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameWithLen16ParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + length_lo_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameWithLen16ParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameWithLen16ParserState::LookingForStart1: + if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLen16ParserState::LookingForStart2; + } + break; + + case BasicFrameWithLen16ParserState::LookingForStart2: + if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameWithLen16ParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLen16ParserState::LookingForStart2; + } else { + state_ = BasicFrameWithLen16ParserState::LookingForStart1; + } + break; + + case BasicFrameWithLen16ParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = BasicFrameWithLen16ParserState::GettingLength; + break; + } + + case BasicFrameWithLen16ParserState::GettingLength: + buffer_[buffer_index_++] = byte; + if (buffer_index_ == 4) { + length_lo_ = byte; + } else { + msg_length_ = length_lo_ | (static_cast(byte) << 8); + packet_size_ = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameWithLen16ParserState::GettingPayload; + } else { + state_ = BasicFrameWithLen16ParserState::LookingForStart1; + } + } + break; + + case BasicFrameWithLen16ParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - BASIC_FRAME_WITH_LEN16_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1 + 2); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN16_HEADER_SIZE; + } + state_ = BasicFrameWithLen16ParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameWithLen16ParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + uint8_t length_lo_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrameWithLen16 format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_WITH_LEN16_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN16_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = static_cast(msg_size & 0xFF); + buffer[4] = static_cast((msg_size >> 8) & 0xFF); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1 + 2); + buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLen16 packet in a buffer + */ +inline FrameMsgInfo basic_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_WITH_LEN16_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_WITH_LEN16_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_WITH_LEN16_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_WITH_LEN16_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1 + 2); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/BasicFrameWithLen16NoCrc.hpp b/src/struct_frame/boilerplate/cpp/BasicFrameWithLen16NoCrc.hpp new file mode 100644 index 00000000..7834beb9 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrameWithLen16NoCrc.hpp @@ -0,0 +1,237 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrameWithLen16NoCrc Frame Format +// ============================================================================= + +enum class BasicFrameWithLen16NoCrcParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingLength = 3, + GettingPayload = 4 +}; + +// BasicFrameWithLen16NoCrc constants +constexpr uint8_t BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2 = 0x97; +constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE = 5; +constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD = BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE; +constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_LENGTH_BYTES = 2; + +/** + * BasicFrameWithLen16NoCrc Encode Buffer + */ +class BasicFrameWithLen16NoCrcEncodeBuffer { +public: + BasicFrameWithLen16NoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1; + packet_start[1] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2; + packet_start[2] = msg_id; + packet_start[3] = static_cast(msg_size & 0xFF); + packet_start[4] = static_cast((msg_size >> 8) & 0xFF); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrameWithLen16NoCrc Frame Parser + */ +class BasicFrameWithLen16NoCrcParser { +public: + using MsgLengthCallback = std::function; + + BasicFrameWithLen16NoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameWithLen16NoCrcParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + length_lo_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameWithLen16NoCrcParserState::LookingForStart1: + if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart2; + } + break; + + case BasicFrameWithLen16NoCrcParserState::LookingForStart2: + if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameWithLen16NoCrcParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart2; + } else { + state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; + } + break; + + case BasicFrameWithLen16NoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = BasicFrameWithLen16NoCrcParserState::GettingLength; + break; + } + + case BasicFrameWithLen16NoCrcParserState::GettingLength: + buffer_[buffer_index_++] = byte; + if (buffer_index_ == 4) { + length_lo_ = byte; + } else { + msg_length_ = length_lo_ | (static_cast(byte) << 8); + packet_size_ = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameWithLen16NoCrcParserState::GettingPayload; + } else { + state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; + } + } + break; + + case BasicFrameWithLen16NoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; + state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameWithLen16NoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + uint8_t length_lo_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrameWithLen16NoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = static_cast(msg_size & 0xFF); + buffer[4] = static_cast((msg_size >> 8) & 0xFF); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLen16NoCrc packet in a buffer + */ +inline FrameMsgInfo basic_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/BasicFrameWithLenNoCrc.hpp b/src/struct_frame/boilerplate/cpp/BasicFrameWithLenNoCrc.hpp new file mode 100644 index 00000000..cbba84d0 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrameWithLenNoCrc.hpp @@ -0,0 +1,229 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrameWithLenNoCrc Frame Format +// ============================================================================= + +enum class BasicFrameWithLenNoCrcParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingLength = 3, + GettingPayload = 4 +}; + +// BasicFrameWithLenNoCrc constants +constexpr uint8_t BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2 = 0x96; +constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE = 4; +constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD = BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE; +constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_LENGTH_BYTES = 1; + +/** + * BasicFrameWithLenNoCrc Encode Buffer + */ +class BasicFrameWithLenNoCrcEncodeBuffer { +public: + BasicFrameWithLenNoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1; + packet_start[1] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2; + packet_start[2] = msg_id; + packet_start[3] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrameWithLenNoCrc Frame Parser + */ +class BasicFrameWithLenNoCrcParser { +public: + using MsgLengthCallback = std::function; + + BasicFrameWithLenNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameWithLenNoCrcParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameWithLenNoCrcParserState::LookingForStart1: + if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLenNoCrcParserState::LookingForStart2; + } + break; + + case BasicFrameWithLenNoCrcParserState::LookingForStart2: + if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameWithLenNoCrcParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithLenNoCrcParserState::LookingForStart2; + } else { + state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; + } + break; + + case BasicFrameWithLenNoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = BasicFrameWithLenNoCrcParserState::GettingLength; + break; + } + + case BasicFrameWithLenNoCrcParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameWithLenNoCrcParserState::GettingPayload; + } else { + state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; + } + break; + + case BasicFrameWithLenNoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; + state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameWithLenNoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrameWithLenNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete BasicFrameWithLenNoCrc packet in a buffer + */ +inline FrameMsgInfo basic_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/BasicFrameWithSysComp.hpp b/src/struct_frame/boilerplate/cpp/BasicFrameWithSysComp.hpp new file mode 100644 index 00000000..ccd44f05 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/BasicFrameWithSysComp.hpp @@ -0,0 +1,238 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// BasicFrameWithSysComp Frame Format +// ============================================================================= + +enum class BasicFrameWithSysCompParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingPayload = 3 +}; + +// BasicFrameWithSysComp constants +constexpr uint8_t BASIC_FRAME_WITH_SYS_COMP_START_BYTE1 = 0x90; +constexpr uint8_t BASIC_FRAME_WITH_SYS_COMP_START_BYTE2 = 0x94; +constexpr size_t BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE = 3; +constexpr size_t BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE = 2; +constexpr size_t BASIC_FRAME_WITH_SYS_COMP_OVERHEAD = BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE; + +/** + * BasicFrameWithSysComp Encode Buffer + */ +class BasicFrameWithSysCompEncodeBuffer { +public: + BasicFrameWithSysCompEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE1; + packet_start[1] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE2; + packet_start[2] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1); + packet_start[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * BasicFrameWithSysComp Frame Parser + */ +class BasicFrameWithSysCompParser { +public: + using MsgLengthCallback = std::function; + + BasicFrameWithSysCompParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(BasicFrameWithSysCompParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = BasicFrameWithSysCompParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case BasicFrameWithSysCompParserState::LookingForStart1: + if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithSysCompParserState::LookingForStart2; + } + break; + + case BasicFrameWithSysCompParserState::LookingForStart2: + if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = BasicFrameWithSysCompParserState::GettingMsgId; + } else if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = BasicFrameWithSysCompParserState::LookingForStart2; + } else { + state_ = BasicFrameWithSysCompParserState::LookingForStart1; + } + break; + + case BasicFrameWithSysCompParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = BasicFrameWithSysCompParserState::GettingPayload; + } else { + state_ = BasicFrameWithSysCompParserState::LookingForStart1; + } + } else { + state_ = BasicFrameWithSysCompParserState::LookingForStart1; + } + break; + } + + case BasicFrameWithSysCompParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE; + } + state_ = BasicFrameWithSysCompParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + BasicFrameWithSysCompParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with BasicFrameWithSysComp format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t basic_frame_with_sys_comp_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE1; + buffer[1] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE2; + buffer[2] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1); + buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size] = ck.byte1; + buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete BasicFrameWithSysComp packet in a buffer + */ +inline FrameMsgInfo basic_frame_with_sys_comp_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < BASIC_FRAME_WITH_SYS_COMP_OVERHEAD) return result; + + if (buffer[0] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) return result; + if (buffer[1] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) return result; + + size_t msg_length = length - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/FrameFormatConfig.hpp b/src/struct_frame/boilerplate/cpp/FrameFormatConfig.hpp new file mode 100644 index 00000000..e56d684b --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/FrameFormatConfig.hpp @@ -0,0 +1,238 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// FrameFormatConfig Frame Format +// ============================================================================= + +enum class FrameFormatConfigParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingPayload = 3 +}; + +// FrameFormatConfig constants +constexpr uint8_t FRAME_FORMAT_CONFIG_START_BYTE1 = 0x90; +constexpr uint8_t FRAME_FORMAT_CONFIG_START_BYTE2 = 0x91; +constexpr size_t FRAME_FORMAT_CONFIG_HEADER_SIZE = 2; +constexpr size_t FRAME_FORMAT_CONFIG_FOOTER_SIZE = 1; +constexpr size_t FRAME_FORMAT_CONFIG_OVERHEAD = FRAME_FORMAT_CONFIG_HEADER_SIZE + FRAME_FORMAT_CONFIG_FOOTER_SIZE; + +/** + * FrameFormatConfig Encode Buffer + */ +class FrameFormatConfigEncodeBuffer { +public: + FrameFormatConfigEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = FRAME_FORMAT_CONFIG_START_BYTE1; + packet_start[1] = FRAME_FORMAT_CONFIG_START_BYTE2; + packet_start[2] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + FRAME_FORMAT_CONFIG_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1); + packet_start[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * FrameFormatConfig Frame Parser + */ +class FrameFormatConfigParser { +public: + using MsgLengthCallback = std::function; + + FrameFormatConfigParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(FrameFormatConfigParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = FrameFormatConfigParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case FrameFormatConfigParserState::LookingForStart1: + if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = FrameFormatConfigParserState::LookingForStart2; + } + break; + + case FrameFormatConfigParserState::LookingForStart2: + if (byte == FRAME_FORMAT_CONFIG_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = FrameFormatConfigParserState::GettingMsgId; + } else if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = FrameFormatConfigParserState::LookingForStart2; + } else { + state_ = FrameFormatConfigParserState::LookingForStart1; + } + break; + + case FrameFormatConfigParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = FRAME_FORMAT_CONFIG_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = FrameFormatConfigParserState::GettingPayload; + } else { + state_ = FrameFormatConfigParserState::LookingForStart1; + } + } else { + state_ = FrameFormatConfigParserState::LookingForStart1; + } + break; + } + + case FrameFormatConfigParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - FRAME_FORMAT_CONFIG_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + FRAME_FORMAT_CONFIG_HEADER_SIZE; + } + state_ = FrameFormatConfigParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + FrameFormatConfigParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with FrameFormatConfig format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t frame_format_config_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = FRAME_FORMAT_CONFIG_START_BYTE1; + buffer[1] = FRAME_FORMAT_CONFIG_START_BYTE2; + buffer[2] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1); + buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size] = ck.byte1; + buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete FrameFormatConfig packet in a buffer + */ +inline FrameMsgInfo frame_format_config_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < FRAME_FORMAT_CONFIG_OVERHEAD) return result; + + if (buffer[0] != FRAME_FORMAT_CONFIG_START_BYTE1) return result; + if (buffer[1] != FRAME_FORMAT_CONFIG_START_BYTE2) return result; + + size_t msg_length = length - FRAME_FORMAT_CONFIG_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MavlinkV1Frame.hpp b/src/struct_frame/boilerplate/cpp/MavlinkV1Frame.hpp new file mode 100644 index 00000000..de7146da --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MavlinkV1Frame.hpp @@ -0,0 +1,227 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MavlinkV1Frame Frame Format +// ============================================================================= + +enum class MavlinkV1FrameParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingLength = 2, + GettingPayload = 3 +}; + +// MavlinkV1Frame constants +constexpr uint8_t MAVLINK_V1_FRAME_START_BYTE = 0xFE; +constexpr size_t MAVLINK_V1_FRAME_HEADER_SIZE = 3; +constexpr size_t MAVLINK_V1_FRAME_FOOTER_SIZE = 2; +constexpr size_t MAVLINK_V1_FRAME_OVERHEAD = MAVLINK_V1_FRAME_HEADER_SIZE + MAVLINK_V1_FRAME_FOOTER_SIZE; +constexpr size_t MAVLINK_V1_FRAME_LENGTH_BYTES = 1; + +/** + * MavlinkV1Frame Encode Buffer + */ +class MavlinkV1FrameEncodeBuffer { +public: + MavlinkV1FrameEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MAVLINK_V1_FRAME_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = MAVLINK_V1_FRAME_START_BYTE; + packet_start[1] = msg_id; + packet_start[2] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MAVLINK_V1_FRAME_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 1); + packet_start[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MavlinkV1Frame Frame Parser + */ +class MavlinkV1FrameParser { +public: + using MsgLengthCallback = std::function; + + MavlinkV1FrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MavlinkV1FrameParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MavlinkV1FrameParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MavlinkV1FrameParserState::LookingForStart: + if (byte == MAVLINK_V1_FRAME_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = MavlinkV1FrameParserState::GettingMsgId; + } + break; + + case MavlinkV1FrameParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = MavlinkV1FrameParserState::GettingLength; + break; + } + + case MavlinkV1FrameParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = MAVLINK_V1_FRAME_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = MavlinkV1FrameParserState::GettingPayload; + } else { + state_ = MavlinkV1FrameParserState::LookingForStart; + } + break; + + case MavlinkV1FrameParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - MAVLINK_V1_FRAME_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + MAVLINK_V1_FRAME_HEADER_SIZE; + } + state_ = MavlinkV1FrameParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + MavlinkV1FrameParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MavlinkV1Frame format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t mavlink_v1_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MAVLINK_V1_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = MAVLINK_V1_FRAME_START_BYTE; + buffer[1] = msg_id; + buffer[2] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MAVLINK_V1_FRAME_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 1); + buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MavlinkV1Frame packet in a buffer + */ +inline FrameMsgInfo mavlink_v1_frame_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MAVLINK_V1_FRAME_OVERHEAD) return result; + + if (buffer[0] != MAVLINK_V1_FRAME_START_BYTE) return result; + + size_t msg_length = length - MAVLINK_V1_FRAME_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MAVLINK_V1_FRAME_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MavlinkV2Frame.hpp b/src/struct_frame/boilerplate/cpp/MavlinkV2Frame.hpp new file mode 100644 index 00000000..0e2c7ff4 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MavlinkV2Frame.hpp @@ -0,0 +1,227 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MavlinkV2Frame Frame Format +// ============================================================================= + +enum class MavlinkV2FrameParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingLength = 2, + GettingPayload = 3 +}; + +// MavlinkV2Frame constants +constexpr uint8_t MAVLINK_V2_FRAME_START_BYTE = 0xFD; +constexpr size_t MAVLINK_V2_FRAME_HEADER_SIZE = 5; +constexpr size_t MAVLINK_V2_FRAME_FOOTER_SIZE = 2; +constexpr size_t MAVLINK_V2_FRAME_OVERHEAD = MAVLINK_V2_FRAME_HEADER_SIZE + MAVLINK_V2_FRAME_FOOTER_SIZE; +constexpr size_t MAVLINK_V2_FRAME_LENGTH_BYTES = 1; + +/** + * MavlinkV2Frame Encode Buffer + */ +class MavlinkV2FrameEncodeBuffer { +public: + MavlinkV2FrameEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MAVLINK_V2_FRAME_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = MAVLINK_V2_FRAME_START_BYTE; + packet_start[1] = msg_id; + packet_start[2] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MAVLINK_V2_FRAME_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 1); + packet_start[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MavlinkV2Frame Frame Parser + */ +class MavlinkV2FrameParser { +public: + using MsgLengthCallback = std::function; + + MavlinkV2FrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MavlinkV2FrameParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MavlinkV2FrameParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MavlinkV2FrameParserState::LookingForStart: + if (byte == MAVLINK_V2_FRAME_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = MavlinkV2FrameParserState::GettingMsgId; + } + break; + + case MavlinkV2FrameParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = MavlinkV2FrameParserState::GettingLength; + break; + } + + case MavlinkV2FrameParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = MAVLINK_V2_FRAME_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = MavlinkV2FrameParserState::GettingPayload; + } else { + state_ = MavlinkV2FrameParserState::LookingForStart; + } + break; + + case MavlinkV2FrameParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - MAVLINK_V2_FRAME_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + MAVLINK_V2_FRAME_HEADER_SIZE; + } + state_ = MavlinkV2FrameParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + MavlinkV2FrameParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MavlinkV2Frame format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t mavlink_v2_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MAVLINK_V2_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = MAVLINK_V2_FRAME_START_BYTE; + buffer[1] = msg_id; + buffer[2] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MAVLINK_V2_FRAME_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 1); + buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MavlinkV2Frame packet in a buffer + */ +inline FrameMsgInfo mavlink_v2_frame_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MAVLINK_V2_FRAME_OVERHEAD) return result; + + if (buffer[0] != MAVLINK_V2_FRAME_START_BYTE) return result; + + size_t msg_length = length - MAVLINK_V2_FRAME_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MAVLINK_V2_FRAME_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MinimalFrame.hpp b/src/struct_frame/boilerplate/cpp/MinimalFrame.hpp new file mode 100644 index 00000000..3092fabb --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MinimalFrame.hpp @@ -0,0 +1,206 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MinimalFrame Frame Format +// ============================================================================= + +enum class MinimalFrameParserState : uint8_t { + GettingMsgId = 0, + GettingPayload = 1 +}; + +// MinimalFrame constants +constexpr size_t MINIMAL_FRAME_HEADER_SIZE = 1; +constexpr size_t MINIMAL_FRAME_FOOTER_SIZE = 2; +constexpr size_t MINIMAL_FRAME_OVERHEAD = MINIMAL_FRAME_HEADER_SIZE + MINIMAL_FRAME_FOOTER_SIZE; + +/** + * MinimalFrame Encode Buffer + */ +class MinimalFrameEncodeBuffer { +public: + MinimalFrameEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MINIMAL_FRAME_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MINIMAL_FRAME_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 0, msg_size + 1); + packet_start[MINIMAL_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[MINIMAL_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MinimalFrame Frame Parser + */ +class MinimalFrameParser { +public: + using MsgLengthCallback = std::function; + + MinimalFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MinimalFrameParserState::GettingMsgId), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MinimalFrameParserState::GettingMsgId; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MinimalFrameParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = MINIMAL_FRAME_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = MinimalFrameParserState::GettingPayload; + } else { + state_ = MinimalFrameParserState::GettingMsgId; + } + } else { + state_ = MinimalFrameParserState::GettingMsgId; + } + break; + } + + case MinimalFrameParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - MINIMAL_FRAME_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 0, msg_length + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + MINIMAL_FRAME_HEADER_SIZE; + } + state_ = MinimalFrameParserState::GettingMsgId; + } + break; + } + + return result; + } + +private: + MinimalFrameParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MinimalFrame format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t minimal_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MINIMAL_FRAME_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 0, msg_size + 1); + buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MinimalFrame packet in a buffer + */ +inline FrameMsgInfo minimal_frame_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MINIMAL_FRAME_OVERHEAD) return result; + + + size_t msg_length = length - MINIMAL_FRAME_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 0, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MINIMAL_FRAME_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen.hpp b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen.hpp new file mode 100644 index 00000000..9b025bec --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen.hpp @@ -0,0 +1,214 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MinimalFrameWithLen Frame Format +// ============================================================================= + +enum class MinimalFrameWithLenParserState : uint8_t { + GettingMsgId = 0, + GettingLength = 1, + GettingPayload = 2 +}; + +// MinimalFrameWithLen constants +constexpr size_t MINIMAL_FRAME_WITH_LEN_HEADER_SIZE = 2; +constexpr size_t MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE = 2; +constexpr size_t MINIMAL_FRAME_WITH_LEN_OVERHEAD = MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE; +constexpr size_t MINIMAL_FRAME_WITH_LEN_LENGTH_BYTES = 1; + +/** + * MinimalFrameWithLen Encode Buffer + */ +class MinimalFrameWithLenEncodeBuffer { +public: + MinimalFrameWithLenEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = msg_id; + packet_start[1] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 0, msg_size + 1 + 1); + packet_start[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MinimalFrameWithLen Frame Parser + */ +class MinimalFrameWithLenParser { +public: + using MsgLengthCallback = std::function; + + MinimalFrameWithLenParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MinimalFrameWithLenParserState::GettingMsgId), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MinimalFrameWithLenParserState::GettingMsgId; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MinimalFrameWithLenParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = MinimalFrameWithLenParserState::GettingLength; + break; + } + + case MinimalFrameWithLenParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = MinimalFrameWithLenParserState::GettingPayload; + } else { + state_ = MinimalFrameWithLenParserState::GettingMsgId; + } + break; + + case MinimalFrameWithLenParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - MINIMAL_FRAME_WITH_LEN_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 0, msg_length + 1 + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE; + } + state_ = MinimalFrameWithLenParserState::GettingMsgId; + } + break; + } + + return result; + } + +private: + MinimalFrameWithLenParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MinimalFrameWithLen format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t minimal_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = msg_id; + buffer[1] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 0, msg_size + 1 + 1); + buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLen packet in a buffer + */ +inline FrameMsgInfo minimal_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MINIMAL_FRAME_WITH_LEN_OVERHEAD) return result; + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 0, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen16.hpp b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen16.hpp new file mode 100644 index 00000000..00044909 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen16.hpp @@ -0,0 +1,222 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MinimalFrameWithLen16 Frame Format +// ============================================================================= + +enum class MinimalFrameWithLen16ParserState : uint8_t { + GettingMsgId = 0, + GettingLength = 1, + GettingPayload = 2 +}; + +// MinimalFrameWithLen16 constants +constexpr size_t MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE = 3; +constexpr size_t MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE = 2; +constexpr size_t MINIMAL_FRAME_WITH_LEN16_OVERHEAD = MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE; +constexpr size_t MINIMAL_FRAME_WITH_LEN16_LENGTH_BYTES = 2; + +/** + * MinimalFrameWithLen16 Encode Buffer + */ +class MinimalFrameWithLen16EncodeBuffer { +public: + MinimalFrameWithLen16EncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = msg_id; + packet_start[1] = static_cast(msg_size & 0xFF); + packet_start[2] = static_cast((msg_size >> 8) & 0xFF); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 0, msg_size + 1 + 2); + packet_start[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MinimalFrameWithLen16 Frame Parser + */ +class MinimalFrameWithLen16Parser { +public: + using MsgLengthCallback = std::function; + + MinimalFrameWithLen16Parser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MinimalFrameWithLen16ParserState::GettingMsgId), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + length_lo_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MinimalFrameWithLen16ParserState::GettingMsgId; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MinimalFrameWithLen16ParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = MinimalFrameWithLen16ParserState::GettingLength; + break; + } + + case MinimalFrameWithLen16ParserState::GettingLength: + buffer_[buffer_index_++] = byte; + if (buffer_index_ == 2) { + length_lo_ = byte; + } else { + msg_length_ = length_lo_ | (static_cast(byte) << 8); + packet_size_ = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = MinimalFrameWithLen16ParserState::GettingPayload; + } else { + state_ = MinimalFrameWithLen16ParserState::GettingMsgId; + } + } + break; + + case MinimalFrameWithLen16ParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 0, msg_length + 1 + 2); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE; + } + state_ = MinimalFrameWithLen16ParserState::GettingMsgId; + } + break; + } + + return result; + } + +private: + MinimalFrameWithLen16ParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + uint8_t length_lo_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MinimalFrameWithLen16 format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t minimal_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = msg_id; + buffer[1] = static_cast(msg_size & 0xFF); + buffer[2] = static_cast((msg_size >> 8) & 0xFF); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 0, msg_size + 1 + 2); + buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLen16 packet in a buffer + */ +inline FrameMsgInfo minimal_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MINIMAL_FRAME_WITH_LEN16_OVERHEAD) return result; + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 0, msg_length + 1 + 2); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen16NoCrc.hpp b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen16NoCrc.hpp new file mode 100644 index 00000000..237970ca --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLen16NoCrc.hpp @@ -0,0 +1,205 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MinimalFrameWithLen16NoCrc Frame Format +// ============================================================================= + +enum class MinimalFrameWithLen16NoCrcParserState : uint8_t { + GettingMsgId = 0, + GettingLength = 1, + GettingPayload = 2 +}; + +// MinimalFrameWithLen16NoCrc constants +constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE = 3; +constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD = MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE; +constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_LENGTH_BYTES = 2; + +/** + * MinimalFrameWithLen16NoCrc Encode Buffer + */ +class MinimalFrameWithLen16NoCrcEncodeBuffer { +public: + MinimalFrameWithLen16NoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = msg_id; + packet_start[1] = static_cast(msg_size & 0xFF); + packet_start[2] = static_cast((msg_size >> 8) & 0xFF); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MinimalFrameWithLen16NoCrc Frame Parser + */ +class MinimalFrameWithLen16NoCrcParser { +public: + using MsgLengthCallback = std::function; + + MinimalFrameWithLen16NoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MinimalFrameWithLen16NoCrcParserState::GettingMsgId), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + length_lo_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MinimalFrameWithLen16NoCrcParserState::GettingMsgId; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MinimalFrameWithLen16NoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = MinimalFrameWithLen16NoCrcParserState::GettingLength; + break; + } + + case MinimalFrameWithLen16NoCrcParserState::GettingLength: + buffer_[buffer_index_++] = byte; + if (buffer_index_ == 2) { + length_lo_ = byte; + } else { + msg_length_ = length_lo_ | (static_cast(byte) << 8); + packet_size_ = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = MinimalFrameWithLen16NoCrcParserState::GettingPayload; + } else { + state_ = MinimalFrameWithLen16NoCrcParserState::GettingMsgId; + } + } + break; + + case MinimalFrameWithLen16NoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; + state_ = MinimalFrameWithLen16NoCrcParserState::GettingMsgId; + } + break; + } + + return result; + } + +private: + MinimalFrameWithLen16NoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + uint8_t length_lo_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MinimalFrameWithLen16NoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t minimal_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = msg_id; + buffer[1] = static_cast(msg_size & 0xFF); + buffer[2] = static_cast((msg_size >> 8) & 0xFF); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer + */ +inline FrameMsgInfo minimal_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) return result; + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/MinimalFrameWithLenNoCrc.hpp b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLenNoCrc.hpp new file mode 100644 index 00000000..3f036572 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/MinimalFrameWithLenNoCrc.hpp @@ -0,0 +1,197 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// MinimalFrameWithLenNoCrc Frame Format +// ============================================================================= + +enum class MinimalFrameWithLenNoCrcParserState : uint8_t { + GettingMsgId = 0, + GettingLength = 1, + GettingPayload = 2 +}; + +// MinimalFrameWithLenNoCrc constants +constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE = 2; +constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD = MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE; +constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_LENGTH_BYTES = 1; + +/** + * MinimalFrameWithLenNoCrc Encode Buffer + */ +class MinimalFrameWithLenNoCrcEncodeBuffer { +public: + MinimalFrameWithLenNoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = msg_id; + packet_start[1] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * MinimalFrameWithLenNoCrc Frame Parser + */ +class MinimalFrameWithLenNoCrcParser { +public: + using MsgLengthCallback = std::function; + + MinimalFrameWithLenNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(MinimalFrameWithLenNoCrcParserState::GettingMsgId), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = MinimalFrameWithLenNoCrcParserState::GettingMsgId; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case MinimalFrameWithLenNoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = MinimalFrameWithLenNoCrcParserState::GettingLength; + break; + } + + case MinimalFrameWithLenNoCrcParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = MinimalFrameWithLenNoCrcParserState::GettingPayload; + } else { + state_ = MinimalFrameWithLenNoCrcParserState::GettingMsgId; + } + break; + + case MinimalFrameWithLenNoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; + state_ = MinimalFrameWithLenNoCrcParserState::GettingMsgId; + } + break; + } + + return result; + } + +private: + MinimalFrameWithLenNoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with MinimalFrameWithLenNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t minimal_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = msg_id; + buffer[1] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete MinimalFrameWithLenNoCrc packet in a buffer + */ +inline FrameMsgInfo minimal_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD) return result; + + + size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/TinyFrame.hpp b/src/struct_frame/boilerplate/cpp/TinyFrame.hpp new file mode 100644 index 00000000..4188be36 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/TinyFrame.hpp @@ -0,0 +1,219 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// TinyFrame Frame Format +// ============================================================================= + +enum class TinyFrameParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingPayload = 2 +}; + +// TinyFrame constants +constexpr uint8_t TINY_FRAME_START_BYTE = 0x70; +constexpr size_t TINY_FRAME_HEADER_SIZE = 2; +constexpr size_t TINY_FRAME_FOOTER_SIZE = 2; +constexpr size_t TINY_FRAME_OVERHEAD = TINY_FRAME_HEADER_SIZE + TINY_FRAME_FOOTER_SIZE; + +/** + * TinyFrame Encode Buffer + */ +class TinyFrameEncodeBuffer { +public: + TinyFrameEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = TINY_FRAME_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = TINY_FRAME_START_BYTE; + packet_start[1] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + TINY_FRAME_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1); + packet_start[TINY_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[TINY_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * TinyFrame Frame Parser + */ +class TinyFrameParser { +public: + using MsgLengthCallback = std::function; + + TinyFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(TinyFrameParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = TinyFrameParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case TinyFrameParserState::LookingForStart: + if (byte == TINY_FRAME_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = TinyFrameParserState::GettingMsgId; + } + break; + + case TinyFrameParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = TINY_FRAME_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = TinyFrameParserState::GettingPayload; + } else { + state_ = TinyFrameParserState::LookingForStart; + } + } else { + state_ = TinyFrameParserState::LookingForStart; + } + break; + } + + case TinyFrameParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - TINY_FRAME_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + TINY_FRAME_HEADER_SIZE; + } + state_ = TinyFrameParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + TinyFrameParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with TinyFrame format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t tiny_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = TINY_FRAME_START_BYTE; + buffer[1] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + TINY_FRAME_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1); + buffer[TINY_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[TINY_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete TinyFrame packet in a buffer + */ +inline FrameMsgInfo tiny_frame_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < TINY_FRAME_OVERHEAD) return result; + + if (buffer[0] != TINY_FRAME_START_BYTE) return result; + + size_t msg_length = length - TINY_FRAME_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + TINY_FRAME_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/TinyFrameNoCrc.hpp b/src/struct_frame/boilerplate/cpp/TinyFrameNoCrc.hpp new file mode 100644 index 00000000..b3c26a8e --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/TinyFrameNoCrc.hpp @@ -0,0 +1,202 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// TinyFrameNoCrc Frame Format +// ============================================================================= + +enum class TinyFrameNoCrcParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingPayload = 2 +}; + +// TinyFrameNoCrc constants +constexpr uint8_t TINY_FRAME_NO_CRC_START_BYTE = 0x72; +constexpr size_t TINY_FRAME_NO_CRC_HEADER_SIZE = 2; +constexpr size_t TINY_FRAME_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t TINY_FRAME_NO_CRC_OVERHEAD = TINY_FRAME_NO_CRC_HEADER_SIZE + TINY_FRAME_NO_CRC_FOOTER_SIZE; + +/** + * TinyFrameNoCrc Encode Buffer + */ +class TinyFrameNoCrcEncodeBuffer { +public: + TinyFrameNoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = TINY_FRAME_NO_CRC_START_BYTE; + packet_start[1] = msg_id; + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + TINY_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * TinyFrameNoCrc Frame Parser + */ +class TinyFrameNoCrcParser { +public: + using MsgLengthCallback = std::function; + + TinyFrameNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(TinyFrameNoCrcParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = TinyFrameNoCrcParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case TinyFrameNoCrcParserState::LookingForStart: + if (byte == TINY_FRAME_NO_CRC_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = TinyFrameNoCrcParserState::GettingMsgId; + } + break; + + case TinyFrameNoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + size_t msg_length = 0; + if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { + packet_size_ = TINY_FRAME_NO_CRC_OVERHEAD + msg_length; + if (packet_size_ <= buffer_max_size_) { + state_ = TinyFrameNoCrcParserState::GettingPayload; + } else { + state_ = TinyFrameNoCrcParserState::LookingForStart; + } + } else { + state_ = TinyFrameNoCrcParserState::LookingForStart; + } + break; + } + + case TinyFrameNoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - TINY_FRAME_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + TINY_FRAME_NO_CRC_HEADER_SIZE; + state_ = TinyFrameNoCrcParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + TinyFrameNoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with TinyFrameNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t tiny_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = TINY_FRAME_NO_CRC_START_BYTE; + buffer[1] = msg_id; + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete TinyFrameNoCrc packet in a buffer + */ +inline FrameMsgInfo tiny_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < TINY_FRAME_NO_CRC_OVERHEAD) return result; + + if (buffer[0] != TINY_FRAME_NO_CRC_START_BYTE) return result; + + size_t msg_length = length - TINY_FRAME_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/TinyFrameWithLen.hpp b/src/struct_frame/boilerplate/cpp/TinyFrameWithLen.hpp new file mode 100644 index 00000000..92c762eb --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/TinyFrameWithLen.hpp @@ -0,0 +1,227 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// TinyFrameWithLen Frame Format +// ============================================================================= + +enum class TinyFrameWithLenParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingLength = 2, + GettingPayload = 3 +}; + +// TinyFrameWithLen constants +constexpr uint8_t TINY_FRAME_WITH_LEN_START_BYTE = 0x71; +constexpr size_t TINY_FRAME_WITH_LEN_HEADER_SIZE = 3; +constexpr size_t TINY_FRAME_WITH_LEN_FOOTER_SIZE = 2; +constexpr size_t TINY_FRAME_WITH_LEN_OVERHEAD = TINY_FRAME_WITH_LEN_HEADER_SIZE + TINY_FRAME_WITH_LEN_FOOTER_SIZE; +constexpr size_t TINY_FRAME_WITH_LEN_LENGTH_BYTES = 1; + +/** + * TinyFrameWithLen Encode Buffer + */ +class TinyFrameWithLenEncodeBuffer { +public: + TinyFrameWithLenEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = TINY_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = TINY_FRAME_WITH_LEN_START_BYTE; + packet_start[1] = msg_id; + packet_start[2] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + TINY_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 1); + packet_start[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * TinyFrameWithLen Frame Parser + */ +class TinyFrameWithLenParser { +public: + using MsgLengthCallback = std::function; + + TinyFrameWithLenParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(TinyFrameWithLenParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = TinyFrameWithLenParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case TinyFrameWithLenParserState::LookingForStart: + if (byte == TINY_FRAME_WITH_LEN_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = TinyFrameWithLenParserState::GettingMsgId; + } + break; + + case TinyFrameWithLenParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = TinyFrameWithLenParserState::GettingLength; + break; + } + + case TinyFrameWithLenParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = TINY_FRAME_WITH_LEN_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = TinyFrameWithLenParserState::GettingPayload; + } else { + state_ = TinyFrameWithLenParserState::LookingForStart; + } + break; + + case TinyFrameWithLenParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - TINY_FRAME_WITH_LEN_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + TINY_FRAME_WITH_LEN_HEADER_SIZE; + } + state_ = TinyFrameWithLenParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + TinyFrameWithLenParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with TinyFrameWithLen format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t tiny_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = TINY_FRAME_WITH_LEN_START_BYTE; + buffer[1] = msg_id; + buffer[2] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 1); + buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; + buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLen packet in a buffer + */ +inline FrameMsgInfo tiny_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < TINY_FRAME_WITH_LEN_OVERHEAD) return result; + + if (buffer[0] != TINY_FRAME_WITH_LEN_START_BYTE) return result; + + size_t msg_length = length - TINY_FRAME_WITH_LEN_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/TinyFrameWithLen16.hpp b/src/struct_frame/boilerplate/cpp/TinyFrameWithLen16.hpp new file mode 100644 index 00000000..2c7c8c32 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/TinyFrameWithLen16.hpp @@ -0,0 +1,235 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// TinyFrameWithLen16 Frame Format +// ============================================================================= + +enum class TinyFrameWithLen16ParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingLength = 2, + GettingPayload = 3 +}; + +// TinyFrameWithLen16 constants +constexpr uint8_t TINY_FRAME_WITH_LEN16_START_BYTE = 0x74; +constexpr size_t TINY_FRAME_WITH_LEN16_HEADER_SIZE = 4; +constexpr size_t TINY_FRAME_WITH_LEN16_FOOTER_SIZE = 2; +constexpr size_t TINY_FRAME_WITH_LEN16_OVERHEAD = TINY_FRAME_WITH_LEN16_HEADER_SIZE + TINY_FRAME_WITH_LEN16_FOOTER_SIZE; +constexpr size_t TINY_FRAME_WITH_LEN16_LENGTH_BYTES = 2; + +/** + * TinyFrameWithLen16 Encode Buffer + */ +class TinyFrameWithLen16EncodeBuffer { +public: + TinyFrameWithLen16EncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = TINY_FRAME_WITH_LEN16_START_BYTE; + packet_start[1] = msg_id; + packet_start[2] = static_cast(msg_size & 0xFF); + packet_start[3] = static_cast((msg_size >> 8) & 0xFF); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + TINY_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 2); + packet_start[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * TinyFrameWithLen16 Frame Parser + */ +class TinyFrameWithLen16Parser { +public: + using MsgLengthCallback = std::function; + + TinyFrameWithLen16Parser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(TinyFrameWithLen16ParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + length_lo_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = TinyFrameWithLen16ParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case TinyFrameWithLen16ParserState::LookingForStart: + if (byte == TINY_FRAME_WITH_LEN16_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = TinyFrameWithLen16ParserState::GettingMsgId; + } + break; + + case TinyFrameWithLen16ParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = TinyFrameWithLen16ParserState::GettingLength; + break; + } + + case TinyFrameWithLen16ParserState::GettingLength: + buffer_[buffer_index_++] = byte; + if (buffer_index_ == 3) { + length_lo_ = byte; + } else { + msg_length_ = length_lo_ | (static_cast(byte) << 8); + packet_size_ = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = TinyFrameWithLen16ParserState::GettingPayload; + } else { + state_ = TinyFrameWithLen16ParserState::LookingForStart; + } + } + break; + + case TinyFrameWithLen16ParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - TINY_FRAME_WITH_LEN16_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 2); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + TINY_FRAME_WITH_LEN16_HEADER_SIZE; + } + state_ = TinyFrameWithLen16ParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + TinyFrameWithLen16ParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + uint8_t length_lo_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with TinyFrameWithLen16 format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t tiny_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = TINY_FRAME_WITH_LEN16_START_BYTE; + buffer[1] = msg_id; + buffer[2] = static_cast(msg_size & 0xFF); + buffer[3] = static_cast((msg_size >> 8) & 0xFF); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 2); + buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; + buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLen16 packet in a buffer + */ +inline FrameMsgInfo tiny_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < TINY_FRAME_WITH_LEN16_OVERHEAD) return result; + + if (buffer[0] != TINY_FRAME_WITH_LEN16_START_BYTE) return result; + + size_t msg_length = length - TINY_FRAME_WITH_LEN16_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 2); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/TinyFrameWithLen16NoCrc.hpp b/src/struct_frame/boilerplate/cpp/TinyFrameWithLen16NoCrc.hpp new file mode 100644 index 00000000..b2a9db30 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/TinyFrameWithLen16NoCrc.hpp @@ -0,0 +1,218 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// TinyFrameWithLen16NoCrc Frame Format +// ============================================================================= + +enum class TinyFrameWithLen16NoCrcParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingLength = 2, + GettingPayload = 3 +}; + +// TinyFrameWithLen16NoCrc constants +constexpr uint8_t TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE = 0x75; +constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE = 4; +constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD = TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE; +constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_LENGTH_BYTES = 2; + +/** + * TinyFrameWithLen16NoCrc Encode Buffer + */ +class TinyFrameWithLen16NoCrcEncodeBuffer { +public: + TinyFrameWithLen16NoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE; + packet_start[1] = msg_id; + packet_start[2] = static_cast(msg_size & 0xFF); + packet_start[3] = static_cast((msg_size >> 8) & 0xFF); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * TinyFrameWithLen16NoCrc Frame Parser + */ +class TinyFrameWithLen16NoCrcParser { +public: + using MsgLengthCallback = std::function; + + TinyFrameWithLen16NoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(TinyFrameWithLen16NoCrcParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + length_lo_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = TinyFrameWithLen16NoCrcParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case TinyFrameWithLen16NoCrcParserState::LookingForStart: + if (byte == TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = TinyFrameWithLen16NoCrcParserState::GettingMsgId; + } + break; + + case TinyFrameWithLen16NoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = TinyFrameWithLen16NoCrcParserState::GettingLength; + break; + } + + case TinyFrameWithLen16NoCrcParserState::GettingLength: + buffer_[buffer_index_++] = byte; + if (buffer_index_ == 3) { + length_lo_ = byte; + } else { + msg_length_ = length_lo_ | (static_cast(byte) << 8); + packet_size_ = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = TinyFrameWithLen16NoCrcParserState::GettingPayload; + } else { + state_ = TinyFrameWithLen16NoCrcParserState::LookingForStart; + } + } + break; + + case TinyFrameWithLen16NoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; + state_ = TinyFrameWithLen16NoCrcParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + TinyFrameWithLen16NoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + uint8_t length_lo_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with TinyFrameWithLen16NoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t tiny_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE; + buffer[1] = msg_id; + buffer[2] = static_cast(msg_size & 0xFF); + buffer[3] = static_cast((msg_size >> 8) & 0xFF); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLen16NoCrc packet in a buffer + */ +inline FrameMsgInfo tiny_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) return result; + + if (buffer[0] != TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) return result; + + size_t msg_length = length - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/TinyFrameWithLenNoCrc.hpp b/src/struct_frame/boilerplate/cpp/TinyFrameWithLenNoCrc.hpp new file mode 100644 index 00000000..ebfe0674 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/TinyFrameWithLenNoCrc.hpp @@ -0,0 +1,210 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// TinyFrameWithLenNoCrc Frame Format +// ============================================================================= + +enum class TinyFrameWithLenNoCrcParserState : uint8_t { + LookingForStart = 0, + GettingMsgId = 1, + GettingLength = 2, + GettingPayload = 3 +}; + +// TinyFrameWithLenNoCrc constants +constexpr uint8_t TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE = 0x73; +constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE = 3; +constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE = 0; +constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD = TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE; +constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_LENGTH_BYTES = 1; + +/** + * TinyFrameWithLenNoCrc Encode Buffer + */ +class TinyFrameWithLenNoCrcEncodeBuffer { +public: + TinyFrameWithLenNoCrcEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE; + packet_start[1] = msg_id; + packet_start[2] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * TinyFrameWithLenNoCrc Frame Parser + */ +class TinyFrameWithLenNoCrcParser { +public: + using MsgLengthCallback = std::function; + + TinyFrameWithLenNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(TinyFrameWithLenNoCrcParserState::LookingForStart), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = TinyFrameWithLenNoCrcParserState::LookingForStart; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case TinyFrameWithLenNoCrcParserState::LookingForStart: + if (byte == TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = TinyFrameWithLenNoCrcParserState::GettingMsgId; + } + break; + + case TinyFrameWithLenNoCrcParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = TinyFrameWithLenNoCrcParserState::GettingLength; + break; + } + + case TinyFrameWithLenNoCrcParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = TinyFrameWithLenNoCrcParserState::GettingPayload; + } else { + state_ = TinyFrameWithLenNoCrcParserState::LookingForStart; + } + break; + + case TinyFrameWithLenNoCrcParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = packet_size_ - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + result.msg_data = buffer_ + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; + state_ = TinyFrameWithLenNoCrcParserState::LookingForStart; + } + break; + } + + return result; + } + +private: + TinyFrameWithLenNoCrcParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with TinyFrameWithLenNoCrc format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t tiny_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE; + buffer[1] = msg_id; + buffer[2] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); + } + + + return total_size; +} + +/** + * Validate a complete TinyFrameWithLenNoCrc packet in a buffer + */ +inline FrameMsgInfo tiny_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD) return result; + + if (buffer[0] != TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) return result; + + size_t msg_length = length - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/UbxFrame.hpp b/src/struct_frame/boilerplate/cpp/UbxFrame.hpp new file mode 100644 index 00000000..83bbf9bc --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/UbxFrame.hpp @@ -0,0 +1,246 @@ +/* Automatically generated frame parser */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include "frame_base.hpp" + +namespace FrameParsers { + +// ============================================================================= +// UbxFrame Frame Format +// ============================================================================= + +enum class UbxFrameParserState : uint8_t { + LookingForStart1 = 0, + LookingForStart2 = 1, + GettingMsgId = 2, + GettingLength = 3, + GettingPayload = 4 +}; + +// UbxFrame constants +constexpr uint8_t UBX_FRAME_START_BYTE1 = 0xB5; +constexpr uint8_t UBX_FRAME_START_BYTE2 = 0x62; +constexpr size_t UBX_FRAME_HEADER_SIZE = 5; +constexpr size_t UBX_FRAME_FOOTER_SIZE = 2; +constexpr size_t UBX_FRAME_OVERHEAD = UBX_FRAME_HEADER_SIZE + UBX_FRAME_FOOTER_SIZE; +constexpr size_t UBX_FRAME_LENGTH_BYTES = 1; + +/** + * UbxFrame Encode Buffer + */ +class UbxFrameEncodeBuffer { +public: + UbxFrameEncodeBuffer(uint8_t* data, size_t max_size) + : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} + + void reset() { + size_ = 0; + in_progress_ = false; + } + + uint8_t* data() { return data_; } + const uint8_t* data() const { return data_; } + size_t size() const { return size_; } + size_t max_size() const { return max_size_; } + bool in_progress() const { return in_progress_; } + + /** + * Encode a message into the buffer + */ + bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { + if (in_progress_) return false; + + size_t total_size = UBX_FRAME_OVERHEAD + msg_size; + if (size_ + total_size > max_size_) return false; + + uint8_t* packet_start = data_ + size_; + + // Write header + packet_start[0] = UBX_FRAME_START_BYTE1; + packet_start[1] = UBX_FRAME_START_BYTE2; + packet_start[2] = msg_id; + packet_start[3] = static_cast(msg_size); + + // Write message data + if (msg_size > 0 && msg != nullptr) { + std::memcpy(packet_start + UBX_FRAME_HEADER_SIZE, msg, msg_size); + } + + // Calculate checksum + FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1 + 1); + packet_start[UBX_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + packet_start[UBX_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + size_ += total_size; + return true; + } + +private: + uint8_t* data_; + size_t max_size_; + size_t size_; + bool in_progress_; +}; + +/** + * UbxFrame Frame Parser + */ +class UbxFrameParser { +public: + using MsgLengthCallback = std::function; + + UbxFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) + : state_(UbxFrameParserState::LookingForStart1), + buffer_(buffer), + buffer_max_size_(buffer_size), + buffer_index_(0), + packet_size_(0), + msg_id_(0), + msg_length_(0), + get_msg_length_(std::move(msg_length_cb)) {} + + void reset() { + state_ = UbxFrameParserState::LookingForStart1; + buffer_index_ = 0; + packet_size_ = 0; + msg_id_ = 0; + msg_length_ = 0; + } + + /** + * Parse a single byte + * Returns FrameMsgInfo with valid=true when a complete valid message is received + */ + FrameMsgInfo parse_byte(uint8_t byte) { + FrameMsgInfo result; + + switch (state_) { + case UbxFrameParserState::LookingForStart1: + if (byte == UBX_FRAME_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = UbxFrameParserState::LookingForStart2; + } + break; + + case UbxFrameParserState::LookingForStart2: + if (byte == UBX_FRAME_START_BYTE2) { + buffer_[1] = byte; + buffer_index_ = 2; + state_ = UbxFrameParserState::GettingMsgId; + } else if (byte == UBX_FRAME_START_BYTE1) { + buffer_[0] = byte; + buffer_index_ = 1; + state_ = UbxFrameParserState::LookingForStart2; + } else { + state_ = UbxFrameParserState::LookingForStart1; + } + break; + + case UbxFrameParserState::GettingMsgId: { + buffer_[buffer_index_++] = byte; + msg_id_ = byte; + + state_ = UbxFrameParserState::GettingLength; + break; + } + + case UbxFrameParserState::GettingLength: + buffer_[buffer_index_++] = byte; + msg_length_ = byte; + packet_size_ = UBX_FRAME_OVERHEAD + msg_length_; + if (packet_size_ <= buffer_max_size_) { + state_ = UbxFrameParserState::GettingPayload; + } else { + state_ = UbxFrameParserState::LookingForStart1; + } + break; + + case UbxFrameParserState::GettingPayload: + if (buffer_index_ < buffer_max_size_) { + buffer_[buffer_index_++] = byte; + } + + if (buffer_index_ >= packet_size_) { + // Validate checksum + size_t msg_length = packet_size_ - UBX_FRAME_OVERHEAD; + FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1 + 1); + + if (ck.byte1 == buffer_[packet_size_ - 2] && + ck.byte2 == buffer_[packet_size_ - 1]) { + result.valid = true; + result.msg_id = msg_id_; + result.msg_len = msg_length; + result.msg_data = buffer_ + UBX_FRAME_HEADER_SIZE; + } + state_ = UbxFrameParserState::LookingForStart1; + } + break; + } + + return result; + } + +private: + UbxFrameParserState state_; + uint8_t* buffer_; + size_t buffer_max_size_; + size_t buffer_index_; + size_t packet_size_; + uint8_t msg_id_; + size_t msg_length_; + MsgLengthCallback get_msg_length_; +}; + +/** + * Encode a message with UbxFrame format + * Returns the number of bytes written, or 0 on failure + */ +inline size_t ubx_frame_encode(uint8_t* buffer, size_t buffer_size, + uint8_t msg_id, const uint8_t* msg, size_t msg_size) { + size_t total_size = UBX_FRAME_OVERHEAD + msg_size; + if (buffer_size < total_size) return 0; + + buffer[0] = UBX_FRAME_START_BYTE1; + buffer[1] = UBX_FRAME_START_BYTE2; + buffer[2] = msg_id; + buffer[3] = static_cast(msg_size); + + if (msg_size > 0 && msg != nullptr) { + std::memcpy(buffer + UBX_FRAME_HEADER_SIZE, msg, msg_size); + } + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1 + 1); + buffer[UBX_FRAME_HEADER_SIZE + msg_size] = ck.byte1; + buffer[UBX_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; + + return total_size; +} + +/** + * Validate a complete UbxFrame packet in a buffer + */ +inline FrameMsgInfo ubx_frame_validate_packet(const uint8_t* buffer, size_t length) { + FrameMsgInfo result; + + if (length < UBX_FRAME_OVERHEAD) return result; + + if (buffer[0] != UBX_FRAME_START_BYTE1) return result; + if (buffer[1] != UBX_FRAME_START_BYTE2) return result; + + size_t msg_length = length - UBX_FRAME_OVERHEAD; + + FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1 + 1); + if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = const_cast(buffer + UBX_FRAME_HEADER_SIZE); + } + + return result; +} + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/frame_base.hpp b/src/struct_frame/boilerplate/cpp/frame_base.hpp new file mode 100644 index 00000000..27221c56 --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/frame_base.hpp @@ -0,0 +1,67 @@ +/* Automatically generated frame parser base utilities */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +#include +#include +#include +#include + +namespace FrameParsers { + +// Frame format type enumeration +enum class FrameFormatType { + MINIMAL_FRAME = 0, + BASIC_FRAME = 1, + BASIC_FRAME_NO_CRC = 2, + TINY_FRAME = 3, + TINY_FRAME_NO_CRC = 4, + MINIMAL_FRAME_WITH_LEN = 5, + MINIMAL_FRAME_WITH_LEN_NO_CRC = 6, + BASIC_FRAME_WITH_LEN = 7, + BASIC_FRAME_WITH_LEN_NO_CRC = 8, + TINY_FRAME_WITH_LEN = 9, + TINY_FRAME_WITH_LEN_NO_CRC = 10, + MINIMAL_FRAME_WITH_LEN16 = 11, + MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12, + BASIC_FRAME_WITH_LEN16 = 13, + BASIC_FRAME_WITH_LEN16_NO_CRC = 14, + TINY_FRAME_WITH_LEN16 = 15, + TINY_FRAME_WITH_LEN16_NO_CRC = 16, + BASIC_FRAME_WITH_SYS_COMP = 17, + UBX_FRAME = 18, + MAVLINK_V1_FRAME = 19, + MAVLINK_V2_FRAME = 20, + FRAME_FORMAT_CONFIG = 21, +}; + +// Checksum result +struct FrameChecksum { + uint8_t byte1; + uint8_t byte2; +}; + +// Fletcher-16 checksum calculation +inline FrameChecksum fletcher_checksum(const uint8_t* data, size_t length) { + FrameChecksum ck{0, 0}; + for (size_t i = 0; i < length; i++) { + ck.byte1 = static_cast(ck.byte1 + data[i]); + ck.byte2 = static_cast(ck.byte2 + ck.byte1); + } + return ck; +} + +// Parse result +struct FrameMsgInfo { + bool valid; + uint8_t msg_id; + size_t msg_len; + uint8_t* msg_data; + + FrameMsgInfo() : valid(false), msg_id(0), msg_len(0), msg_data(nullptr) {} + FrameMsgInfo(bool v, uint8_t id, size_t len, uint8_t* data) + : valid(v), msg_id(id), msg_len(len), msg_data(data) {} +}; + +} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/cpp/frame_parsers.hpp b/src/struct_frame/boilerplate/cpp/frame_parsers.hpp new file mode 100644 index 00000000..cd9f1b1e --- /dev/null +++ b/src/struct_frame/boilerplate/cpp/frame_parsers.hpp @@ -0,0 +1,31 @@ +/* Automatically generated frame parser main header */ +/* Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. */ + +#pragma once + +/* Base utilities */ +#include "frame_base.hpp" + +/* Individual frame format parsers */ +#include "MinimalFrame.hpp" +#include "BasicFrame.hpp" +#include "BasicFrameNoCrc.hpp" +#include "TinyFrame.hpp" +#include "TinyFrameNoCrc.hpp" +#include "MinimalFrameWithLen.hpp" +#include "MinimalFrameWithLenNoCrc.hpp" +#include "BasicFrameWithLen.hpp" +#include "BasicFrameWithLenNoCrc.hpp" +#include "TinyFrameWithLen.hpp" +#include "TinyFrameWithLenNoCrc.hpp" +#include "MinimalFrameWithLen16.hpp" +#include "MinimalFrameWithLen16NoCrc.hpp" +#include "BasicFrameWithLen16.hpp" +#include "BasicFrameWithLen16NoCrc.hpp" +#include "TinyFrameWithLen16.hpp" +#include "TinyFrameWithLen16NoCrc.hpp" +#include "BasicFrameWithSysComp.hpp" +#include "UbxFrame.hpp" +#include "MavlinkV1Frame.hpp" +#include "MavlinkV2Frame.hpp" +#include "FrameFormatConfig.hpp" diff --git a/src/struct_frame/boilerplate/cpp/frame_parsers_gen.hpp b/src/struct_frame/boilerplate/cpp/frame_parsers_gen.hpp deleted file mode 100644 index 6e665734..00000000 --- a/src/struct_frame/boilerplate/cpp/frame_parsers_gen.hpp +++ /dev/null @@ -1,4825 +0,0 @@ -/* Automatically generated frame parser header */ -/* Generated by 0.0.1 at Wed Dec 3 09:37:56 2025. */ - -#pragma once - -#include -#include -#include -#include - -namespace FrameParsers { - -// Frame format type enumeration -enum class FrameFormatType { - MINIMAL_FRAME = 0, - BASIC_FRAME = 1, - BASIC_FRAME_NO_CRC = 2, - TINY_FRAME = 3, - TINY_FRAME_NO_CRC = 4, - MINIMAL_FRAME_WITH_LEN = 5, - MINIMAL_FRAME_WITH_LEN_NO_CRC = 6, - BASIC_FRAME_WITH_LEN = 7, - BASIC_FRAME_WITH_LEN_NO_CRC = 8, - TINY_FRAME_WITH_LEN = 9, - TINY_FRAME_WITH_LEN_NO_CRC = 10, - MINIMAL_FRAME_WITH_LEN16 = 11, - MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12, - BASIC_FRAME_WITH_LEN16 = 13, - BASIC_FRAME_WITH_LEN16_NO_CRC = 14, - TINY_FRAME_WITH_LEN16 = 15, - TINY_FRAME_WITH_LEN16_NO_CRC = 16, - BASIC_FRAME_WITH_SYS_COMP = 17, - UBX_FRAME = 18, - MAVLINK_V1_FRAME = 19, - MAVLINK_V2_FRAME = 20, - FRAME_FORMAT_CONFIG = 21, -}; - -// Checksum result -struct FrameChecksum { - uint8_t byte1; - uint8_t byte2; -}; - -// Fletcher-16 checksum calculation -inline FrameChecksum fletcher_checksum(const uint8_t* data, size_t length) { - FrameChecksum ck{0, 0}; - for (size_t i = 0; i < length; i++) { - ck.byte1 = static_cast(ck.byte1 + data[i]); - ck.byte2 = static_cast(ck.byte2 + ck.byte1); - } - return ck; -} - -// Parse result -struct FrameMsgInfo { - bool valid; - uint8_t msg_id; - size_t msg_len; - uint8_t* msg_data; - - FrameMsgInfo() : valid(false), msg_id(0), msg_len(0), msg_data(nullptr) {} - FrameMsgInfo(bool v, uint8_t id, size_t len, uint8_t* data) - : valid(v), msg_id(id), msg_len(len), msg_data(data) {} -}; - -// ============================================================================= -// MinimalFrame Frame Format -// ============================================================================= - -enum class MinimalFrameParserState : uint8_t { - GettingMsgId = 0, - GettingPayload = 1 -}; - -// MinimalFrame constants -constexpr size_t MINIMAL_FRAME_HEADER_SIZE = 1; -constexpr size_t MINIMAL_FRAME_FOOTER_SIZE = 2; -constexpr size_t MINIMAL_FRAME_OVERHEAD = MINIMAL_FRAME_HEADER_SIZE + MINIMAL_FRAME_FOOTER_SIZE; - -/** - * MinimalFrame Encode Buffer - */ -class MinimalFrameEncodeBuffer { -public: - MinimalFrameEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MINIMAL_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MINIMAL_FRAME_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 0, msg_size + 1); - packet_start[MINIMAL_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[MINIMAL_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MinimalFrame Frame Parser - */ -class MinimalFrameParser { -public: - using MsgLengthCallback = std::function; - - MinimalFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MinimalFrameParserState::GettingMsgId), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MinimalFrameParserState::GettingMsgId; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MinimalFrameParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = MINIMAL_FRAME_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = MinimalFrameParserState::GettingPayload; - } else { - state_ = MinimalFrameParserState::GettingMsgId; - } - } else { - state_ = MinimalFrameParserState::GettingMsgId; - } - break; - } - - case MinimalFrameParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - MINIMAL_FRAME_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 0, msg_length + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + MINIMAL_FRAME_HEADER_SIZE; - } - state_ = MinimalFrameParserState::GettingMsgId; - } - break; - } - - return result; - } - -private: - MinimalFrameParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MinimalFrame format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t minimal_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MINIMAL_FRAME_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 0, msg_size + 1); - buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MINIMAL_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MinimalFrame packet in a buffer - */ -inline FrameMsgInfo minimal_frame_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MINIMAL_FRAME_OVERHEAD) return result; - - - size_t msg_length = length - MINIMAL_FRAME_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 0, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MINIMAL_FRAME_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// BasicFrame Frame Format -// ============================================================================= - -enum class BasicFrameParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingPayload = 3 -}; - -// BasicFrame constants -constexpr uint8_t BASIC_FRAME_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_START_BYTE2 = 0x91; -constexpr size_t BASIC_FRAME_HEADER_SIZE = 3; -constexpr size_t BASIC_FRAME_FOOTER_SIZE = 2; -constexpr size_t BASIC_FRAME_OVERHEAD = BASIC_FRAME_HEADER_SIZE + BASIC_FRAME_FOOTER_SIZE; - -/** - * BasicFrame Encode Buffer - */ -class BasicFrameEncodeBuffer { -public: - BasicFrameEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_START_BYTE1; - packet_start[1] = BASIC_FRAME_START_BYTE2; - packet_start[2] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1); - packet_start[BASIC_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[BASIC_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrame Frame Parser - */ -class BasicFrameParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameParserState::LookingForStart1: - if (byte == BASIC_FRAME_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameParserState::LookingForStart2; - } - break; - - case BasicFrameParserState::LookingForStart2: - if (byte == BASIC_FRAME_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameParserState::LookingForStart2; - } else { - state_ = BasicFrameParserState::LookingForStart1; - } - break; - - case BasicFrameParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = BASIC_FRAME_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameParserState::GettingPayload; - } else { - state_ = BasicFrameParserState::LookingForStart1; - } - } else { - state_ = BasicFrameParserState::LookingForStart1; - } - break; - } - - case BasicFrameParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - BASIC_FRAME_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + BASIC_FRAME_HEADER_SIZE; - } - state_ = BasicFrameParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrame format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_START_BYTE1; - buffer[1] = BASIC_FRAME_START_BYTE2; - buffer[2] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1); - buffer[BASIC_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrame packet in a buffer - */ -inline FrameMsgInfo basic_frame_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// BasicFrameNoCrc Frame Format -// ============================================================================= - -enum class BasicFrameNoCrcParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingPayload = 3 -}; - -// BasicFrameNoCrc constants -constexpr uint8_t BASIC_FRAME_NO_CRC_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_NO_CRC_START_BYTE2 = 0x95; -constexpr size_t BASIC_FRAME_NO_CRC_HEADER_SIZE = 3; -constexpr size_t BASIC_FRAME_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t BASIC_FRAME_NO_CRC_OVERHEAD = BASIC_FRAME_NO_CRC_HEADER_SIZE + BASIC_FRAME_NO_CRC_FOOTER_SIZE; - -/** - * BasicFrameNoCrc Encode Buffer - */ -class BasicFrameNoCrcEncodeBuffer { -public: - BasicFrameNoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_NO_CRC_START_BYTE1; - packet_start[1] = BASIC_FRAME_NO_CRC_START_BYTE2; - packet_start[2] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrameNoCrc Frame Parser - */ -class BasicFrameNoCrcParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameNoCrcParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameNoCrcParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameNoCrcParserState::LookingForStart1: - if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameNoCrcParserState::LookingForStart2; - } - break; - - case BasicFrameNoCrcParserState::LookingForStart2: - if (byte == BASIC_FRAME_NO_CRC_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameNoCrcParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_NO_CRC_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameNoCrcParserState::LookingForStart2; - } else { - state_ = BasicFrameNoCrcParserState::LookingForStart1; - } - break; - - case BasicFrameNoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = BASIC_FRAME_NO_CRC_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameNoCrcParserState::GettingPayload; - } else { - state_ = BasicFrameNoCrcParserState::LookingForStart1; - } - } else { - state_ = BasicFrameNoCrcParserState::LookingForStart1; - } - break; - } - - case BasicFrameNoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - BASIC_FRAME_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + BASIC_FRAME_NO_CRC_HEADER_SIZE; - state_ = BasicFrameNoCrcParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameNoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrameNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_NO_CRC_START_BYTE1; - buffer[1] = BASIC_FRAME_NO_CRC_START_BYTE2; - buffer[2] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete BasicFrameNoCrc packet in a buffer - */ -inline FrameMsgInfo basic_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_NO_CRC_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_NO_CRC_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_NO_CRC_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// TinyFrame Frame Format -// ============================================================================= - -enum class TinyFrameParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingPayload = 2 -}; - -// TinyFrame constants -constexpr uint8_t TINY_FRAME_START_BYTE = 0x70; -constexpr size_t TINY_FRAME_HEADER_SIZE = 2; -constexpr size_t TINY_FRAME_FOOTER_SIZE = 2; -constexpr size_t TINY_FRAME_OVERHEAD = TINY_FRAME_HEADER_SIZE + TINY_FRAME_FOOTER_SIZE; - -/** - * TinyFrame Encode Buffer - */ -class TinyFrameEncodeBuffer { -public: - TinyFrameEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = TINY_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = TINY_FRAME_START_BYTE; - packet_start[1] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + TINY_FRAME_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1); - packet_start[TINY_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[TINY_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * TinyFrame Frame Parser - */ -class TinyFrameParser { -public: - using MsgLengthCallback = std::function; - - TinyFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(TinyFrameParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = TinyFrameParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case TinyFrameParserState::LookingForStart: - if (byte == TINY_FRAME_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = TinyFrameParserState::GettingMsgId; - } - break; - - case TinyFrameParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = TINY_FRAME_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = TinyFrameParserState::GettingPayload; - } else { - state_ = TinyFrameParserState::LookingForStart; - } - } else { - state_ = TinyFrameParserState::LookingForStart; - } - break; - } - - case TinyFrameParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - TINY_FRAME_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + TINY_FRAME_HEADER_SIZE; - } - state_ = TinyFrameParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - TinyFrameParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with TinyFrame format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t tiny_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = TINY_FRAME_START_BYTE; - buffer[1] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + TINY_FRAME_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1); - buffer[TINY_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[TINY_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete TinyFrame packet in a buffer - */ -inline FrameMsgInfo tiny_frame_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < TINY_FRAME_OVERHEAD) return result; - - if (buffer[0] != TINY_FRAME_START_BYTE) return result; - - size_t msg_length = length - TINY_FRAME_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + TINY_FRAME_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// TinyFrameNoCrc Frame Format -// ============================================================================= - -enum class TinyFrameNoCrcParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingPayload = 2 -}; - -// TinyFrameNoCrc constants -constexpr uint8_t TINY_FRAME_NO_CRC_START_BYTE = 0x72; -constexpr size_t TINY_FRAME_NO_CRC_HEADER_SIZE = 2; -constexpr size_t TINY_FRAME_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t TINY_FRAME_NO_CRC_OVERHEAD = TINY_FRAME_NO_CRC_HEADER_SIZE + TINY_FRAME_NO_CRC_FOOTER_SIZE; - -/** - * TinyFrameNoCrc Encode Buffer - */ -class TinyFrameNoCrcEncodeBuffer { -public: - TinyFrameNoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = TINY_FRAME_NO_CRC_START_BYTE; - packet_start[1] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + TINY_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * TinyFrameNoCrc Frame Parser - */ -class TinyFrameNoCrcParser { -public: - using MsgLengthCallback = std::function; - - TinyFrameNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(TinyFrameNoCrcParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = TinyFrameNoCrcParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case TinyFrameNoCrcParserState::LookingForStart: - if (byte == TINY_FRAME_NO_CRC_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = TinyFrameNoCrcParserState::GettingMsgId; - } - break; - - case TinyFrameNoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = TINY_FRAME_NO_CRC_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = TinyFrameNoCrcParserState::GettingPayload; - } else { - state_ = TinyFrameNoCrcParserState::LookingForStart; - } - } else { - state_ = TinyFrameNoCrcParserState::LookingForStart; - } - break; - } - - case TinyFrameNoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - TINY_FRAME_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + TINY_FRAME_NO_CRC_HEADER_SIZE; - state_ = TinyFrameNoCrcParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - TinyFrameNoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with TinyFrameNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t tiny_frame_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = TINY_FRAME_NO_CRC_START_BYTE; - buffer[1] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete TinyFrameNoCrc packet in a buffer - */ -inline FrameMsgInfo tiny_frame_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < TINY_FRAME_NO_CRC_OVERHEAD) return result; - - if (buffer[0] != TINY_FRAME_NO_CRC_START_BYTE) return result; - - size_t msg_length = length - TINY_FRAME_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + TINY_FRAME_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// MinimalFrameWithLen Frame Format -// ============================================================================= - -enum class MinimalFrameWithLenParserState : uint8_t { - GettingMsgId = 0, - GettingLength = 1, - GettingPayload = 2 -}; - -// MinimalFrameWithLen constants -constexpr size_t MINIMAL_FRAME_WITH_LEN_HEADER_SIZE = 2; -constexpr size_t MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE = 2; -constexpr size_t MINIMAL_FRAME_WITH_LEN_OVERHEAD = MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_FOOTER_SIZE; -constexpr size_t MINIMAL_FRAME_WITH_LEN_LENGTH_BYTES = 1; - -/** - * MinimalFrameWithLen Encode Buffer - */ -class MinimalFrameWithLenEncodeBuffer { -public: - MinimalFrameWithLenEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = msg_id; - packet_start[1] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 0, msg_size + 1 + 1); - packet_start[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MinimalFrameWithLen Frame Parser - */ -class MinimalFrameWithLenParser { -public: - using MsgLengthCallback = std::function; - - MinimalFrameWithLenParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MinimalFrameWithLenParserState::GettingMsgId), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MinimalFrameWithLenParserState::GettingMsgId; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MinimalFrameWithLenParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = MinimalFrameWithLenParserState::GettingLength; - break; - } - - case MinimalFrameWithLenParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = MinimalFrameWithLenParserState::GettingPayload; - } else { - state_ = MinimalFrameWithLenParserState::GettingMsgId; - } - break; - - case MinimalFrameWithLenParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - MINIMAL_FRAME_WITH_LEN_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 0, msg_length + 1 + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE; - } - state_ = MinimalFrameWithLenParserState::GettingMsgId; - } - break; - } - - return result; - } - -private: - MinimalFrameWithLenParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MinimalFrameWithLen format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t minimal_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = msg_id; - buffer[1] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 0, msg_size + 1 + 1); - buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MINIMAL_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLen packet in a buffer - */ -inline FrameMsgInfo minimal_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MINIMAL_FRAME_WITH_LEN_OVERHEAD) return result; - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 0, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// MinimalFrameWithLenNoCrc Frame Format -// ============================================================================= - -enum class MinimalFrameWithLenNoCrcParserState : uint8_t { - GettingMsgId = 0, - GettingLength = 1, - GettingPayload = 2 -}; - -// MinimalFrameWithLenNoCrc constants -constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE = 2; -constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD = MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE; -constexpr size_t MINIMAL_FRAME_WITH_LEN_NO_CRC_LENGTH_BYTES = 1; - -/** - * MinimalFrameWithLenNoCrc Encode Buffer - */ -class MinimalFrameWithLenNoCrcEncodeBuffer { -public: - MinimalFrameWithLenNoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = msg_id; - packet_start[1] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MinimalFrameWithLenNoCrc Frame Parser - */ -class MinimalFrameWithLenNoCrcParser { -public: - using MsgLengthCallback = std::function; - - MinimalFrameWithLenNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MinimalFrameWithLenNoCrcParserState::GettingMsgId), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MinimalFrameWithLenNoCrcParserState::GettingMsgId; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MinimalFrameWithLenNoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = MinimalFrameWithLenNoCrcParserState::GettingLength; - break; - } - - case MinimalFrameWithLenNoCrcParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = MinimalFrameWithLenNoCrcParserState::GettingPayload; - } else { - state_ = MinimalFrameWithLenNoCrcParserState::GettingMsgId; - } - break; - - case MinimalFrameWithLenNoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; - state_ = MinimalFrameWithLenNoCrcParserState::GettingMsgId; - } - break; - } - - return result; - } - -private: - MinimalFrameWithLenNoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MinimalFrameWithLenNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t minimal_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = msg_id; - buffer[1] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLenNoCrc packet in a buffer - */ -inline FrameMsgInfo minimal_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD) return result; - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// BasicFrameWithLen Frame Format -// ============================================================================= - -enum class BasicFrameWithLenParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingLength = 3, - GettingPayload = 4 -}; - -// BasicFrameWithLen constants -constexpr uint8_t BASIC_FRAME_WITH_LEN_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_WITH_LEN_START_BYTE2 = 0x92; -constexpr size_t BASIC_FRAME_WITH_LEN_HEADER_SIZE = 4; -constexpr size_t BASIC_FRAME_WITH_LEN_FOOTER_SIZE = 2; -constexpr size_t BASIC_FRAME_WITH_LEN_OVERHEAD = BASIC_FRAME_WITH_LEN_HEADER_SIZE + BASIC_FRAME_WITH_LEN_FOOTER_SIZE; -constexpr size_t BASIC_FRAME_WITH_LEN_LENGTH_BYTES = 1; - -/** - * BasicFrameWithLen Encode Buffer - */ -class BasicFrameWithLenEncodeBuffer { -public: - BasicFrameWithLenEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; - packet_start[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; - packet_start[2] = msg_id; - packet_start[3] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1 + 1); - packet_start[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrameWithLen Frame Parser - */ -class BasicFrameWithLenParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameWithLenParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameWithLenParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameWithLenParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameWithLenParserState::LookingForStart1: - if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLenParserState::LookingForStart2; - } - break; - - case BasicFrameWithLenParserState::LookingForStart2: - if (byte == BASIC_FRAME_WITH_LEN_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameWithLenParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_WITH_LEN_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLenParserState::LookingForStart2; - } else { - state_ = BasicFrameWithLenParserState::LookingForStart1; - } - break; - - case BasicFrameWithLenParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = BasicFrameWithLenParserState::GettingLength; - break; - } - - case BasicFrameWithLenParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameWithLenParserState::GettingPayload; - } else { - state_ = BasicFrameWithLenParserState::LookingForStart1; - } - break; - - case BasicFrameWithLenParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - BASIC_FRAME_WITH_LEN_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1 + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN_HEADER_SIZE; - } - state_ = BasicFrameWithLenParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameWithLenParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrameWithLen format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1 + 1); - buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLen packet in a buffer - */ -inline FrameMsgInfo basic_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_WITH_LEN_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_WITH_LEN_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_WITH_LEN_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_WITH_LEN_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// BasicFrameWithLenNoCrc Frame Format -// ============================================================================= - -enum class BasicFrameWithLenNoCrcParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingLength = 3, - GettingPayload = 4 -}; - -// BasicFrameWithLenNoCrc constants -constexpr uint8_t BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2 = 0x96; -constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE = 4; -constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD = BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE; -constexpr size_t BASIC_FRAME_WITH_LEN_NO_CRC_LENGTH_BYTES = 1; - -/** - * BasicFrameWithLenNoCrc Encode Buffer - */ -class BasicFrameWithLenNoCrcEncodeBuffer { -public: - BasicFrameWithLenNoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1; - packet_start[1] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2; - packet_start[2] = msg_id; - packet_start[3] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrameWithLenNoCrc Frame Parser - */ -class BasicFrameWithLenNoCrcParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameWithLenNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameWithLenNoCrcParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameWithLenNoCrcParserState::LookingForStart1: - if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLenNoCrcParserState::LookingForStart2; - } - break; - - case BasicFrameWithLenNoCrcParserState::LookingForStart2: - if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameWithLenNoCrcParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLenNoCrcParserState::LookingForStart2; - } else { - state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; - } - break; - - case BasicFrameWithLenNoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = BasicFrameWithLenNoCrcParserState::GettingLength; - break; - } - - case BasicFrameWithLenNoCrcParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameWithLenNoCrcParserState::GettingPayload; - } else { - state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; - } - break; - - case BasicFrameWithLenNoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; - state_ = BasicFrameWithLenNoCrcParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameWithLenNoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrameWithLenNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLenNoCrc packet in a buffer - */ -inline FrameMsgInfo basic_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_WITH_LEN_NO_CRC_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// TinyFrameWithLen Frame Format -// ============================================================================= - -enum class TinyFrameWithLenParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingLength = 2, - GettingPayload = 3 -}; - -// TinyFrameWithLen constants -constexpr uint8_t TINY_FRAME_WITH_LEN_START_BYTE = 0x71; -constexpr size_t TINY_FRAME_WITH_LEN_HEADER_SIZE = 3; -constexpr size_t TINY_FRAME_WITH_LEN_FOOTER_SIZE = 2; -constexpr size_t TINY_FRAME_WITH_LEN_OVERHEAD = TINY_FRAME_WITH_LEN_HEADER_SIZE + TINY_FRAME_WITH_LEN_FOOTER_SIZE; -constexpr size_t TINY_FRAME_WITH_LEN_LENGTH_BYTES = 1; - -/** - * TinyFrameWithLen Encode Buffer - */ -class TinyFrameWithLenEncodeBuffer { -public: - TinyFrameWithLenEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = TINY_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = TINY_FRAME_WITH_LEN_START_BYTE; - packet_start[1] = msg_id; - packet_start[2] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + TINY_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 1); - packet_start[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * TinyFrameWithLen Frame Parser - */ -class TinyFrameWithLenParser { -public: - using MsgLengthCallback = std::function; - - TinyFrameWithLenParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(TinyFrameWithLenParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = TinyFrameWithLenParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case TinyFrameWithLenParserState::LookingForStart: - if (byte == TINY_FRAME_WITH_LEN_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = TinyFrameWithLenParserState::GettingMsgId; - } - break; - - case TinyFrameWithLenParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = TinyFrameWithLenParserState::GettingLength; - break; - } - - case TinyFrameWithLenParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = TINY_FRAME_WITH_LEN_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = TinyFrameWithLenParserState::GettingPayload; - } else { - state_ = TinyFrameWithLenParserState::LookingForStart; - } - break; - - case TinyFrameWithLenParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - TINY_FRAME_WITH_LEN_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + TINY_FRAME_WITH_LEN_HEADER_SIZE; - } - state_ = TinyFrameWithLenParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - TinyFrameWithLenParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with TinyFrameWithLen format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t tiny_frame_with_len_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = TINY_FRAME_WITH_LEN_START_BYTE; - buffer[1] = msg_id; - buffer[2] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 1); - buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size] = ck.byte1; - buffer[TINY_FRAME_WITH_LEN_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLen packet in a buffer - */ -inline FrameMsgInfo tiny_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < TINY_FRAME_WITH_LEN_OVERHEAD) return result; - - if (buffer[0] != TINY_FRAME_WITH_LEN_START_BYTE) return result; - - size_t msg_length = length - TINY_FRAME_WITH_LEN_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// TinyFrameWithLenNoCrc Frame Format -// ============================================================================= - -enum class TinyFrameWithLenNoCrcParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingLength = 2, - GettingPayload = 3 -}; - -// TinyFrameWithLenNoCrc constants -constexpr uint8_t TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE = 0x73; -constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE = 3; -constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD = TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN_NO_CRC_FOOTER_SIZE; -constexpr size_t TINY_FRAME_WITH_LEN_NO_CRC_LENGTH_BYTES = 1; - -/** - * TinyFrameWithLenNoCrc Encode Buffer - */ -class TinyFrameWithLenNoCrcEncodeBuffer { -public: - TinyFrameWithLenNoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE; - packet_start[1] = msg_id; - packet_start[2] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * TinyFrameWithLenNoCrc Frame Parser - */ -class TinyFrameWithLenNoCrcParser { -public: - using MsgLengthCallback = std::function; - - TinyFrameWithLenNoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(TinyFrameWithLenNoCrcParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = TinyFrameWithLenNoCrcParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case TinyFrameWithLenNoCrcParserState::LookingForStart: - if (byte == TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = TinyFrameWithLenNoCrcParserState::GettingMsgId; - } - break; - - case TinyFrameWithLenNoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = TinyFrameWithLenNoCrcParserState::GettingLength; - break; - } - - case TinyFrameWithLenNoCrcParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = TinyFrameWithLenNoCrcParserState::GettingPayload; - } else { - state_ = TinyFrameWithLenNoCrcParserState::LookingForStart; - } - break; - - case TinyFrameWithLenNoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE; - state_ = TinyFrameWithLenNoCrcParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - TinyFrameWithLenNoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with TinyFrameWithLenNoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t tiny_frame_with_len_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE; - buffer[1] = msg_id; - buffer[2] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLenNoCrc packet in a buffer - */ -inline FrameMsgInfo tiny_frame_with_len_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD) return result; - - if (buffer[0] != TINY_FRAME_WITH_LEN_NO_CRC_START_BYTE) return result; - - size_t msg_length = length - TINY_FRAME_WITH_LEN_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// MinimalFrameWithLen16 Frame Format -// ============================================================================= - -enum class MinimalFrameWithLen16ParserState : uint8_t { - GettingMsgId = 0, - GettingLength = 1, - GettingPayload = 2 -}; - -// MinimalFrameWithLen16 constants -constexpr size_t MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE = 3; -constexpr size_t MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE = 2; -constexpr size_t MINIMAL_FRAME_WITH_LEN16_OVERHEAD = MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_FOOTER_SIZE; -constexpr size_t MINIMAL_FRAME_WITH_LEN16_LENGTH_BYTES = 2; - -/** - * MinimalFrameWithLen16 Encode Buffer - */ -class MinimalFrameWithLen16EncodeBuffer { -public: - MinimalFrameWithLen16EncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = msg_id; - packet_start[1] = static_cast(msg_size & 0xFF); - packet_start[2] = static_cast((msg_size >> 8) & 0xFF); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 0, msg_size + 1 + 2); - packet_start[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MinimalFrameWithLen16 Frame Parser - */ -class MinimalFrameWithLen16Parser { -public: - using MsgLengthCallback = std::function; - - MinimalFrameWithLen16Parser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MinimalFrameWithLen16ParserState::GettingMsgId), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - length_lo_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MinimalFrameWithLen16ParserState::GettingMsgId; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MinimalFrameWithLen16ParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = MinimalFrameWithLen16ParserState::GettingLength; - break; - } - - case MinimalFrameWithLen16ParserState::GettingLength: - buffer_[buffer_index_++] = byte; - if (buffer_index_ == 2) { - length_lo_ = byte; - } else { - msg_length_ = length_lo_ | (static_cast(byte) << 8); - packet_size_ = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = MinimalFrameWithLen16ParserState::GettingPayload; - } else { - state_ = MinimalFrameWithLen16ParserState::GettingMsgId; - } - } - break; - - case MinimalFrameWithLen16ParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 0, msg_length + 1 + 2); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE; - } - state_ = MinimalFrameWithLen16ParserState::GettingMsgId; - } - break; - } - - return result; - } - -private: - MinimalFrameWithLen16ParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - uint8_t length_lo_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MinimalFrameWithLen16 format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t minimal_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = msg_id; - buffer[1] = static_cast(msg_size & 0xFF); - buffer[2] = static_cast((msg_size >> 8) & 0xFF); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 0, msg_size + 1 + 2); - buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLen16 packet in a buffer - */ -inline FrameMsgInfo minimal_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MINIMAL_FRAME_WITH_LEN16_OVERHEAD) return result; - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 0, msg_length + 1 + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN16_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// MinimalFrameWithLen16NoCrc Frame Format -// ============================================================================= - -enum class MinimalFrameWithLen16NoCrcParserState : uint8_t { - GettingMsgId = 0, - GettingLength = 1, - GettingPayload = 2 -}; - -// MinimalFrameWithLen16NoCrc constants -constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE = 3; -constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD = MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + MINIMAL_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE; -constexpr size_t MINIMAL_FRAME_WITH_LEN16_NO_CRC_LENGTH_BYTES = 2; - -/** - * MinimalFrameWithLen16NoCrc Encode Buffer - */ -class MinimalFrameWithLen16NoCrcEncodeBuffer { -public: - MinimalFrameWithLen16NoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = msg_id; - packet_start[1] = static_cast(msg_size & 0xFF); - packet_start[2] = static_cast((msg_size >> 8) & 0xFF); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MinimalFrameWithLen16NoCrc Frame Parser - */ -class MinimalFrameWithLen16NoCrcParser { -public: - using MsgLengthCallback = std::function; - - MinimalFrameWithLen16NoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MinimalFrameWithLen16NoCrcParserState::GettingMsgId), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - length_lo_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MinimalFrameWithLen16NoCrcParserState::GettingMsgId; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MinimalFrameWithLen16NoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = MinimalFrameWithLen16NoCrcParserState::GettingLength; - break; - } - - case MinimalFrameWithLen16NoCrcParserState::GettingLength: - buffer_[buffer_index_++] = byte; - if (buffer_index_ == 2) { - length_lo_ = byte; - } else { - msg_length_ = length_lo_ | (static_cast(byte) << 8); - packet_size_ = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = MinimalFrameWithLen16NoCrcParserState::GettingPayload; - } else { - state_ = MinimalFrameWithLen16NoCrcParserState::GettingMsgId; - } - } - break; - - case MinimalFrameWithLen16NoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; - state_ = MinimalFrameWithLen16NoCrcParserState::GettingMsgId; - } - break; - } - - return result; - } - -private: - MinimalFrameWithLen16NoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - uint8_t length_lo_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MinimalFrameWithLen16NoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t minimal_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = msg_id; - buffer[1] = static_cast(msg_size & 0xFF); - buffer[2] = static_cast((msg_size >> 8) & 0xFF); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer - */ -inline FrameMsgInfo minimal_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) return result; - - - size_t msg_length = length - MINIMAL_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MINIMAL_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// BasicFrameWithLen16 Frame Format -// ============================================================================= - -enum class BasicFrameWithLen16ParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingLength = 3, - GettingPayload = 4 -}; - -// BasicFrameWithLen16 constants -constexpr uint8_t BASIC_FRAME_WITH_LEN16_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_WITH_LEN16_START_BYTE2 = 0x93; -constexpr size_t BASIC_FRAME_WITH_LEN16_HEADER_SIZE = 5; -constexpr size_t BASIC_FRAME_WITH_LEN16_FOOTER_SIZE = 2; -constexpr size_t BASIC_FRAME_WITH_LEN16_OVERHEAD = BASIC_FRAME_WITH_LEN16_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_FOOTER_SIZE; -constexpr size_t BASIC_FRAME_WITH_LEN16_LENGTH_BYTES = 2; - -/** - * BasicFrameWithLen16 Encode Buffer - */ -class BasicFrameWithLen16EncodeBuffer { -public: - BasicFrameWithLen16EncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_WITH_LEN16_START_BYTE1; - packet_start[1] = BASIC_FRAME_WITH_LEN16_START_BYTE2; - packet_start[2] = msg_id; - packet_start[3] = static_cast(msg_size & 0xFF); - packet_start[4] = static_cast((msg_size >> 8) & 0xFF); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1 + 2); - packet_start[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrameWithLen16 Frame Parser - */ -class BasicFrameWithLen16Parser { -public: - using MsgLengthCallback = std::function; - - BasicFrameWithLen16Parser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameWithLen16ParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - length_lo_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameWithLen16ParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameWithLen16ParserState::LookingForStart1: - if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLen16ParserState::LookingForStart2; - } - break; - - case BasicFrameWithLen16ParserState::LookingForStart2: - if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameWithLen16ParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_WITH_LEN16_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLen16ParserState::LookingForStart2; - } else { - state_ = BasicFrameWithLen16ParserState::LookingForStart1; - } - break; - - case BasicFrameWithLen16ParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = BasicFrameWithLen16ParserState::GettingLength; - break; - } - - case BasicFrameWithLen16ParserState::GettingLength: - buffer_[buffer_index_++] = byte; - if (buffer_index_ == 4) { - length_lo_ = byte; - } else { - msg_length_ = length_lo_ | (static_cast(byte) << 8); - packet_size_ = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameWithLen16ParserState::GettingPayload; - } else { - state_ = BasicFrameWithLen16ParserState::LookingForStart1; - } - } - break; - - case BasicFrameWithLen16ParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - BASIC_FRAME_WITH_LEN16_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1 + 2); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN16_HEADER_SIZE; - } - state_ = BasicFrameWithLen16ParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameWithLen16ParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - uint8_t length_lo_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrameWithLen16 format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_WITH_LEN16_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN16_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = static_cast(msg_size & 0xFF); - buffer[4] = static_cast((msg_size >> 8) & 0xFF); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1 + 2); - buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLen16 packet in a buffer - */ -inline FrameMsgInfo basic_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_WITH_LEN16_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_WITH_LEN16_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_WITH_LEN16_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_WITH_LEN16_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1 + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN16_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// BasicFrameWithLen16NoCrc Frame Format -// ============================================================================= - -enum class BasicFrameWithLen16NoCrcParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingLength = 3, - GettingPayload = 4 -}; - -// BasicFrameWithLen16NoCrc constants -constexpr uint8_t BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2 = 0x97; -constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE = 5; -constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD = BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + BASIC_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE; -constexpr size_t BASIC_FRAME_WITH_LEN16_NO_CRC_LENGTH_BYTES = 2; - -/** - * BasicFrameWithLen16NoCrc Encode Buffer - */ -class BasicFrameWithLen16NoCrcEncodeBuffer { -public: - BasicFrameWithLen16NoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1; - packet_start[1] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2; - packet_start[2] = msg_id; - packet_start[3] = static_cast(msg_size & 0xFF); - packet_start[4] = static_cast((msg_size >> 8) & 0xFF); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrameWithLen16NoCrc Frame Parser - */ -class BasicFrameWithLen16NoCrcParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameWithLen16NoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameWithLen16NoCrcParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - length_lo_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameWithLen16NoCrcParserState::LookingForStart1: - if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart2; - } - break; - - case BasicFrameWithLen16NoCrcParserState::LookingForStart2: - if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameWithLen16NoCrcParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart2; - } else { - state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; - } - break; - - case BasicFrameWithLen16NoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = BasicFrameWithLen16NoCrcParserState::GettingLength; - break; - } - - case BasicFrameWithLen16NoCrcParserState::GettingLength: - buffer_[buffer_index_++] = byte; - if (buffer_index_ == 4) { - length_lo_ = byte; - } else { - msg_length_ = length_lo_ | (static_cast(byte) << 8); - packet_size_ = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameWithLen16NoCrcParserState::GettingPayload; - } else { - state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; - } - } - break; - - case BasicFrameWithLen16NoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; - state_ = BasicFrameWithLen16NoCrcParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameWithLen16NoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - uint8_t length_lo_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrameWithLen16NoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = static_cast(msg_size & 0xFF); - buffer[4] = static_cast((msg_size >> 8) & 0xFF); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete BasicFrameWithLen16NoCrc packet in a buffer - */ -inline FrameMsgInfo basic_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_WITH_LEN16_NO_CRC_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// TinyFrameWithLen16 Frame Format -// ============================================================================= - -enum class TinyFrameWithLen16ParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingLength = 2, - GettingPayload = 3 -}; - -// TinyFrameWithLen16 constants -constexpr uint8_t TINY_FRAME_WITH_LEN16_START_BYTE = 0x74; -constexpr size_t TINY_FRAME_WITH_LEN16_HEADER_SIZE = 4; -constexpr size_t TINY_FRAME_WITH_LEN16_FOOTER_SIZE = 2; -constexpr size_t TINY_FRAME_WITH_LEN16_OVERHEAD = TINY_FRAME_WITH_LEN16_HEADER_SIZE + TINY_FRAME_WITH_LEN16_FOOTER_SIZE; -constexpr size_t TINY_FRAME_WITH_LEN16_LENGTH_BYTES = 2; - -/** - * TinyFrameWithLen16 Encode Buffer - */ -class TinyFrameWithLen16EncodeBuffer { -public: - TinyFrameWithLen16EncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = TINY_FRAME_WITH_LEN16_START_BYTE; - packet_start[1] = msg_id; - packet_start[2] = static_cast(msg_size & 0xFF); - packet_start[3] = static_cast((msg_size >> 8) & 0xFF); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + TINY_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 2); - packet_start[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * TinyFrameWithLen16 Frame Parser - */ -class TinyFrameWithLen16Parser { -public: - using MsgLengthCallback = std::function; - - TinyFrameWithLen16Parser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(TinyFrameWithLen16ParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - length_lo_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = TinyFrameWithLen16ParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case TinyFrameWithLen16ParserState::LookingForStart: - if (byte == TINY_FRAME_WITH_LEN16_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = TinyFrameWithLen16ParserState::GettingMsgId; - } - break; - - case TinyFrameWithLen16ParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = TinyFrameWithLen16ParserState::GettingLength; - break; - } - - case TinyFrameWithLen16ParserState::GettingLength: - buffer_[buffer_index_++] = byte; - if (buffer_index_ == 3) { - length_lo_ = byte; - } else { - msg_length_ = length_lo_ | (static_cast(byte) << 8); - packet_size_ = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = TinyFrameWithLen16ParserState::GettingPayload; - } else { - state_ = TinyFrameWithLen16ParserState::LookingForStart; - } - } - break; - - case TinyFrameWithLen16ParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - TINY_FRAME_WITH_LEN16_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 2); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + TINY_FRAME_WITH_LEN16_HEADER_SIZE; - } - state_ = TinyFrameWithLen16ParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - TinyFrameWithLen16ParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - uint8_t length_lo_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with TinyFrameWithLen16 format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t tiny_frame_with_len16_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN16_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = TINY_FRAME_WITH_LEN16_START_BYTE; - buffer[1] = msg_id; - buffer[2] = static_cast(msg_size & 0xFF); - buffer[3] = static_cast((msg_size >> 8) & 0xFF); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 2); - buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size] = ck.byte1; - buffer[TINY_FRAME_WITH_LEN16_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLen16 packet in a buffer - */ -inline FrameMsgInfo tiny_frame_with_len16_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < TINY_FRAME_WITH_LEN16_OVERHEAD) return result; - - if (buffer[0] != TINY_FRAME_WITH_LEN16_START_BYTE) return result; - - size_t msg_length = length - TINY_FRAME_WITH_LEN16_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN16_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// TinyFrameWithLen16NoCrc Frame Format -// ============================================================================= - -enum class TinyFrameWithLen16NoCrcParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingLength = 2, - GettingPayload = 3 -}; - -// TinyFrameWithLen16NoCrc constants -constexpr uint8_t TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE = 0x75; -constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE = 4; -constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE = 0; -constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD = TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE + TINY_FRAME_WITH_LEN16_NO_CRC_FOOTER_SIZE; -constexpr size_t TINY_FRAME_WITH_LEN16_NO_CRC_LENGTH_BYTES = 2; - -/** - * TinyFrameWithLen16NoCrc Encode Buffer - */ -class TinyFrameWithLen16NoCrcEncodeBuffer { -public: - TinyFrameWithLen16NoCrcEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE; - packet_start[1] = msg_id; - packet_start[2] = static_cast(msg_size & 0xFF); - packet_start[3] = static_cast((msg_size >> 8) & 0xFF); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * TinyFrameWithLen16NoCrc Frame Parser - */ -class TinyFrameWithLen16NoCrcParser { -public: - using MsgLengthCallback = std::function; - - TinyFrameWithLen16NoCrcParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(TinyFrameWithLen16NoCrcParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - length_lo_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = TinyFrameWithLen16NoCrcParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case TinyFrameWithLen16NoCrcParserState::LookingForStart: - if (byte == TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = TinyFrameWithLen16NoCrcParserState::GettingMsgId; - } - break; - - case TinyFrameWithLen16NoCrcParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = TinyFrameWithLen16NoCrcParserState::GettingLength; - break; - } - - case TinyFrameWithLen16NoCrcParserState::GettingLength: - buffer_[buffer_index_++] = byte; - if (buffer_index_ == 3) { - length_lo_ = byte; - } else { - msg_length_ = length_lo_ | (static_cast(byte) << 8); - packet_size_ = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = TinyFrameWithLen16NoCrcParserState::GettingPayload; - } else { - state_ = TinyFrameWithLen16NoCrcParserState::LookingForStart; - } - } - break; - - case TinyFrameWithLen16NoCrcParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = packet_size_ - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - result.msg_data = buffer_ + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE; - state_ = TinyFrameWithLen16NoCrcParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - TinyFrameWithLen16NoCrcParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - uint8_t length_lo_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with TinyFrameWithLen16NoCrc format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t tiny_frame_with_len16_no_crc_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE; - buffer[1] = msg_id; - buffer[2] = static_cast(msg_size & 0xFF); - buffer[3] = static_cast((msg_size >> 8) & 0xFF); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE, msg, msg_size); - } - - - return total_size; -} - -/** - * Validate a complete TinyFrameWithLen16NoCrc packet in a buffer - */ -inline FrameMsgInfo tiny_frame_with_len16_no_crc_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD) return result; - - if (buffer[0] != TINY_FRAME_WITH_LEN16_NO_CRC_START_BYTE) return result; - - size_t msg_length = length - TINY_FRAME_WITH_LEN16_NO_CRC_OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + TINY_FRAME_WITH_LEN16_NO_CRC_HEADER_SIZE); - - return result; -} - - -// ============================================================================= -// BasicFrameWithSysComp Frame Format -// ============================================================================= - -enum class BasicFrameWithSysCompParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingPayload = 3 -}; - -// BasicFrameWithSysComp constants -constexpr uint8_t BASIC_FRAME_WITH_SYS_COMP_START_BYTE1 = 0x90; -constexpr uint8_t BASIC_FRAME_WITH_SYS_COMP_START_BYTE2 = 0x94; -constexpr size_t BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE = 3; -constexpr size_t BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE = 2; -constexpr size_t BASIC_FRAME_WITH_SYS_COMP_OVERHEAD = BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + BASIC_FRAME_WITH_SYS_COMP_FOOTER_SIZE; - -/** - * BasicFrameWithSysComp Encode Buffer - */ -class BasicFrameWithSysCompEncodeBuffer { -public: - BasicFrameWithSysCompEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE1; - packet_start[1] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE2; - packet_start[2] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1); - packet_start[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * BasicFrameWithSysComp Frame Parser - */ -class BasicFrameWithSysCompParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameWithSysCompParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(BasicFrameWithSysCompParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = BasicFrameWithSysCompParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case BasicFrameWithSysCompParserState::LookingForStart1: - if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithSysCompParserState::LookingForStart2; - } - break; - - case BasicFrameWithSysCompParserState::LookingForStart2: - if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = BasicFrameWithSysCompParserState::GettingMsgId; - } else if (byte == BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = BasicFrameWithSysCompParserState::LookingForStart2; - } else { - state_ = BasicFrameWithSysCompParserState::LookingForStart1; - } - break; - - case BasicFrameWithSysCompParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = BasicFrameWithSysCompParserState::GettingPayload; - } else { - state_ = BasicFrameWithSysCompParserState::LookingForStart1; - } - } else { - state_ = BasicFrameWithSysCompParserState::LookingForStart1; - } - break; - } - - case BasicFrameWithSysCompParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE; - } - state_ = BasicFrameWithSysCompParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - BasicFrameWithSysCompParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with BasicFrameWithSysComp format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t basic_frame_with_sys_comp_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_SYS_COMP_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_SYS_COMP_START_BYTE2; - buffer[2] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1); - buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size] = ck.byte1; - buffer[BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete BasicFrameWithSysComp packet in a buffer - */ -inline FrameMsgInfo basic_frame_with_sys_comp_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < BASIC_FRAME_WITH_SYS_COMP_OVERHEAD) return result; - - if (buffer[0] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE1) return result; - if (buffer[1] != BASIC_FRAME_WITH_SYS_COMP_START_BYTE2) return result; - - size_t msg_length = length - BASIC_FRAME_WITH_SYS_COMP_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_SYS_COMP_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// UbxFrame Frame Format -// ============================================================================= - -enum class UbxFrameParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingLength = 3, - GettingPayload = 4 -}; - -// UbxFrame constants -constexpr uint8_t UBX_FRAME_START_BYTE1 = 0xB5; -constexpr uint8_t UBX_FRAME_START_BYTE2 = 0x62; -constexpr size_t UBX_FRAME_HEADER_SIZE = 5; -constexpr size_t UBX_FRAME_FOOTER_SIZE = 2; -constexpr size_t UBX_FRAME_OVERHEAD = UBX_FRAME_HEADER_SIZE + UBX_FRAME_FOOTER_SIZE; -constexpr size_t UBX_FRAME_LENGTH_BYTES = 1; - -/** - * UbxFrame Encode Buffer - */ -class UbxFrameEncodeBuffer { -public: - UbxFrameEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = UBX_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = UBX_FRAME_START_BYTE1; - packet_start[1] = UBX_FRAME_START_BYTE2; - packet_start[2] = msg_id; - packet_start[3] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + UBX_FRAME_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1 + 1); - packet_start[UBX_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[UBX_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * UbxFrame Frame Parser - */ -class UbxFrameParser { -public: - using MsgLengthCallback = std::function; - - UbxFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(UbxFrameParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = UbxFrameParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case UbxFrameParserState::LookingForStart1: - if (byte == UBX_FRAME_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = UbxFrameParserState::LookingForStart2; - } - break; - - case UbxFrameParserState::LookingForStart2: - if (byte == UBX_FRAME_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = UbxFrameParserState::GettingMsgId; - } else if (byte == UBX_FRAME_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = UbxFrameParserState::LookingForStart2; - } else { - state_ = UbxFrameParserState::LookingForStart1; - } - break; - - case UbxFrameParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = UbxFrameParserState::GettingLength; - break; - } - - case UbxFrameParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = UBX_FRAME_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = UbxFrameParserState::GettingPayload; - } else { - state_ = UbxFrameParserState::LookingForStart1; - } - break; - - case UbxFrameParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - UBX_FRAME_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1 + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + UBX_FRAME_HEADER_SIZE; - } - state_ = UbxFrameParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - UbxFrameParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with UbxFrame format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t ubx_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = UBX_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = UBX_FRAME_START_BYTE1; - buffer[1] = UBX_FRAME_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + UBX_FRAME_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1 + 1); - buffer[UBX_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[UBX_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete UbxFrame packet in a buffer - */ -inline FrameMsgInfo ubx_frame_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < UBX_FRAME_OVERHEAD) return result; - - if (buffer[0] != UBX_FRAME_START_BYTE1) return result; - if (buffer[1] != UBX_FRAME_START_BYTE2) return result; - - size_t msg_length = length - UBX_FRAME_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + UBX_FRAME_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// MavlinkV1Frame Frame Format -// ============================================================================= - -enum class MavlinkV1FrameParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingLength = 2, - GettingPayload = 3 -}; - -// MavlinkV1Frame constants -constexpr uint8_t MAVLINK_V1_FRAME_START_BYTE = 0xFE; -constexpr size_t MAVLINK_V1_FRAME_HEADER_SIZE = 3; -constexpr size_t MAVLINK_V1_FRAME_FOOTER_SIZE = 2; -constexpr size_t MAVLINK_V1_FRAME_OVERHEAD = MAVLINK_V1_FRAME_HEADER_SIZE + MAVLINK_V1_FRAME_FOOTER_SIZE; -constexpr size_t MAVLINK_V1_FRAME_LENGTH_BYTES = 1; - -/** - * MavlinkV1Frame Encode Buffer - */ -class MavlinkV1FrameEncodeBuffer { -public: - MavlinkV1FrameEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MAVLINK_V1_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = MAVLINK_V1_FRAME_START_BYTE; - packet_start[1] = msg_id; - packet_start[2] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MAVLINK_V1_FRAME_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 1); - packet_start[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MavlinkV1Frame Frame Parser - */ -class MavlinkV1FrameParser { -public: - using MsgLengthCallback = std::function; - - MavlinkV1FrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MavlinkV1FrameParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MavlinkV1FrameParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MavlinkV1FrameParserState::LookingForStart: - if (byte == MAVLINK_V1_FRAME_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = MavlinkV1FrameParserState::GettingMsgId; - } - break; - - case MavlinkV1FrameParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = MavlinkV1FrameParserState::GettingLength; - break; - } - - case MavlinkV1FrameParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = MAVLINK_V1_FRAME_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = MavlinkV1FrameParserState::GettingPayload; - } else { - state_ = MavlinkV1FrameParserState::LookingForStart; - } - break; - - case MavlinkV1FrameParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - MAVLINK_V1_FRAME_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + MAVLINK_V1_FRAME_HEADER_SIZE; - } - state_ = MavlinkV1FrameParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - MavlinkV1FrameParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MavlinkV1Frame format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t mavlink_v1_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MAVLINK_V1_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = MAVLINK_V1_FRAME_START_BYTE; - buffer[1] = msg_id; - buffer[2] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MAVLINK_V1_FRAME_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 1); - buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MAVLINK_V1_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MavlinkV1Frame packet in a buffer - */ -inline FrameMsgInfo mavlink_v1_frame_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MAVLINK_V1_FRAME_OVERHEAD) return result; - - if (buffer[0] != MAVLINK_V1_FRAME_START_BYTE) return result; - - size_t msg_length = length - MAVLINK_V1_FRAME_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MAVLINK_V1_FRAME_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// MavlinkV2Frame Frame Format -// ============================================================================= - -enum class MavlinkV2FrameParserState : uint8_t { - LookingForStart = 0, - GettingMsgId = 1, - GettingLength = 2, - GettingPayload = 3 -}; - -// MavlinkV2Frame constants -constexpr uint8_t MAVLINK_V2_FRAME_START_BYTE = 0xFD; -constexpr size_t MAVLINK_V2_FRAME_HEADER_SIZE = 5; -constexpr size_t MAVLINK_V2_FRAME_FOOTER_SIZE = 2; -constexpr size_t MAVLINK_V2_FRAME_OVERHEAD = MAVLINK_V2_FRAME_HEADER_SIZE + MAVLINK_V2_FRAME_FOOTER_SIZE; -constexpr size_t MAVLINK_V2_FRAME_LENGTH_BYTES = 1; - -/** - * MavlinkV2Frame Encode Buffer - */ -class MavlinkV2FrameEncodeBuffer { -public: - MavlinkV2FrameEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = MAVLINK_V2_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = MAVLINK_V2_FRAME_START_BYTE; - packet_start[1] = msg_id; - packet_start[2] = static_cast(msg_size); - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + MAVLINK_V2_FRAME_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 1, msg_size + 1 + 1); - packet_start[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * MavlinkV2Frame Frame Parser - */ -class MavlinkV2FrameParser { -public: - using MsgLengthCallback = std::function; - - MavlinkV2FrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(MavlinkV2FrameParserState::LookingForStart), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_length_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = MavlinkV2FrameParserState::LookingForStart; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_length_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case MavlinkV2FrameParserState::LookingForStart: - if (byte == MAVLINK_V2_FRAME_START_BYTE) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = MavlinkV2FrameParserState::GettingMsgId; - } - break; - - case MavlinkV2FrameParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - state_ = MavlinkV2FrameParserState::GettingLength; - break; - } - - case MavlinkV2FrameParserState::GettingLength: - buffer_[buffer_index_++] = byte; - msg_length_ = byte; - packet_size_ = MAVLINK_V2_FRAME_OVERHEAD + msg_length_; - if (packet_size_ <= buffer_max_size_) { - state_ = MavlinkV2FrameParserState::GettingPayload; - } else { - state_ = MavlinkV2FrameParserState::LookingForStart; - } - break; - - case MavlinkV2FrameParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - MAVLINK_V2_FRAME_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 1, msg_length + 1 + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + MAVLINK_V2_FRAME_HEADER_SIZE; - } - state_ = MavlinkV2FrameParserState::LookingForStart; - } - break; - } - - return result; - } - -private: - MavlinkV2FrameParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - size_t msg_length_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with MavlinkV2Frame format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t mavlink_v2_frame_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = MAVLINK_V2_FRAME_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = MAVLINK_V2_FRAME_START_BYTE; - buffer[1] = msg_id; - buffer[2] = static_cast(msg_size); - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + MAVLINK_V2_FRAME_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_size + 1 + 1); - buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size] = ck.byte1; - buffer[MAVLINK_V2_FRAME_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete MavlinkV2Frame packet in a buffer - */ -inline FrameMsgInfo mavlink_v2_frame_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < MAVLINK_V2_FRAME_OVERHEAD) return result; - - if (buffer[0] != MAVLINK_V2_FRAME_START_BYTE) return result; - - size_t msg_length = length - MAVLINK_V2_FRAME_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 1, msg_length + 1 + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + MAVLINK_V2_FRAME_HEADER_SIZE); - } - - return result; -} - - -// ============================================================================= -// FrameFormatConfig Frame Format -// ============================================================================= - -enum class FrameFormatConfigParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingPayload = 3 -}; - -// FrameFormatConfig constants -constexpr uint8_t FRAME_FORMAT_CONFIG_START_BYTE1 = 0x90; -constexpr uint8_t FRAME_FORMAT_CONFIG_START_BYTE2 = 0x91; -constexpr size_t FRAME_FORMAT_CONFIG_HEADER_SIZE = 2; -constexpr size_t FRAME_FORMAT_CONFIG_FOOTER_SIZE = 1; -constexpr size_t FRAME_FORMAT_CONFIG_OVERHEAD = FRAME_FORMAT_CONFIG_HEADER_SIZE + FRAME_FORMAT_CONFIG_FOOTER_SIZE; - -/** - * FrameFormatConfig Encode Buffer - */ -class FrameFormatConfigEncodeBuffer { -public: - FrameFormatConfigEncodeBuffer(uint8_t* data, size_t max_size) - : data_(data), max_size_(max_size), size_(0), in_progress_(false) {} - - void reset() { - size_ = 0; - in_progress_ = false; - } - - uint8_t* data() { return data_; } - const uint8_t* data() const { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - bool in_progress() const { return in_progress_; } - - /** - * Encode a message into the buffer - */ - bool encode(uint8_t msg_id, const void* msg, size_t msg_size) { - if (in_progress_) return false; - - size_t total_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) return false; - - uint8_t* packet_start = data_ + size_; - - // Write header - packet_start[0] = FRAME_FORMAT_CONFIG_START_BYTE1; - packet_start[1] = FRAME_FORMAT_CONFIG_START_BYTE2; - packet_start[2] = msg_id; - - // Write message data - if (msg_size > 0 && msg != nullptr) { - std::memcpy(packet_start + FRAME_FORMAT_CONFIG_HEADER_SIZE, msg, msg_size); - } - - // Calculate checksum - FrameChecksum ck = fletcher_checksum(packet_start + 2, msg_size + 1); - packet_start[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size] = ck.byte1; - packet_start[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size + 1] = ck.byte2; - - size_ += total_size; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -/** - * FrameFormatConfig Frame Parser - */ -class FrameFormatConfigParser { -public: - using MsgLengthCallback = std::function; - - FrameFormatConfigParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb = nullptr) - : state_(FrameFormatConfigParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - get_msg_length_(std::move(msg_length_cb)) {} - - void reset() { - state_ = FrameFormatConfigParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - } - - /** - * Parse a single byte - * Returns FrameMsgInfo with valid=true when a complete valid message is received - */ - FrameMsgInfo parse_byte(uint8_t byte) { - FrameMsgInfo result; - - switch (state_) { - case FrameFormatConfigParserState::LookingForStart1: - if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = FrameFormatConfigParserState::LookingForStart2; - } - break; - - case FrameFormatConfigParserState::LookingForStart2: - if (byte == FRAME_FORMAT_CONFIG_START_BYTE2) { - buffer_[1] = byte; - buffer_index_ = 2; - state_ = FrameFormatConfigParserState::GettingMsgId; - } else if (byte == FRAME_FORMAT_CONFIG_START_BYTE1) { - buffer_[0] = byte; - buffer_index_ = 1; - state_ = FrameFormatConfigParserState::LookingForStart2; - } else { - state_ = FrameFormatConfigParserState::LookingForStart1; - } - break; - - case FrameFormatConfigParserState::GettingMsgId: { - buffer_[buffer_index_++] = byte; - msg_id_ = byte; - - size_t msg_length = 0; - if (get_msg_length_ && get_msg_length_(byte, &msg_length)) { - packet_size_ = FRAME_FORMAT_CONFIG_OVERHEAD + msg_length; - if (packet_size_ <= buffer_max_size_) { - state_ = FrameFormatConfigParserState::GettingPayload; - } else { - state_ = FrameFormatConfigParserState::LookingForStart1; - } - } else { - state_ = FrameFormatConfigParserState::LookingForStart1; - } - break; - } - - case FrameFormatConfigParserState::GettingPayload: - if (buffer_index_ < buffer_max_size_) { - buffer_[buffer_index_++] = byte; - } - - if (buffer_index_ >= packet_size_) { - // Validate checksum - size_t msg_length = packet_size_ - FRAME_FORMAT_CONFIG_OVERHEAD; - FrameChecksum ck = fletcher_checksum(buffer_ + 2, msg_length + 1); - - if (ck.byte1 == buffer_[packet_size_ - 2] && - ck.byte2 == buffer_[packet_size_ - 1]) { - result.valid = true; - result.msg_id = msg_id_; - result.msg_len = msg_length; - result.msg_data = buffer_ + FRAME_FORMAT_CONFIG_HEADER_SIZE; - } - state_ = FrameFormatConfigParserState::LookingForStart1; - } - break; - } - - return result; - } - -private: - FrameFormatConfigParserState state_; - uint8_t* buffer_; - size_t buffer_max_size_; - size_t buffer_index_; - size_t packet_size_; - uint8_t msg_id_; - MsgLengthCallback get_msg_length_; -}; - -/** - * Encode a message with FrameFormatConfig format - * Returns the number of bytes written, or 0 on failure - */ -inline size_t frame_format_config_encode(uint8_t* buffer, size_t buffer_size, - uint8_t msg_id, const uint8_t* msg, size_t msg_size) { - size_t total_size = FRAME_FORMAT_CONFIG_OVERHEAD + msg_size; - if (buffer_size < total_size) return 0; - - buffer[0] = FRAME_FORMAT_CONFIG_START_BYTE1; - buffer[1] = FRAME_FORMAT_CONFIG_START_BYTE2; - buffer[2] = msg_id; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE, msg, msg_size); - } - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_size + 1); - buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size] = ck.byte1; - buffer[FRAME_FORMAT_CONFIG_HEADER_SIZE + msg_size + 1] = ck.byte2; - - return total_size; -} - -/** - * Validate a complete FrameFormatConfig packet in a buffer - */ -inline FrameMsgInfo frame_format_config_validate_packet(const uint8_t* buffer, size_t length) { - FrameMsgInfo result; - - if (length < FRAME_FORMAT_CONFIG_OVERHEAD) return result; - - if (buffer[0] != FRAME_FORMAT_CONFIG_START_BYTE1) return result; - if (buffer[1] != FRAME_FORMAT_CONFIG_START_BYTE2) return result; - - size_t msg_length = length - FRAME_FORMAT_CONFIG_OVERHEAD; - - FrameChecksum ck = fletcher_checksum(buffer + 2, msg_length + 1); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = const_cast(buffer + FRAME_FORMAT_CONFIG_HEADER_SIZE); - } - - return result; -} - - -} // namespace FrameParsers diff --git a/src/struct_frame/boilerplate/js/BasicFrame.js b/src/struct_frame/boilerplate/js/BasicFrame.js new file mode 100644 index 00000000..a65417ca --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrame.js @@ -0,0 +1,146 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrame Frame Format +// ============================================================================= + +const BasicFrameParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * BasicFrame - Frame format parser and encoder + */ +class BasicFrame { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x91; + static HEADER_SIZE = 3; + static FOOTER_SIZE = 2; + static OVERHEAD = 5; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameParserState.LOOKING_FOR_START1: + if (byte === BasicFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameParserState.LOOKING_FOR_START2: + if (byte === BasicFrame.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameParserState.GETTING_MSG_ID; + } else if (byte === BasicFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = BasicFrame.OVERHEAD + msg_length; + this.state = BasicFrameParserState.GETTING_PAYLOAD; + } else { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + } else { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - BasicFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrame.HEADER_SIZE, this.packet_size - BasicFrame.FOOTER_SIZE)); + } + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrame.START_BYTE1); + output.push(BasicFrame.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrame.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrame.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrame.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrame.OVERHEAD; + + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrame.HEADER_SIZE, buffer.length - BasicFrame.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + BasicFrame, + BasicFrameParserState, +}; diff --git a/src/struct_frame/boilerplate/js/BasicFrameNoCrc.js b/src/struct_frame/boilerplate/js/BasicFrameNoCrc.js new file mode 100644 index 00000000..1239a24f --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrameNoCrc.js @@ -0,0 +1,136 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrameNoCrc Frame Format +// ============================================================================= + +const BasicFrameNoCrcParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * BasicFrameNoCrc - Frame format parser and encoder + */ +class BasicFrameNoCrc { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x95; + static HEADER_SIZE = 3; + static FOOTER_SIZE = 0; + static OVERHEAD = 3; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameNoCrcParserState.LOOKING_FOR_START1: + if (byte === BasicFrameNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameNoCrcParserState.LOOKING_FOR_START2: + if (byte === BasicFrameNoCrc.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameNoCrcParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = BasicFrameNoCrc.OVERHEAD + msg_length; + this.state = BasicFrameNoCrcParserState.GETTING_PAYLOAD; + } else { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + } else { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - BasicFrameNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameNoCrc.HEADER_SIZE)); + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrameNoCrc.START_BYTE1); + output.push(BasicFrameNoCrc.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameNoCrc.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameNoCrc.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameNoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + BasicFrameNoCrc, + BasicFrameNoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/BasicFrameWithLen.js b/src/struct_frame/boilerplate/js/BasicFrameWithLen.js new file mode 100644 index 00000000..c1282b29 --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrameWithLen.js @@ -0,0 +1,148 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrameWithLen Frame Format +// ============================================================================= + +const BasicFrameWithLenParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_LENGTH: 3, + GETTING_PAYLOAD: 4 +}; + +/** + * BasicFrameWithLen - Frame format parser and encoder + */ +class BasicFrameWithLen { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x92; + static HEADER_SIZE = 4; + static FOOTER_SIZE = 2; + static OVERHEAD = 6; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLenParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLen.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLenParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLen.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLenParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLen.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLenParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLenParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLenParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = BasicFrameWithLen.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLenParserState.GETTING_PAYLOAD; + break; + + case BasicFrameWithLenParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - BasicFrameWithLen.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen.HEADER_SIZE, this.packet_size - BasicFrameWithLen.FOOTER_SIZE)); + } + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrameWithLen.START_BYTE1); + output.push(BasicFrameWithLen.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLen.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLen.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLen.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLen.OVERHEAD; + + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen.HEADER_SIZE, buffer.length - BasicFrameWithLen.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + BasicFrameWithLen, + BasicFrameWithLenParserState, +}; diff --git a/src/struct_frame/boilerplate/js/BasicFrameWithLen16.js b/src/struct_frame/boilerplate/js/BasicFrameWithLen16.js new file mode 100644 index 00000000..dc180525 --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrameWithLen16.js @@ -0,0 +1,154 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrameWithLen16 Frame Format +// ============================================================================= + +const BasicFrameWithLen16ParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_LENGTH: 3, + GETTING_PAYLOAD: 4 +}; + +/** + * BasicFrameWithLen16 - Frame format parser and encoder + */ +class BasicFrameWithLen16 { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x93; + static HEADER_SIZE = 5; + static FOOTER_SIZE = 2; + static OVERHEAD = 7; + static LENGTH_BYTES = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + reset() { + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLen16ParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLen16.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLen16ParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLen16.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLen16ParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLen16.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLen16ParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLen16ParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLen16ParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 4) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = BasicFrameWithLen16.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLen16ParserState.GETTING_PAYLOAD; + } + break; + + case BasicFrameWithLen16ParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - BasicFrameWithLen16.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 2); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16.HEADER_SIZE, this.packet_size - BasicFrameWithLen16.FOOTER_SIZE)); + } + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrameWithLen16.START_BYTE1); + output.push(BasicFrameWithLen16.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 2); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLen16.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLen16.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLen16.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLen16.OVERHEAD; + + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 2); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16.HEADER_SIZE, buffer.length - BasicFrameWithLen16.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + BasicFrameWithLen16, + BasicFrameWithLen16ParserState, +}; diff --git a/src/struct_frame/boilerplate/js/BasicFrameWithLen16NoCrc.js b/src/struct_frame/boilerplate/js/BasicFrameWithLen16NoCrc.js new file mode 100644 index 00000000..1b7294a8 --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrameWithLen16NoCrc.js @@ -0,0 +1,144 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrameWithLen16NoCrc Frame Format +// ============================================================================= + +const BasicFrameWithLen16NoCrcParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_LENGTH: 3, + GETTING_PAYLOAD: 4 +}; + +/** + * BasicFrameWithLen16NoCrc - Frame format parser and encoder + */ +class BasicFrameWithLen16NoCrc { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x97; + static HEADER_SIZE = 5; + static FOOTER_SIZE = 0; + static OVERHEAD = 5; + static LENGTH_BYTES = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + reset() { + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLen16NoCrc.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 4) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = BasicFrameWithLen16NoCrc.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; + } + break; + + case BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - BasicFrameWithLen16NoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16NoCrc.HEADER_SIZE)); + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrameWithLen16NoCrc.START_BYTE1); + output.push(BasicFrameWithLen16NoCrc.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLen16NoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLen16NoCrc.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLen16NoCrc.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLen16NoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16NoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + BasicFrameWithLen16NoCrc, + BasicFrameWithLen16NoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/BasicFrameWithLenNoCrc.js b/src/struct_frame/boilerplate/js/BasicFrameWithLenNoCrc.js new file mode 100644 index 00000000..55ddcf99 --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrameWithLenNoCrc.js @@ -0,0 +1,138 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrameWithLenNoCrc Frame Format +// ============================================================================= + +const BasicFrameWithLenNoCrcParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_LENGTH: 3, + GETTING_PAYLOAD: 4 +}; + +/** + * BasicFrameWithLenNoCrc - Frame format parser and encoder + */ +class BasicFrameWithLenNoCrc { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x96; + static HEADER_SIZE = 4; + static FOOTER_SIZE = 0; + static OVERHEAD = 4; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLenNoCrc.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLenNoCrcParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLenNoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = BasicFrameWithLenNoCrc.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD; + break; + + case BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - BasicFrameWithLenNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLenNoCrc.HEADER_SIZE)); + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrameWithLenNoCrc.START_BYTE1); + output.push(BasicFrameWithLenNoCrc.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLenNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLenNoCrc.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLenNoCrc.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLenNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLenNoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + BasicFrameWithLenNoCrc, + BasicFrameWithLenNoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/BasicFrameWithSysComp.js b/src/struct_frame/boilerplate/js/BasicFrameWithSysComp.js new file mode 100644 index 00000000..770d9cba --- /dev/null +++ b/src/struct_frame/boilerplate/js/BasicFrameWithSysComp.js @@ -0,0 +1,146 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// BasicFrameWithSysComp Frame Format +// ============================================================================= + +const BasicFrameWithSysCompParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * BasicFrameWithSysComp - Frame format parser and encoder + */ +class BasicFrameWithSysComp { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x94; + static HEADER_SIZE = 3; + static FOOTER_SIZE = 2; + static OVERHEAD = 5; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithSysCompParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithSysComp.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithSysCompParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithSysComp.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithSysCompParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithSysComp.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithSysCompParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = BasicFrameWithSysComp.OVERHEAD + msg_length; + this.state = BasicFrameWithSysCompParserState.GETTING_PAYLOAD; + } else { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + } else { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithSysCompParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - BasicFrameWithSysComp.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithSysComp.HEADER_SIZE, this.packet_size - BasicFrameWithSysComp.FOOTER_SIZE)); + } + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(BasicFrameWithSysComp.START_BYTE1); + output.push(BasicFrameWithSysComp.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithSysComp.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithSysComp.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithSysComp.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithSysComp.OVERHEAD; + + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithSysComp.HEADER_SIZE, buffer.length - BasicFrameWithSysComp.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + BasicFrameWithSysComp, + BasicFrameWithSysCompParserState, +}; diff --git a/src/struct_frame/boilerplate/js/FrameFormatConfig.js b/src/struct_frame/boilerplate/js/FrameFormatConfig.js new file mode 100644 index 00000000..30759814 --- /dev/null +++ b/src/struct_frame/boilerplate/js/FrameFormatConfig.js @@ -0,0 +1,146 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// FrameFormatConfig Frame Format +// ============================================================================= + +const FrameFormatConfigParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * FrameFormatConfig - Frame format parser and encoder + */ +class FrameFormatConfig { + static START_BYTE1 = 0x90; + static START_BYTE2 = 0x91; + static HEADER_SIZE = 2; + static FOOTER_SIZE = 1; + static OVERHEAD = 3; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case FrameFormatConfigParserState.LOOKING_FOR_START1: + if (byte === FrameFormatConfig.START_BYTE1) { + this.buffer = [byte]; + this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; + } + break; + + case FrameFormatConfigParserState.LOOKING_FOR_START2: + if (byte === FrameFormatConfig.START_BYTE2) { + this.buffer.push(byte); + this.state = FrameFormatConfigParserState.GETTING_MSG_ID; + } else if (byte === FrameFormatConfig.START_BYTE1) { + this.buffer = [byte]; + this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; + } else { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + break; + + case FrameFormatConfigParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = FrameFormatConfig.OVERHEAD + msg_length; + this.state = FrameFormatConfigParserState.GETTING_PAYLOAD; + } else { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + } else { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + break; + + case FrameFormatConfigParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - FrameFormatConfig.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(FrameFormatConfig.HEADER_SIZE, this.packet_size - FrameFormatConfig.FOOTER_SIZE)); + } + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(FrameFormatConfig.START_BYTE1); + output.push(FrameFormatConfig.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < FrameFormatConfig.OVERHEAD) { + return result; + } + + if (buffer[0] !== FrameFormatConfig.START_BYTE1) { + return result; + } + if (buffer[1] !== FrameFormatConfig.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - FrameFormatConfig.OVERHEAD; + + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, FrameFormatConfig.HEADER_SIZE, buffer.length - FrameFormatConfig.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + FrameFormatConfig, + FrameFormatConfigParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MavlinkV1Frame.js b/src/struct_frame/boilerplate/js/MavlinkV1Frame.js new file mode 100644 index 00000000..9cdef551 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MavlinkV1Frame.js @@ -0,0 +1,130 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MavlinkV1Frame Frame Format +// ============================================================================= + +const MavlinkV1FrameParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_LENGTH: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * MavlinkV1Frame - Frame format parser and encoder + */ +class MavlinkV1Frame { + static START_BYTE = 0xFE; + static HEADER_SIZE = 3; + static FOOTER_SIZE = 2; + static OVERHEAD = 5; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MavlinkV1FrameParserState.LOOKING_FOR_START: + if (byte === MavlinkV1Frame.START_BYTE) { + this.buffer = [byte]; + this.state = MavlinkV1FrameParserState.GETTING_MSG_ID; + } + break; + + case MavlinkV1FrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MavlinkV1FrameParserState.GETTING_LENGTH; + break; + + case MavlinkV1FrameParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MavlinkV1Frame.OVERHEAD + this.msg_length; + this.state = MavlinkV1FrameParserState.GETTING_PAYLOAD; + break; + + case MavlinkV1FrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - MavlinkV1Frame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV1Frame.HEADER_SIZE, this.packet_size - MavlinkV1Frame.FOOTER_SIZE)); + } + this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(MavlinkV1Frame.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MavlinkV1Frame.OVERHEAD) { + return result; + } + + if (buffer[0] !== MavlinkV1Frame.START_BYTE) { + return result; + } + + const msg_length = buffer.length - MavlinkV1Frame.OVERHEAD; + + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV1Frame.HEADER_SIZE, buffer.length - MavlinkV1Frame.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + MavlinkV1Frame, + MavlinkV1FrameParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MavlinkV2Frame.js b/src/struct_frame/boilerplate/js/MavlinkV2Frame.js new file mode 100644 index 00000000..f5065f32 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MavlinkV2Frame.js @@ -0,0 +1,130 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MavlinkV2Frame Frame Format +// ============================================================================= + +const MavlinkV2FrameParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_LENGTH: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * MavlinkV2Frame - Frame format parser and encoder + */ +class MavlinkV2Frame { + static START_BYTE = 0xFD; + static HEADER_SIZE = 5; + static FOOTER_SIZE = 2; + static OVERHEAD = 7; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MavlinkV2FrameParserState.LOOKING_FOR_START: + if (byte === MavlinkV2Frame.START_BYTE) { + this.buffer = [byte]; + this.state = MavlinkV2FrameParserState.GETTING_MSG_ID; + } + break; + + case MavlinkV2FrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MavlinkV2FrameParserState.GETTING_LENGTH; + break; + + case MavlinkV2FrameParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MavlinkV2Frame.OVERHEAD + this.msg_length; + this.state = MavlinkV2FrameParserState.GETTING_PAYLOAD; + break; + + case MavlinkV2FrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - MavlinkV2Frame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV2Frame.HEADER_SIZE, this.packet_size - MavlinkV2Frame.FOOTER_SIZE)); + } + this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(MavlinkV2Frame.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MavlinkV2Frame.OVERHEAD) { + return result; + } + + if (buffer[0] !== MavlinkV2Frame.START_BYTE) { + return result; + } + + const msg_length = buffer.length - MavlinkV2Frame.OVERHEAD; + + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV2Frame.HEADER_SIZE, buffer.length - MavlinkV2Frame.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + MavlinkV2Frame, + MavlinkV2FrameParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MinimalFrame.js b/src/struct_frame/boilerplate/js/MinimalFrame.js new file mode 100644 index 00000000..5e2beaa4 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MinimalFrame.js @@ -0,0 +1,115 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MinimalFrame Frame Format +// ============================================================================= + +const MinimalFrameParserState = { + GETTING_MSG_ID: 0, + GETTING_PAYLOAD: 1 +}; + +/** + * MinimalFrame - Frame format parser and encoder + */ +class MinimalFrame { + static HEADER_SIZE = 1; + static FOOTER_SIZE = 2; + static OVERHEAD = 3; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = MinimalFrameParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = MinimalFrame.OVERHEAD + msg_length; + this.state = MinimalFrameParserState.GETTING_PAYLOAD; + } else { + this.state = MinimalFrameParserState.GETTING_MSG_ID; + } + } else { + this.state = MinimalFrameParserState.GETTING_MSG_ID; + } + break; + + case MinimalFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - MinimalFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrame.HEADER_SIZE, this.packet_size - MinimalFrame.FOOTER_SIZE)); + } + this.state = MinimalFrameParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 0, 0 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrame.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrame.OVERHEAD; + + const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrame.HEADER_SIZE, buffer.length - MinimalFrame.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + MinimalFrame, + MinimalFrameParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MinimalFrameWithLen.js b/src/struct_frame/boilerplate/js/MinimalFrameWithLen.js new file mode 100644 index 00000000..4488eb87 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MinimalFrameWithLen.js @@ -0,0 +1,117 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MinimalFrameWithLen Frame Format +// ============================================================================= + +const MinimalFrameWithLenParserState = { + GETTING_MSG_ID: 0, + GETTING_LENGTH: 1, + GETTING_PAYLOAD: 2 +}; + +/** + * MinimalFrameWithLen - Frame format parser and encoder + */ +class MinimalFrameWithLen { + static HEADER_SIZE = 2; + static FOOTER_SIZE = 2; + static OVERHEAD = 4; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLenParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLenParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLenParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MinimalFrameWithLen.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLenParserState.GETTING_PAYLOAD; + break; + + case MinimalFrameWithLenParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - MinimalFrameWithLen.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen.HEADER_SIZE, this.packet_size - MinimalFrameWithLen.FOOTER_SIZE)); + } + this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLen.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLen.OVERHEAD; + + const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen.HEADER_SIZE, buffer.length - MinimalFrameWithLen.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + MinimalFrameWithLen, + MinimalFrameWithLenParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MinimalFrameWithLen16.js b/src/struct_frame/boilerplate/js/MinimalFrameWithLen16.js new file mode 100644 index 00000000..c83b6c10 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MinimalFrameWithLen16.js @@ -0,0 +1,123 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MinimalFrameWithLen16 Frame Format +// ============================================================================= + +const MinimalFrameWithLen16ParserState = { + GETTING_MSG_ID: 0, + GETTING_LENGTH: 1, + GETTING_PAYLOAD: 2 +}; + +/** + * MinimalFrameWithLen16 - Frame format parser and encoder + */ +class MinimalFrameWithLen16 { + static HEADER_SIZE = 3; + static FOOTER_SIZE = 2; + static OVERHEAD = 5; + static LENGTH_BYTES = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + reset() { + this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLen16ParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLen16ParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLen16ParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 2) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = MinimalFrameWithLen16.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLen16ParserState.GETTING_PAYLOAD; + } + break; + + case MinimalFrameWithLen16ParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - MinimalFrameWithLen16.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 2); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16.HEADER_SIZE, this.packet_size - MinimalFrameWithLen16.FOOTER_SIZE)); + } + this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 2); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLen16.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLen16.OVERHEAD; + + const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 2); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16.HEADER_SIZE, buffer.length - MinimalFrameWithLen16.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + MinimalFrameWithLen16, + MinimalFrameWithLen16ParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MinimalFrameWithLen16NoCrc.js b/src/struct_frame/boilerplate/js/MinimalFrameWithLen16NoCrc.js new file mode 100644 index 00000000..eeff9d16 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MinimalFrameWithLen16NoCrc.js @@ -0,0 +1,113 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MinimalFrameWithLen16NoCrc Frame Format +// ============================================================================= + +const MinimalFrameWithLen16NoCrcParserState = { + GETTING_MSG_ID: 0, + GETTING_LENGTH: 1, + GETTING_PAYLOAD: 2 +}; + +/** + * MinimalFrameWithLen16NoCrc - Frame format parser and encoder + */ +class MinimalFrameWithLen16NoCrc { + static HEADER_SIZE = 3; + static FOOTER_SIZE = 0; + static OVERHEAD = 3; + static LENGTH_BYTES = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + reset() { + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 2) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = MinimalFrameWithLen16NoCrc.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; + } + break; + + case MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - MinimalFrameWithLen16NoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16NoCrc.HEADER_SIZE)); + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLen16NoCrc.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLen16NoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16NoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + MinimalFrameWithLen16NoCrc, + MinimalFrameWithLen16NoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/MinimalFrameWithLenNoCrc.js b/src/struct_frame/boilerplate/js/MinimalFrameWithLenNoCrc.js new file mode 100644 index 00000000..12f374c5 --- /dev/null +++ b/src/struct_frame/boilerplate/js/MinimalFrameWithLenNoCrc.js @@ -0,0 +1,107 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// MinimalFrameWithLenNoCrc Frame Format +// ============================================================================= + +const MinimalFrameWithLenNoCrcParserState = { + GETTING_MSG_ID: 0, + GETTING_LENGTH: 1, + GETTING_PAYLOAD: 2 +}; + +/** + * MinimalFrameWithLenNoCrc - Frame format parser and encoder + */ +class MinimalFrameWithLenNoCrc { + static HEADER_SIZE = 2; + static FOOTER_SIZE = 0; + static OVERHEAD = 2; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MinimalFrameWithLenNoCrc.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD; + break; + + case MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - MinimalFrameWithLenNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLenNoCrc.HEADER_SIZE)); + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLenNoCrc.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLenNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLenNoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + MinimalFrameWithLenNoCrc, + MinimalFrameWithLenNoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/TinyFrame.js b/src/struct_frame/boilerplate/js/TinyFrame.js new file mode 100644 index 00000000..aba63682 --- /dev/null +++ b/src/struct_frame/boilerplate/js/TinyFrame.js @@ -0,0 +1,128 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// TinyFrame Frame Format +// ============================================================================= + +const TinyFrameParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_PAYLOAD: 2 +}; + +/** + * TinyFrame - Frame format parser and encoder + */ +class TinyFrame { + static START_BYTE = 0x70; + static HEADER_SIZE = 2; + static FOOTER_SIZE = 2; + static OVERHEAD = 4; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = TinyFrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameParserState.LOOKING_FOR_START: + if (byte === TinyFrame.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = TinyFrame.OVERHEAD + msg_length; + this.state = TinyFrameParserState.GETTING_PAYLOAD; + } else { + this.state = TinyFrameParserState.LOOKING_FOR_START; + } + } else { + this.state = TinyFrameParserState.LOOKING_FOR_START; + } + break; + + case TinyFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - TinyFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrame.HEADER_SIZE, this.packet_size - TinyFrame.FOOTER_SIZE)); + } + this.state = TinyFrameParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(TinyFrame.START_BYTE); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrame.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrame.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrame.OVERHEAD; + + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrame.HEADER_SIZE, buffer.length - TinyFrame.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + TinyFrame, + TinyFrameParserState, +}; diff --git a/src/struct_frame/boilerplate/js/TinyFrameNoCrc.js b/src/struct_frame/boilerplate/js/TinyFrameNoCrc.js new file mode 100644 index 00000000..72725fcd --- /dev/null +++ b/src/struct_frame/boilerplate/js/TinyFrameNoCrc.js @@ -0,0 +1,118 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// TinyFrameNoCrc Frame Format +// ============================================================================= + +const TinyFrameNoCrcParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_PAYLOAD: 2 +}; + +/** + * TinyFrameNoCrc - Frame format parser and encoder + */ +class TinyFrameNoCrc { + static START_BYTE = 0x72; + static HEADER_SIZE = 2; + static FOOTER_SIZE = 0; + static OVERHEAD = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + reset() { + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameNoCrcParserState.LOOKING_FOR_START: + if (byte === TinyFrameNoCrc.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameNoCrcParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = TinyFrameNoCrc.OVERHEAD + msg_length; + this.state = TinyFrameNoCrcParserState.GETTING_PAYLOAD; + } else { + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + } + } else { + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + } + break; + + case TinyFrameNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - TinyFrameNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameNoCrc.HEADER_SIZE)); + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(TinyFrameNoCrc.START_BYTE); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameNoCrc.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameNoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + TinyFrameNoCrc, + TinyFrameNoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/TinyFrameWithLen.js b/src/struct_frame/boilerplate/js/TinyFrameWithLen.js new file mode 100644 index 00000000..8deea69d --- /dev/null +++ b/src/struct_frame/boilerplate/js/TinyFrameWithLen.js @@ -0,0 +1,130 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// TinyFrameWithLen Frame Format +// ============================================================================= + +const TinyFrameWithLenParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_LENGTH: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * TinyFrameWithLen - Frame format parser and encoder + */ +class TinyFrameWithLen { + static START_BYTE = 0x71; + static HEADER_SIZE = 3; + static FOOTER_SIZE = 2; + static OVERHEAD = 5; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLenParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLen.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLenParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLenParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLenParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLenParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = TinyFrameWithLen.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLenParserState.GETTING_PAYLOAD; + break; + + case TinyFrameWithLenParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - TinyFrameWithLen.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen.HEADER_SIZE, this.packet_size - TinyFrameWithLen.FOOTER_SIZE)); + } + this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(TinyFrameWithLen.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLen.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLen.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLen.OVERHEAD; + + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen.HEADER_SIZE, buffer.length - TinyFrameWithLen.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + TinyFrameWithLen, + TinyFrameWithLenParserState, +}; diff --git a/src/struct_frame/boilerplate/js/TinyFrameWithLen16.js b/src/struct_frame/boilerplate/js/TinyFrameWithLen16.js new file mode 100644 index 00000000..fe3dac5a --- /dev/null +++ b/src/struct_frame/boilerplate/js/TinyFrameWithLen16.js @@ -0,0 +1,136 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// TinyFrameWithLen16 Frame Format +// ============================================================================= + +const TinyFrameWithLen16ParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_LENGTH: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * TinyFrameWithLen16 - Frame format parser and encoder + */ +class TinyFrameWithLen16 { + static START_BYTE = 0x74; + static HEADER_SIZE = 4; + static FOOTER_SIZE = 2; + static OVERHEAD = 6; + static LENGTH_BYTES = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + reset() { + this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLen16ParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLen16.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLen16ParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLen16ParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLen16ParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLen16ParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 3) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = TinyFrameWithLen16.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLen16ParserState.GETTING_PAYLOAD; + } + break; + + case TinyFrameWithLen16ParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - TinyFrameWithLen16.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 2); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16.HEADER_SIZE, this.packet_size - TinyFrameWithLen16.FOOTER_SIZE)); + } + this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(TinyFrameWithLen16.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 2); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLen16.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLen16.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLen16.OVERHEAD; + + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 2); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16.HEADER_SIZE, buffer.length - TinyFrameWithLen16.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + TinyFrameWithLen16, + TinyFrameWithLen16ParserState, +}; diff --git a/src/struct_frame/boilerplate/js/TinyFrameWithLen16NoCrc.js b/src/struct_frame/boilerplate/js/TinyFrameWithLen16NoCrc.js new file mode 100644 index 00000000..4a279fae --- /dev/null +++ b/src/struct_frame/boilerplate/js/TinyFrameWithLen16NoCrc.js @@ -0,0 +1,126 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// TinyFrameWithLen16NoCrc Frame Format +// ============================================================================= + +const TinyFrameWithLen16NoCrcParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_LENGTH: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * TinyFrameWithLen16NoCrc - Frame format parser and encoder + */ +class TinyFrameWithLen16NoCrc { + static START_BYTE = 0x75; + static HEADER_SIZE = 4; + static FOOTER_SIZE = 0; + static OVERHEAD = 4; + static LENGTH_BYTES = 2; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + reset() { + this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLen16NoCrc.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 3) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = TinyFrameWithLen16NoCrc.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; + } + break; + + case TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - TinyFrameWithLen16NoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16NoCrc.HEADER_SIZE)); + this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(TinyFrameWithLen16NoCrc.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLen16NoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLen16NoCrc.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLen16NoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16NoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + TinyFrameWithLen16NoCrc, + TinyFrameWithLen16NoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/TinyFrameWithLenNoCrc.js b/src/struct_frame/boilerplate/js/TinyFrameWithLenNoCrc.js new file mode 100644 index 00000000..1508dbf6 --- /dev/null +++ b/src/struct_frame/boilerplate/js/TinyFrameWithLenNoCrc.js @@ -0,0 +1,120 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// TinyFrameWithLenNoCrc Frame Format +// ============================================================================= + +const TinyFrameWithLenNoCrcParserState = { + LOOKING_FOR_START: 0, + GETTING_MSG_ID: 1, + GETTING_LENGTH: 2, + GETTING_PAYLOAD: 3 +}; + +/** + * TinyFrameWithLenNoCrc - Frame format parser and encoder + */ +class TinyFrameWithLenNoCrc { + static START_BYTE = 0x73; + static HEADER_SIZE = 3; + static FOOTER_SIZE = 0; + static OVERHEAD = 3; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLenNoCrc.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLenNoCrcParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLenNoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = TinyFrameWithLenNoCrc.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD; + break; + + case TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - TinyFrameWithLenNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLenNoCrc.HEADER_SIZE)); + this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(TinyFrameWithLenNoCrc.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLenNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLenNoCrc.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLenNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLenNoCrc.HEADER_SIZE)); + + return result; + } +} + +module.exports = { + TinyFrameWithLenNoCrc, + TinyFrameWithLenNoCrcParserState, +}; diff --git a/src/struct_frame/boilerplate/js/UbxFrame.js b/src/struct_frame/boilerplate/js/UbxFrame.js new file mode 100644 index 00000000..4a1ab410 --- /dev/null +++ b/src/struct_frame/boilerplate/js/UbxFrame.js @@ -0,0 +1,148 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +const { createFrameMsgInfo, fletcher_checksum } = require('./frame_base'); + +// ============================================================================= +// UbxFrame Frame Format +// ============================================================================= + +const UbxFrameParserState = { + LOOKING_FOR_START1: 0, + LOOKING_FOR_START2: 1, + GETTING_MSG_ID: 2, + GETTING_LENGTH: 3, + GETTING_PAYLOAD: 4 +}; + +/** + * UbxFrame - Frame format parser and encoder + */ +class UbxFrame { + static START_BYTE1 = 0xB5; + static START_BYTE2 = 0x62; + static HEADER_SIZE = 5; + static FOOTER_SIZE = 2; + static OVERHEAD = 7; + static LENGTH_BYTES = 1; + + constructor(get_msg_length) { + this.get_msg_length = get_msg_length; + this.state = UbxFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + reset() { + this.state = UbxFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + parse_byte(byte) { + const result = createFrameMsgInfo(); + + switch (this.state) { + case UbxFrameParserState.LOOKING_FOR_START1: + if (byte === UbxFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = UbxFrameParserState.LOOKING_FOR_START2; + } + break; + + case UbxFrameParserState.LOOKING_FOR_START2: + if (byte === UbxFrame.START_BYTE2) { + this.buffer.push(byte); + this.state = UbxFrameParserState.GETTING_MSG_ID; + } else if (byte === UbxFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = UbxFrameParserState.LOOKING_FOR_START2; + } else { + this.state = UbxFrameParserState.LOOKING_FOR_START1; + } + break; + + case UbxFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = UbxFrameParserState.GETTING_LENGTH; + break; + + case UbxFrameParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = UbxFrame.OVERHEAD + this.msg_length; + this.state = UbxFrameParserState.GETTING_PAYLOAD; + break; + + case UbxFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + const msg_length = this.packet_size - UbxFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(UbxFrame.HEADER_SIZE, this.packet_size - UbxFrame.FOOTER_SIZE)); + } + this.state = UbxFrameParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + static encode(msg_id, msg) { + const output = []; + output.push(UbxFrame.START_BYTE1); + output.push(UbxFrame.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + static validate_packet(buffer) { + const result = createFrameMsgInfo(); + + if (buffer.length < UbxFrame.OVERHEAD) { + return result; + } + + if (buffer[0] !== UbxFrame.START_BYTE1) { + return result; + } + if (buffer[1] !== UbxFrame.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - UbxFrame.OVERHEAD; + + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, UbxFrame.HEADER_SIZE, buffer.length - UbxFrame.FOOTER_SIZE)); + } + + return result; + } +} + +module.exports = { + UbxFrame, + UbxFrameParserState, +}; diff --git a/src/struct_frame/boilerplate/js/frame_base.js b/src/struct_frame/boilerplate/js/frame_base.js new file mode 100644 index 00000000..4416e5c5 --- /dev/null +++ b/src/struct_frame/boilerplate/js/frame_base.js @@ -0,0 +1,61 @@ +// Automatically generated frame parser base utilities +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +// Frame format type enumeration +const FrameFormatType = { + MINIMAL_FRAME: 0, + BASIC_FRAME: 1, + BASIC_FRAME_NO_CRC: 2, + TINY_FRAME: 3, + TINY_FRAME_NO_CRC: 4, + MINIMAL_FRAME_WITH_LEN: 5, + MINIMAL_FRAME_WITH_LEN_NO_CRC: 6, + BASIC_FRAME_WITH_LEN: 7, + BASIC_FRAME_WITH_LEN_NO_CRC: 8, + TINY_FRAME_WITH_LEN: 9, + TINY_FRAME_WITH_LEN_NO_CRC: 10, + MINIMAL_FRAME_WITH_LEN16: 11, + MINIMAL_FRAME_WITH_LEN16_NO_CRC: 12, + BASIC_FRAME_WITH_LEN16: 13, + BASIC_FRAME_WITH_LEN16_NO_CRC: 14, + TINY_FRAME_WITH_LEN16: 15, + TINY_FRAME_WITH_LEN16_NO_CRC: 16, + BASIC_FRAME_WITH_SYS_COMP: 17, + UBX_FRAME: 18, + MAVLINK_V1_FRAME: 19, + MAVLINK_V2_FRAME: 20, + FRAME_FORMAT_CONFIG: 21, +}; + +// Fletcher-16 checksum calculation +function fletcher_checksum(buffer, start = 0, end = undefined) { + if (end === undefined) { + end = buffer.length; + } + + let byte1 = 0; + let byte2 = 0; + + for (let i = start; i < end; i++) { + byte1 = (byte1 + buffer[i]) % 256; + byte2 = (byte2 + byte1) % 256; + } + + return [byte1, byte2]; +} + +// Create default FrameMsgInfo +function createFrameMsgInfo() { + return { + valid: false, + msg_id: 0, + msg_len: 0, + msg_data: new Uint8Array(0) + }; +} + +module.exports = { + FrameFormatType, + fletcher_checksum, + createFrameMsgInfo, +}; diff --git a/src/struct_frame/boilerplate/js/frame_parsers_gen.js b/src/struct_frame/boilerplate/js/frame_parsers_gen.js deleted file mode 100644 index 31a8301f..00000000 --- a/src/struct_frame/boilerplate/js/frame_parsers_gen.js +++ /dev/null @@ -1,2829 +0,0 @@ -// Automatically generated frame parser -// Generated by 0.0.1 at Wed Dec 3 09:37:56 2025. - -// Frame format type enumeration -const FrameFormatType = { - MINIMAL_FRAME: 0, - BASIC_FRAME: 1, - BASIC_FRAME_NO_CRC: 2, - TINY_FRAME: 3, - TINY_FRAME_NO_CRC: 4, - MINIMAL_FRAME_WITH_LEN: 5, - MINIMAL_FRAME_WITH_LEN_NO_CRC: 6, - BASIC_FRAME_WITH_LEN: 7, - BASIC_FRAME_WITH_LEN_NO_CRC: 8, - TINY_FRAME_WITH_LEN: 9, - TINY_FRAME_WITH_LEN_NO_CRC: 10, - MINIMAL_FRAME_WITH_LEN16: 11, - MINIMAL_FRAME_WITH_LEN16_NO_CRC: 12, - BASIC_FRAME_WITH_LEN16: 13, - BASIC_FRAME_WITH_LEN16_NO_CRC: 14, - TINY_FRAME_WITH_LEN16: 15, - TINY_FRAME_WITH_LEN16_NO_CRC: 16, - BASIC_FRAME_WITH_SYS_COMP: 17, - UBX_FRAME: 18, - MAVLINK_V1_FRAME: 19, - MAVLINK_V2_FRAME: 20, - FRAME_FORMAT_CONFIG: 21, -}; - -// Fletcher-16 checksum calculation -function fletcher_checksum(buffer, start = 0, end = undefined) { - if (end === undefined) { - end = buffer.length; - } - - let byte1 = 0; - let byte2 = 0; - - for (let i = start; i < end; i++) { - byte1 = (byte1 + buffer[i]) % 256; - byte2 = (byte2 + byte1) % 256; - } - - return [byte1, byte2]; -} - -// Create default FrameMsgInfo -function createFrameMsgInfo() { - return { - valid: false, - msg_id: 0, - msg_len: 0, - msg_data: new Uint8Array(0) - }; -} - -// ============================================================================= -// MinimalFrame Frame Format -// ============================================================================= - -const MinimalFrameParserState = { - GETTING_MSG_ID: 0, - GETTING_PAYLOAD: 1 -}; - -/** - * MinimalFrame - Frame format parser and encoder - */ -class MinimalFrame { - static HEADER_SIZE = 1; - static FOOTER_SIZE = 2; - static OVERHEAD = 3; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = MinimalFrameParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = MinimalFrame.OVERHEAD + msg_length; - this.state = MinimalFrameParserState.GETTING_PAYLOAD; - } else { - this.state = MinimalFrameParserState.GETTING_MSG_ID; - } - } else { - this.state = MinimalFrameParserState.GETTING_MSG_ID; - } - break; - - case MinimalFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - MinimalFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrame.HEADER_SIZE, this.packet_size - MinimalFrame.FOOTER_SIZE)); - } - this.state = MinimalFrameParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 0, 0 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrame.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrame.OVERHEAD; - - const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrame.HEADER_SIZE, buffer.length - MinimalFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrame Frame Format -// ============================================================================= - -const BasicFrameParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * BasicFrame - Frame format parser and encoder - */ -class BasicFrame { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x91; - static HEADER_SIZE = 3; - static FOOTER_SIZE = 2; - static OVERHEAD = 5; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameParserState.LOOKING_FOR_START1: - if (byte === BasicFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameParserState.LOOKING_FOR_START2: - if (byte === BasicFrame.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameParserState.GETTING_MSG_ID; - } else if (byte === BasicFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = BasicFrame.OVERHEAD + msg_length; - this.state = BasicFrameParserState.GETTING_PAYLOAD; - } else { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - } else { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - BasicFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrame.HEADER_SIZE, this.packet_size - BasicFrame.FOOTER_SIZE)); - } - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrame.START_BYTE1); - output.push(BasicFrame.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrame.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrame.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrame.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrame.OVERHEAD; - - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrame.HEADER_SIZE, buffer.length - BasicFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrameNoCrc Frame Format -// ============================================================================= - -const BasicFrameNoCrcParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * BasicFrameNoCrc - Frame format parser and encoder - */ -class BasicFrameNoCrc { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x95; - static HEADER_SIZE = 3; - static FOOTER_SIZE = 0; - static OVERHEAD = 3; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameNoCrcParserState.LOOKING_FOR_START1: - if (byte === BasicFrameNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameNoCrcParserState.LOOKING_FOR_START2: - if (byte === BasicFrameNoCrc.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameNoCrcParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = BasicFrameNoCrc.OVERHEAD + msg_length; - this.state = BasicFrameNoCrcParserState.GETTING_PAYLOAD; - } else { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - } else { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - BasicFrameNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameNoCrc.HEADER_SIZE)); - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrameNoCrc.START_BYTE1); - output.push(BasicFrameNoCrc.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameNoCrc.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameNoCrc.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// TinyFrame Frame Format -// ============================================================================= - -const TinyFrameParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_PAYLOAD: 2 -}; - -/** - * TinyFrame - Frame format parser and encoder - */ -class TinyFrame { - static START_BYTE = 0x70; - static HEADER_SIZE = 2; - static FOOTER_SIZE = 2; - static OVERHEAD = 4; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = TinyFrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameParserState.LOOKING_FOR_START: - if (byte === TinyFrame.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = TinyFrame.OVERHEAD + msg_length; - this.state = TinyFrameParserState.GETTING_PAYLOAD; - } else { - this.state = TinyFrameParserState.LOOKING_FOR_START; - } - } else { - this.state = TinyFrameParserState.LOOKING_FOR_START; - } - break; - - case TinyFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - TinyFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrame.HEADER_SIZE, this.packet_size - TinyFrame.FOOTER_SIZE)); - } - this.state = TinyFrameParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(TinyFrame.START_BYTE); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrame.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrame.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrame.OVERHEAD; - - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrame.HEADER_SIZE, buffer.length - TinyFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// TinyFrameNoCrc Frame Format -// ============================================================================= - -const TinyFrameNoCrcParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_PAYLOAD: 2 -}; - -/** - * TinyFrameNoCrc - Frame format parser and encoder - */ -class TinyFrameNoCrc { - static START_BYTE = 0x72; - static HEADER_SIZE = 2; - static FOOTER_SIZE = 0; - static OVERHEAD = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameNoCrcParserState.LOOKING_FOR_START: - if (byte === TinyFrameNoCrc.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameNoCrcParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = TinyFrameNoCrc.OVERHEAD + msg_length; - this.state = TinyFrameNoCrcParserState.GETTING_PAYLOAD; - } else { - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - } - } else { - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - } - break; - - case TinyFrameNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - TinyFrameNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameNoCrc.HEADER_SIZE)); - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(TinyFrameNoCrc.START_BYTE); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameNoCrc.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLen Frame Format -// ============================================================================= - -const MinimalFrameWithLenParserState = { - GETTING_MSG_ID: 0, - GETTING_LENGTH: 1, - GETTING_PAYLOAD: 2 -}; - -/** - * MinimalFrameWithLen - Frame format parser and encoder - */ -class MinimalFrameWithLen { - static HEADER_SIZE = 2; - static FOOTER_SIZE = 2; - static OVERHEAD = 4; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLenParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLenParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLenParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MinimalFrameWithLen.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLenParserState.GETTING_PAYLOAD; - break; - - case MinimalFrameWithLenParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - MinimalFrameWithLen.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen.HEADER_SIZE, this.packet_size - MinimalFrameWithLen.FOOTER_SIZE)); - } - this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLen.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLen.OVERHEAD; - - const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen.HEADER_SIZE, buffer.length - MinimalFrameWithLen.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLenNoCrc Frame Format -// ============================================================================= - -const MinimalFrameWithLenNoCrcParserState = { - GETTING_MSG_ID: 0, - GETTING_LENGTH: 1, - GETTING_PAYLOAD: 2 -}; - -/** - * MinimalFrameWithLenNoCrc - Frame format parser and encoder - */ -class MinimalFrameWithLenNoCrc { - static HEADER_SIZE = 2; - static FOOTER_SIZE = 0; - static OVERHEAD = 2; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MinimalFrameWithLenNoCrc.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD; - break; - - case MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - MinimalFrameWithLenNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLenNoCrc.HEADER_SIZE)); - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLenNoCrc.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLenNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLenNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLen Frame Format -// ============================================================================= - -const BasicFrameWithLenParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_LENGTH: 3, - GETTING_PAYLOAD: 4 -}; - -/** - * BasicFrameWithLen - Frame format parser and encoder - */ -class BasicFrameWithLen { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x92; - static HEADER_SIZE = 4; - static FOOTER_SIZE = 2; - static OVERHEAD = 6; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLenParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLen.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLenParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLen.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLenParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLen.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLenParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLenParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLenParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = BasicFrameWithLen.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLenParserState.GETTING_PAYLOAD; - break; - - case BasicFrameWithLenParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - BasicFrameWithLen.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen.HEADER_SIZE, this.packet_size - BasicFrameWithLen.FOOTER_SIZE)); - } - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrameWithLen.START_BYTE1); - output.push(BasicFrameWithLen.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLen.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLen.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLen.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLen.OVERHEAD; - - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen.HEADER_SIZE, buffer.length - BasicFrameWithLen.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLenNoCrc Frame Format -// ============================================================================= - -const BasicFrameWithLenNoCrcParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_LENGTH: 3, - GETTING_PAYLOAD: 4 -}; - -/** - * BasicFrameWithLenNoCrc - Frame format parser and encoder - */ -class BasicFrameWithLenNoCrc { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x96; - static HEADER_SIZE = 4; - static FOOTER_SIZE = 0; - static OVERHEAD = 4; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLenNoCrc.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLenNoCrcParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLenNoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = BasicFrameWithLenNoCrc.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD; - break; - - case BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - BasicFrameWithLenNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLenNoCrc.HEADER_SIZE)); - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrameWithLenNoCrc.START_BYTE1); - output.push(BasicFrameWithLenNoCrc.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLenNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLenNoCrc.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLenNoCrc.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLenNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLenNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLen Frame Format -// ============================================================================= - -const TinyFrameWithLenParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_LENGTH: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * TinyFrameWithLen - Frame format parser and encoder - */ -class TinyFrameWithLen { - static START_BYTE = 0x71; - static HEADER_SIZE = 3; - static FOOTER_SIZE = 2; - static OVERHEAD = 5; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLenParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLen.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLenParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLenParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLenParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLenParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = TinyFrameWithLen.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLenParserState.GETTING_PAYLOAD; - break; - - case TinyFrameWithLenParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - TinyFrameWithLen.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen.HEADER_SIZE, this.packet_size - TinyFrameWithLen.FOOTER_SIZE)); - } - this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(TinyFrameWithLen.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLen.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLen.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLen.OVERHEAD; - - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen.HEADER_SIZE, buffer.length - TinyFrameWithLen.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLenNoCrc Frame Format -// ============================================================================= - -const TinyFrameWithLenNoCrcParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_LENGTH: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * TinyFrameWithLenNoCrc - Frame format parser and encoder - */ -class TinyFrameWithLenNoCrc { - static START_BYTE = 0x73; - static HEADER_SIZE = 3; - static FOOTER_SIZE = 0; - static OVERHEAD = 3; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLenNoCrc.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLenNoCrcParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLenNoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = TinyFrameWithLenNoCrc.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD; - break; - - case TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - TinyFrameWithLenNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLenNoCrc.HEADER_SIZE)); - this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(TinyFrameWithLenNoCrc.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLenNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLenNoCrc.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLenNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLenNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLen16 Frame Format -// ============================================================================= - -const MinimalFrameWithLen16ParserState = { - GETTING_MSG_ID: 0, - GETTING_LENGTH: 1, - GETTING_PAYLOAD: 2 -}; - -/** - * MinimalFrameWithLen16 - Frame format parser and encoder - */ -class MinimalFrameWithLen16 { - static HEADER_SIZE = 3; - static FOOTER_SIZE = 2; - static OVERHEAD = 5; - static LENGTH_BYTES = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - reset() { - this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLen16ParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLen16ParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLen16ParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 2) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = MinimalFrameWithLen16.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLen16ParserState.GETTING_PAYLOAD; - } - break; - - case MinimalFrameWithLen16ParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - MinimalFrameWithLen16.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 2); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16.HEADER_SIZE, this.packet_size - MinimalFrameWithLen16.FOOTER_SIZE)); - } - this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 2); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLen16.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLen16.OVERHEAD; - - const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 2); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16.HEADER_SIZE, buffer.length - MinimalFrameWithLen16.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLen16NoCrc Frame Format -// ============================================================================= - -const MinimalFrameWithLen16NoCrcParserState = { - GETTING_MSG_ID: 0, - GETTING_LENGTH: 1, - GETTING_PAYLOAD: 2 -}; - -/** - * MinimalFrameWithLen16NoCrc - Frame format parser and encoder - */ -class MinimalFrameWithLen16NoCrc { - static HEADER_SIZE = 3; - static FOOTER_SIZE = 0; - static OVERHEAD = 3; - static LENGTH_BYTES = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - reset() { - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 2) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = MinimalFrameWithLen16NoCrc.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; - } - break; - - case MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - MinimalFrameWithLen16NoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16NoCrc.HEADER_SIZE)); - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLen16NoCrc.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLen16NoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16NoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLen16 Frame Format -// ============================================================================= - -const BasicFrameWithLen16ParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_LENGTH: 3, - GETTING_PAYLOAD: 4 -}; - -/** - * BasicFrameWithLen16 - Frame format parser and encoder - */ -class BasicFrameWithLen16 { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x93; - static HEADER_SIZE = 5; - static FOOTER_SIZE = 2; - static OVERHEAD = 7; - static LENGTH_BYTES = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - reset() { - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLen16ParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLen16.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLen16ParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLen16.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLen16ParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLen16.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLen16ParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLen16ParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLen16ParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 4) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = BasicFrameWithLen16.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLen16ParserState.GETTING_PAYLOAD; - } - break; - - case BasicFrameWithLen16ParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - BasicFrameWithLen16.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 2); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16.HEADER_SIZE, this.packet_size - BasicFrameWithLen16.FOOTER_SIZE)); - } - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrameWithLen16.START_BYTE1); - output.push(BasicFrameWithLen16.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 2); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLen16.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLen16.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLen16.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLen16.OVERHEAD; - - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 2); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16.HEADER_SIZE, buffer.length - BasicFrameWithLen16.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLen16NoCrc Frame Format -// ============================================================================= - -const BasicFrameWithLen16NoCrcParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_LENGTH: 3, - GETTING_PAYLOAD: 4 -}; - -/** - * BasicFrameWithLen16NoCrc - Frame format parser and encoder - */ -class BasicFrameWithLen16NoCrc { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x97; - static HEADER_SIZE = 5; - static FOOTER_SIZE = 0; - static OVERHEAD = 5; - static LENGTH_BYTES = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - reset() { - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLen16NoCrc.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 4) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = BasicFrameWithLen16NoCrc.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; - } - break; - - case BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - BasicFrameWithLen16NoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16NoCrc.HEADER_SIZE)); - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrameWithLen16NoCrc.START_BYTE1); - output.push(BasicFrameWithLen16NoCrc.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLen16NoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLen16NoCrc.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLen16NoCrc.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLen16NoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16NoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLen16 Frame Format -// ============================================================================= - -const TinyFrameWithLen16ParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_LENGTH: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * TinyFrameWithLen16 - Frame format parser and encoder - */ -class TinyFrameWithLen16 { - static START_BYTE = 0x74; - static HEADER_SIZE = 4; - static FOOTER_SIZE = 2; - static OVERHEAD = 6; - static LENGTH_BYTES = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - reset() { - this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLen16ParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLen16.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLen16ParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLen16ParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLen16ParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLen16ParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 3) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = TinyFrameWithLen16.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLen16ParserState.GETTING_PAYLOAD; - } - break; - - case TinyFrameWithLen16ParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - TinyFrameWithLen16.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 2); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16.HEADER_SIZE, this.packet_size - TinyFrameWithLen16.FOOTER_SIZE)); - } - this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(TinyFrameWithLen16.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 2); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLen16.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLen16.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLen16.OVERHEAD; - - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 2); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16.HEADER_SIZE, buffer.length - TinyFrameWithLen16.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLen16NoCrc Frame Format -// ============================================================================= - -const TinyFrameWithLen16NoCrcParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_LENGTH: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * TinyFrameWithLen16NoCrc - Frame format parser and encoder - */ -class TinyFrameWithLen16NoCrc { - static START_BYTE = 0x75; - static HEADER_SIZE = 4; - static FOOTER_SIZE = 0; - static OVERHEAD = 4; - static LENGTH_BYTES = 2; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - reset() { - this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLen16NoCrc.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 3) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = TinyFrameWithLen16NoCrc.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; - } - break; - - case TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - TinyFrameWithLen16NoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16NoCrc.HEADER_SIZE)); - this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(TinyFrameWithLen16NoCrc.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLen16NoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLen16NoCrc.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLen16NoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16NoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithSysComp Frame Format -// ============================================================================= - -const BasicFrameWithSysCompParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * BasicFrameWithSysComp - Frame format parser and encoder - */ -class BasicFrameWithSysComp { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x94; - static HEADER_SIZE = 3; - static FOOTER_SIZE = 2; - static OVERHEAD = 5; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithSysCompParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithSysComp.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithSysCompParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithSysComp.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithSysCompParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithSysComp.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithSysCompParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = BasicFrameWithSysComp.OVERHEAD + msg_length; - this.state = BasicFrameWithSysCompParserState.GETTING_PAYLOAD; - } else { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - } else { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithSysCompParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - BasicFrameWithSysComp.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithSysComp.HEADER_SIZE, this.packet_size - BasicFrameWithSysComp.FOOTER_SIZE)); - } - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(BasicFrameWithSysComp.START_BYTE1); - output.push(BasicFrameWithSysComp.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithSysComp.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithSysComp.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithSysComp.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithSysComp.OVERHEAD; - - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithSysComp.HEADER_SIZE, buffer.length - BasicFrameWithSysComp.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// UbxFrame Frame Format -// ============================================================================= - -const UbxFrameParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_LENGTH: 3, - GETTING_PAYLOAD: 4 -}; - -/** - * UbxFrame - Frame format parser and encoder - */ -class UbxFrame { - static START_BYTE1 = 0xB5; - static START_BYTE2 = 0x62; - static HEADER_SIZE = 5; - static FOOTER_SIZE = 2; - static OVERHEAD = 7; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = UbxFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = UbxFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case UbxFrameParserState.LOOKING_FOR_START1: - if (byte === UbxFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = UbxFrameParserState.LOOKING_FOR_START2; - } - break; - - case UbxFrameParserState.LOOKING_FOR_START2: - if (byte === UbxFrame.START_BYTE2) { - this.buffer.push(byte); - this.state = UbxFrameParserState.GETTING_MSG_ID; - } else if (byte === UbxFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = UbxFrameParserState.LOOKING_FOR_START2; - } else { - this.state = UbxFrameParserState.LOOKING_FOR_START1; - } - break; - - case UbxFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = UbxFrameParserState.GETTING_LENGTH; - break; - - case UbxFrameParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = UbxFrame.OVERHEAD + this.msg_length; - this.state = UbxFrameParserState.GETTING_PAYLOAD; - break; - - case UbxFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - UbxFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(UbxFrame.HEADER_SIZE, this.packet_size - UbxFrame.FOOTER_SIZE)); - } - this.state = UbxFrameParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(UbxFrame.START_BYTE1); - output.push(UbxFrame.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < UbxFrame.OVERHEAD) { - return result; - } - - if (buffer[0] !== UbxFrame.START_BYTE1) { - return result; - } - if (buffer[1] !== UbxFrame.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - UbxFrame.OVERHEAD; - - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, UbxFrame.HEADER_SIZE, buffer.length - UbxFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MavlinkV1Frame Frame Format -// ============================================================================= - -const MavlinkV1FrameParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_LENGTH: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * MavlinkV1Frame - Frame format parser and encoder - */ -class MavlinkV1Frame { - static START_BYTE = 0xFE; - static HEADER_SIZE = 3; - static FOOTER_SIZE = 2; - static OVERHEAD = 5; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MavlinkV1FrameParserState.LOOKING_FOR_START: - if (byte === MavlinkV1Frame.START_BYTE) { - this.buffer = [byte]; - this.state = MavlinkV1FrameParserState.GETTING_MSG_ID; - } - break; - - case MavlinkV1FrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MavlinkV1FrameParserState.GETTING_LENGTH; - break; - - case MavlinkV1FrameParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MavlinkV1Frame.OVERHEAD + this.msg_length; - this.state = MavlinkV1FrameParserState.GETTING_PAYLOAD; - break; - - case MavlinkV1FrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - MavlinkV1Frame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV1Frame.HEADER_SIZE, this.packet_size - MavlinkV1Frame.FOOTER_SIZE)); - } - this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(MavlinkV1Frame.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MavlinkV1Frame.OVERHEAD) { - return result; - } - - if (buffer[0] !== MavlinkV1Frame.START_BYTE) { - return result; - } - - const msg_length = buffer.length - MavlinkV1Frame.OVERHEAD; - - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV1Frame.HEADER_SIZE, buffer.length - MavlinkV1Frame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MavlinkV2Frame Frame Format -// ============================================================================= - -const MavlinkV2FrameParserState = { - LOOKING_FOR_START: 0, - GETTING_MSG_ID: 1, - GETTING_LENGTH: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * MavlinkV2Frame - Frame format parser and encoder - */ -class MavlinkV2Frame { - static START_BYTE = 0xFD; - static HEADER_SIZE = 5; - static FOOTER_SIZE = 2; - static OVERHEAD = 7; - static LENGTH_BYTES = 1; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - reset() { - this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MavlinkV2FrameParserState.LOOKING_FOR_START: - if (byte === MavlinkV2Frame.START_BYTE) { - this.buffer = [byte]; - this.state = MavlinkV2FrameParserState.GETTING_MSG_ID; - } - break; - - case MavlinkV2FrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MavlinkV2FrameParserState.GETTING_LENGTH; - break; - - case MavlinkV2FrameParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MavlinkV2Frame.OVERHEAD + this.msg_length; - this.state = MavlinkV2FrameParserState.GETTING_PAYLOAD; - break; - - case MavlinkV2FrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - MavlinkV2Frame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV2Frame.HEADER_SIZE, this.packet_size - MavlinkV2Frame.FOOTER_SIZE)); - } - this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(MavlinkV2Frame.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < MavlinkV2Frame.OVERHEAD) { - return result; - } - - if (buffer[0] !== MavlinkV2Frame.START_BYTE) { - return result; - } - - const msg_length = buffer.length - MavlinkV2Frame.OVERHEAD; - - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV2Frame.HEADER_SIZE, buffer.length - MavlinkV2Frame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// FrameFormatConfig Frame Format -// ============================================================================= - -const FrameFormatConfigParserState = { - LOOKING_FOR_START1: 0, - LOOKING_FOR_START2: 1, - GETTING_MSG_ID: 2, - GETTING_PAYLOAD: 3 -}; - -/** - * FrameFormatConfig - Frame format parser and encoder - */ -class FrameFormatConfig { - static START_BYTE1 = 0x90; - static START_BYTE2 = 0x91; - static HEADER_SIZE = 2; - static FOOTER_SIZE = 1; - static OVERHEAD = 3; - - constructor(get_msg_length) { - this.get_msg_length = get_msg_length; - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - reset() { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - parse_byte(byte) { - const result = createFrameMsgInfo(); - - switch (this.state) { - case FrameFormatConfigParserState.LOOKING_FOR_START1: - if (byte === FrameFormatConfig.START_BYTE1) { - this.buffer = [byte]; - this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; - } - break; - - case FrameFormatConfigParserState.LOOKING_FOR_START2: - if (byte === FrameFormatConfig.START_BYTE2) { - this.buffer.push(byte); - this.state = FrameFormatConfigParserState.GETTING_MSG_ID; - } else if (byte === FrameFormatConfig.START_BYTE1) { - this.buffer = [byte]; - this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; - } else { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - break; - - case FrameFormatConfigParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = FrameFormatConfig.OVERHEAD + msg_length; - this.state = FrameFormatConfigParserState.GETTING_PAYLOAD; - } else { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - } else { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - break; - - case FrameFormatConfigParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - const msg_length = this.packet_size - FrameFormatConfig.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(FrameFormatConfig.HEADER_SIZE, this.packet_size - FrameFormatConfig.FOOTER_SIZE)); - } - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - static encode(msg_id, msg) { - const output = []; - output.push(FrameFormatConfig.START_BYTE1); - output.push(FrameFormatConfig.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - static validate_packet(buffer) { - const result = createFrameMsgInfo(); - - if (buffer.length < FrameFormatConfig.OVERHEAD) { - return result; - } - - if (buffer[0] !== FrameFormatConfig.START_BYTE1) { - return result; - } - if (buffer[1] !== FrameFormatConfig.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - FrameFormatConfig.OVERHEAD; - - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, FrameFormatConfig.HEADER_SIZE, buffer.length - FrameFormatConfig.FOOTER_SIZE)); - } - - return result; - } -} - - -// Exports -module.exports = { - FrameFormatType, - fletcher_checksum, - createFrameMsgInfo, - MinimalFrame, - MinimalFrameParserState, - BasicFrame, - BasicFrameParserState, - BasicFrameNoCrc, - BasicFrameNoCrcParserState, - TinyFrame, - TinyFrameParserState, - TinyFrameNoCrc, - TinyFrameNoCrcParserState, - MinimalFrameWithLen, - MinimalFrameWithLenParserState, - MinimalFrameWithLenNoCrc, - MinimalFrameWithLenNoCrcParserState, - BasicFrameWithLen, - BasicFrameWithLenParserState, - BasicFrameWithLenNoCrc, - BasicFrameWithLenNoCrcParserState, - TinyFrameWithLen, - TinyFrameWithLenParserState, - TinyFrameWithLenNoCrc, - TinyFrameWithLenNoCrcParserState, - MinimalFrameWithLen16, - MinimalFrameWithLen16ParserState, - MinimalFrameWithLen16NoCrc, - MinimalFrameWithLen16NoCrcParserState, - BasicFrameWithLen16, - BasicFrameWithLen16ParserState, - BasicFrameWithLen16NoCrc, - BasicFrameWithLen16NoCrcParserState, - TinyFrameWithLen16, - TinyFrameWithLen16ParserState, - TinyFrameWithLen16NoCrc, - TinyFrameWithLen16NoCrcParserState, - BasicFrameWithSysComp, - BasicFrameWithSysCompParserState, - UbxFrame, - UbxFrameParserState, - MavlinkV1Frame, - MavlinkV1FrameParserState, - MavlinkV2Frame, - MavlinkV2FrameParserState, - FrameFormatConfig, - FrameFormatConfigParserState, -}; diff --git a/src/struct_frame/boilerplate/js/index.js b/src/struct_frame/boilerplate/js/index.js new file mode 100644 index 00000000..e180ae9b --- /dev/null +++ b/src/struct_frame/boilerplate/js/index.js @@ -0,0 +1,57 @@ +// Automatically generated frame parser package +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +// Base utilities +const frameBase = require('./frame_base'); + +// Individual frame format parsers +const minimal_frame = require('./MinimalFrame'); +const basic_frame = require('./BasicFrame'); +const basic_frame_no_crc = require('./BasicFrameNoCrc'); +const tiny_frame = require('./TinyFrame'); +const tiny_frame_no_crc = require('./TinyFrameNoCrc'); +const minimal_frame_with_len = require('./MinimalFrameWithLen'); +const minimal_frame_with_len_no_crc = require('./MinimalFrameWithLenNoCrc'); +const basic_frame_with_len = require('./BasicFrameWithLen'); +const basic_frame_with_len_no_crc = require('./BasicFrameWithLenNoCrc'); +const tiny_frame_with_len = require('./TinyFrameWithLen'); +const tiny_frame_with_len_no_crc = require('./TinyFrameWithLenNoCrc'); +const minimal_frame_with_len16 = require('./MinimalFrameWithLen16'); +const minimal_frame_with_len16_no_crc = require('./MinimalFrameWithLen16NoCrc'); +const basic_frame_with_len16 = require('./BasicFrameWithLen16'); +const basic_frame_with_len16_no_crc = require('./BasicFrameWithLen16NoCrc'); +const tiny_frame_with_len16 = require('./TinyFrameWithLen16'); +const tiny_frame_with_len16_no_crc = require('./TinyFrameWithLen16NoCrc'); +const basic_frame_with_sys_comp = require('./BasicFrameWithSysComp'); +const ubx_frame = require('./UbxFrame'); +const mavlink_v1_frame = require('./MavlinkV1Frame'); +const mavlink_v2_frame = require('./MavlinkV2Frame'); +const frame_format_config = require('./FrameFormatConfig'); + +module.exports = { + // Base utilities + ...frameBase, + // Frame formats + ...minimal_frame, + ...basic_frame, + ...basic_frame_no_crc, + ...tiny_frame, + ...tiny_frame_no_crc, + ...minimal_frame_with_len, + ...minimal_frame_with_len_no_crc, + ...basic_frame_with_len, + ...basic_frame_with_len_no_crc, + ...tiny_frame_with_len, + ...tiny_frame_with_len_no_crc, + ...minimal_frame_with_len16, + ...minimal_frame_with_len16_no_crc, + ...basic_frame_with_len16, + ...basic_frame_with_len16_no_crc, + ...tiny_frame_with_len16, + ...tiny_frame_with_len16_no_crc, + ...basic_frame_with_sys_comp, + ...ubx_frame, + ...mavlink_v1_frame, + ...mavlink_v2_frame, + ...frame_format_config, +}; diff --git a/src/struct_frame/boilerplate/py/__init__.py b/src/struct_frame/boilerplate/py/__init__.py index e69de29b..772366e3 100644 --- a/src/struct_frame/boilerplate/py/__init__.py +++ b/src/struct_frame/boilerplate/py/__init__.py @@ -0,0 +1,86 @@ +# Automatically generated frame parser package +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +# Base utilities +from .frame_base import ( + FrameFormatType, + FrameMsgInfo, + fletcher_checksum, +) + +# Individual frame format parsers +from .minimal_frame import MinimalFrame, MinimalFrameParserState +from .basic_frame import BasicFrame, BasicFrameParserState +from .basic_frame_no_crc import BasicFrameNoCrc, BasicFrameNoCrcParserState +from .tiny_frame import TinyFrame, TinyFrameParserState +from .tiny_frame_no_crc import TinyFrameNoCrc, TinyFrameNoCrcParserState +from .minimal_frame_with_len import MinimalFrameWithLen, MinimalFrameWithLenParserState +from .minimal_frame_with_len_no_crc import MinimalFrameWithLenNoCrc, MinimalFrameWithLenNoCrcParserState +from .basic_frame_with_len import BasicFrameWithLen, BasicFrameWithLenParserState +from .basic_frame_with_len_no_crc import BasicFrameWithLenNoCrc, BasicFrameWithLenNoCrcParserState +from .tiny_frame_with_len import TinyFrameWithLen, TinyFrameWithLenParserState +from .tiny_frame_with_len_no_crc import TinyFrameWithLenNoCrc, TinyFrameWithLenNoCrcParserState +from .minimal_frame_with_len16 import MinimalFrameWithLen16, MinimalFrameWithLen16ParserState +from .minimal_frame_with_len16_no_crc import MinimalFrameWithLen16NoCrc, MinimalFrameWithLen16NoCrcParserState +from .basic_frame_with_len16 import BasicFrameWithLen16, BasicFrameWithLen16ParserState +from .basic_frame_with_len16_no_crc import BasicFrameWithLen16NoCrc, BasicFrameWithLen16NoCrcParserState +from .tiny_frame_with_len16 import TinyFrameWithLen16, TinyFrameWithLen16ParserState +from .tiny_frame_with_len16_no_crc import TinyFrameWithLen16NoCrc, TinyFrameWithLen16NoCrcParserState +from .basic_frame_with_sys_comp import BasicFrameWithSysComp, BasicFrameWithSysCompParserState +from .ubx_frame import UbxFrame, UbxFrameParserState +from .mavlink_v1_frame import MavlinkV1Frame, MavlinkV1FrameParserState +from .mavlink_v2_frame import MavlinkV2Frame, MavlinkV2FrameParserState +from .frame_format_config import FrameFormatConfig, FrameFormatConfigParserState + +# Re-export all frame formats +__all__ = [ + # Base utilities + "FrameFormatType", + "FrameMsgInfo", + "fletcher_checksum", + # Frame formats + "MinimalFrame", + "MinimalFrameParserState", + "BasicFrame", + "BasicFrameParserState", + "BasicFrameNoCrc", + "BasicFrameNoCrcParserState", + "TinyFrame", + "TinyFrameParserState", + "TinyFrameNoCrc", + "TinyFrameNoCrcParserState", + "MinimalFrameWithLen", + "MinimalFrameWithLenParserState", + "MinimalFrameWithLenNoCrc", + "MinimalFrameWithLenNoCrcParserState", + "BasicFrameWithLen", + "BasicFrameWithLenParserState", + "BasicFrameWithLenNoCrc", + "BasicFrameWithLenNoCrcParserState", + "TinyFrameWithLen", + "TinyFrameWithLenParserState", + "TinyFrameWithLenNoCrc", + "TinyFrameWithLenNoCrcParserState", + "MinimalFrameWithLen16", + "MinimalFrameWithLen16ParserState", + "MinimalFrameWithLen16NoCrc", + "MinimalFrameWithLen16NoCrcParserState", + "BasicFrameWithLen16", + "BasicFrameWithLen16ParserState", + "BasicFrameWithLen16NoCrc", + "BasicFrameWithLen16NoCrcParserState", + "TinyFrameWithLen16", + "TinyFrameWithLen16ParserState", + "TinyFrameWithLen16NoCrc", + "TinyFrameWithLen16NoCrcParserState", + "BasicFrameWithSysComp", + "BasicFrameWithSysCompParserState", + "UbxFrame", + "UbxFrameParserState", + "MavlinkV1Frame", + "MavlinkV1FrameParserState", + "MavlinkV2Frame", + "MavlinkV2FrameParserState", + "FrameFormatConfig", + "FrameFormatConfigParserState", +] diff --git a/src/struct_frame/boilerplate/py/basic_frame.py b/src/struct_frame/boilerplate/py/basic_frame.py new file mode 100644 index 00000000..acc04862 --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame.py @@ -0,0 +1,159 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrame Frame Format +# ============================================================================= + +class BasicFrameParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_PAYLOAD = 3 + + +class BasicFrame: + """ + BasicFrame - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x91 + HEADER_SIZE = 3 + FOOTER_SIZE = 2 + OVERHEAD = 5 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrame parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = BasicFrameParserState.GETTING_PAYLOAD + else: + self.state = BasicFrameParserState.LOOKING_FOR_START1 + else: + self.state = BasicFrameParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = BasicFrameParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrame format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.extend(msg) + ck = fletcher_checksum(output, 2, 2 + len(msg) + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrame packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrame.OVERHEAD: + return result + + if buffer[0] != BasicFrame.START_BYTE1: + return result + if buffer[1] != BasicFrame.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrame.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrame.HEADER_SIZE:len(buffer) - BasicFrame.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/basic_frame_no_crc.py b/src/struct_frame/boilerplate/py/basic_frame_no_crc.py new file mode 100644 index 00000000..dadec44c --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame_no_crc.py @@ -0,0 +1,149 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrameNoCrc Frame Format +# ============================================================================= + +class BasicFrameNoCrcParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_PAYLOAD = 3 + + +class BasicFrameNoCrc: + """ + BasicFrameNoCrc - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x95] [MSG_ID] [MSG...] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x95 + HEADER_SIZE = 3 + FOOTER_SIZE = 0 + OVERHEAD = 3 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrameNoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameNoCrcParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameNoCrcParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameNoCrcParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameNoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = BasicFrameNoCrcParserState.GETTING_PAYLOAD + else: + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 + else: + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameNoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrameNoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrameNoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrameNoCrc.OVERHEAD: + return result + + if buffer[0] != BasicFrameNoCrc.START_BYTE1: + return result + if buffer[1] != BasicFrameNoCrc.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrameNoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrameNoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/basic_frame_with_len.py b/src/struct_frame/boilerplate/py/basic_frame_with_len.py new file mode 100644 index 00000000..99467a2a --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame_with_len.py @@ -0,0 +1,161 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrameWithLen Frame Format +# ============================================================================= + +class BasicFrameWithLenParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_LENGTH = 3 + GETTING_PAYLOAD = 4 + + +class BasicFrameWithLen: + """ + BasicFrameWithLen - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x92] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x92 + HEADER_SIZE = 4 + FOOTER_SIZE = 2 + OVERHEAD = 6 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrameWithLen parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameWithLenParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameWithLenParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLenParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameWithLenParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameWithLenParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLenParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameWithLenParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameWithLenParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = BasicFrameWithLenParserState.GETTING_LENGTH + + elif self.state == BasicFrameWithLenParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = BasicFrameWithLenParserState.GETTING_PAYLOAD + + elif self.state == BasicFrameWithLenParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1 + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = BasicFrameWithLenParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrameWithLen format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 2, 2 + len(msg) + 1 + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrameWithLen packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrameWithLen.OVERHEAD: + return result + + if buffer[0] != BasicFrameWithLen.START_BYTE1: + return result + if buffer[1] != BasicFrameWithLen.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrameWithLen.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrameWithLen.HEADER_SIZE:len(buffer) - BasicFrameWithLen.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/basic_frame_with_len16.py b/src/struct_frame/boilerplate/py/basic_frame_with_len16.py new file mode 100644 index 00000000..17c527e2 --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame_with_len16.py @@ -0,0 +1,166 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrameWithLen16 Frame Format +# ============================================================================= + +class BasicFrameWithLen16ParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_LENGTH = 3 + GETTING_PAYLOAD = 4 + + +class BasicFrameWithLen16: + """ + BasicFrameWithLen16 - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x93] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x93 + HEADER_SIZE = 5 + FOOTER_SIZE = 2 + OVERHEAD = 7 + LENGTH_BYTES = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrameWithLen16 parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + self.length_lo = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameWithLen16ParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameWithLen16ParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameWithLen16ParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameWithLen16ParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = BasicFrameWithLen16ParserState.GETTING_LENGTH + + elif self.state == BasicFrameWithLen16ParserState.GETTING_LENGTH: + self.buffer.append(byte) + if len(self.buffer) == 4: + self.length_lo = byte + else: + self.msg_length = self.length_lo | (byte << 8) + self.packet_size = self.OVERHEAD + self.msg_length + self.state = BasicFrameWithLen16ParserState.GETTING_PAYLOAD + + elif self.state == BasicFrameWithLen16ParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1 + 2) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrameWithLen16 format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.append((len(msg) >> 8) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 2, 2 + len(msg) + 1 + 2) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrameWithLen16 packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrameWithLen16.OVERHEAD: + return result + + if buffer[0] != BasicFrameWithLen16.START_BYTE1: + return result + if buffer[1] != BasicFrameWithLen16.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrameWithLen16.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 2) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrameWithLen16.HEADER_SIZE:len(buffer) - BasicFrameWithLen16.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/basic_frame_with_len16_no_crc.py b/src/struct_frame/boilerplate/py/basic_frame_with_len16_no_crc.py new file mode 100644 index 00000000..44d31343 --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame_with_len16_no_crc.py @@ -0,0 +1,156 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrameWithLen16NoCrc Frame Format +# ============================================================================= + +class BasicFrameWithLen16NoCrcParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_LENGTH = 3 + GETTING_PAYLOAD = 4 + + +class BasicFrameWithLen16NoCrc: + """ + BasicFrameWithLen16NoCrc - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x97] [MSG_ID] [LEN16] [MSG...] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x97 + HEADER_SIZE = 5 + FOOTER_SIZE = 0 + OVERHEAD = 5 + LENGTH_BYTES = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrameWithLen16NoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + self.length_lo = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH + + elif self.state == BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH: + self.buffer.append(byte) + if len(self.buffer) == 4: + self.length_lo = byte + else: + self.msg_length = self.length_lo | (byte << 8) + self.packet_size = self.OVERHEAD + self.msg_length + self.state = BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD + + elif self.state == BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrameWithLen16NoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.append((len(msg) >> 8) & 0xFF) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrameWithLen16NoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrameWithLen16NoCrc.OVERHEAD: + return result + + if buffer[0] != BasicFrameWithLen16NoCrc.START_BYTE1: + return result + if buffer[1] != BasicFrameWithLen16NoCrc.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrameWithLen16NoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrameWithLen16NoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/basic_frame_with_len_no_crc.py b/src/struct_frame/boilerplate/py/basic_frame_with_len_no_crc.py new file mode 100644 index 00000000..1580ed56 --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame_with_len_no_crc.py @@ -0,0 +1,151 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrameWithLenNoCrc Frame Format +# ============================================================================= + +class BasicFrameWithLenNoCrcParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_LENGTH = 3 + GETTING_PAYLOAD = 4 + + +class BasicFrameWithLenNoCrc: + """ + BasicFrameWithLenNoCrc - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x96] [MSG_ID] [LEN] [MSG...] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x96 + HEADER_SIZE = 4 + FOOTER_SIZE = 0 + OVERHEAD = 4 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrameWithLenNoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = BasicFrameWithLenNoCrcParserState.GETTING_LENGTH + + elif self.state == BasicFrameWithLenNoCrcParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD + + elif self.state == BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrameWithLenNoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrameWithLenNoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrameWithLenNoCrc.OVERHEAD: + return result + + if buffer[0] != BasicFrameWithLenNoCrc.START_BYTE1: + return result + if buffer[1] != BasicFrameWithLenNoCrc.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrameWithLenNoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrameWithLenNoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/basic_frame_with_sys_comp.py b/src/struct_frame/boilerplate/py/basic_frame_with_sys_comp.py new file mode 100644 index 00000000..c7f2e78e --- /dev/null +++ b/src/struct_frame/boilerplate/py/basic_frame_with_sys_comp.py @@ -0,0 +1,159 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# BasicFrameWithSysComp Frame Format +# ============================================================================= + +class BasicFrameWithSysCompParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_PAYLOAD = 3 + + +class BasicFrameWithSysComp: + """ + BasicFrameWithSysComp - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x94] [MSG_ID] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x94 + HEADER_SIZE = 3 + FOOTER_SIZE = 2 + OVERHEAD = 5 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the BasicFrameWithSysComp parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == BasicFrameWithSysCompParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2 + + elif self.state == BasicFrameWithSysCompParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = BasicFrameWithSysCompParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2 + else: + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameWithSysCompParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = BasicFrameWithSysCompParserState.GETTING_PAYLOAD + else: + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 + else: + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 + + elif self.state == BasicFrameWithSysCompParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with BasicFrameWithSysComp format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.extend(msg) + ck = fletcher_checksum(output, 2, 2 + len(msg) + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete BasicFrameWithSysComp packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < BasicFrameWithSysComp.OVERHEAD: + return result + + if buffer[0] != BasicFrameWithSysComp.START_BYTE1: + return result + if buffer[1] != BasicFrameWithSysComp.START_BYTE2: + return result + + msg_length = len(buffer) - BasicFrameWithSysComp.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[BasicFrameWithSysComp.HEADER_SIZE:len(buffer) - BasicFrameWithSysComp.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/frame_base.py b/src/struct_frame/boilerplate/py/frame_base.py new file mode 100644 index 00000000..82c3000f --- /dev/null +++ b/src/struct_frame/boilerplate/py/frame_base.py @@ -0,0 +1,55 @@ +# Automatically generated frame parser base utilities +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import List, Tuple, Union +from dataclasses import dataclass + +# Frame format type enumeration +class FrameFormatType(Enum): + MINIMAL_FRAME = 0 + BASIC_FRAME = 1 + BASIC_FRAME_NO_CRC = 2 + TINY_FRAME = 3 + TINY_FRAME_NO_CRC = 4 + MINIMAL_FRAME_WITH_LEN = 5 + MINIMAL_FRAME_WITH_LEN_NO_CRC = 6 + BASIC_FRAME_WITH_LEN = 7 + BASIC_FRAME_WITH_LEN_NO_CRC = 8 + TINY_FRAME_WITH_LEN = 9 + TINY_FRAME_WITH_LEN_NO_CRC = 10 + MINIMAL_FRAME_WITH_LEN16 = 11 + MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12 + BASIC_FRAME_WITH_LEN16 = 13 + BASIC_FRAME_WITH_LEN16_NO_CRC = 14 + TINY_FRAME_WITH_LEN16 = 15 + TINY_FRAME_WITH_LEN16_NO_CRC = 16 + BASIC_FRAME_WITH_SYS_COMP = 17 + UBX_FRAME = 18 + MAVLINK_V1_FRAME = 19 + MAVLINK_V2_FRAME = 20 + FRAME_FORMAT_CONFIG = 21 + + +def fletcher_checksum(buffer: Union[bytes, List[int]], start: int = 0, end: int = None) -> Tuple[int, int]: + """Calculate Fletcher-16 checksum over the given data""" + if end is None: + end = len(buffer) + + byte1 = 0 + byte2 = 0 + + for x in range(start, end): + byte1 = (byte1 + buffer[x]) % 256 + byte2 = (byte2 + byte1) % 256 + + return (byte1, byte2) + + +@dataclass +class FrameMsgInfo: + """Parse result containing message information""" + valid: bool = False + msg_id: int = 0 + msg_len: int = 0 + msg_data: bytes = b'' diff --git a/src/struct_frame/boilerplate/py/frame_format_config.py b/src/struct_frame/boilerplate/py/frame_format_config.py new file mode 100644 index 00000000..893b3cf6 --- /dev/null +++ b/src/struct_frame/boilerplate/py/frame_format_config.py @@ -0,0 +1,159 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# FrameFormatConfig Frame Format +# ============================================================================= + +class FrameFormatConfigParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_PAYLOAD = 3 + + +class FrameFormatConfig: + """ + FrameFormatConfig - Frame format parser and encoder + + Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE1 = 0x90 + START_BYTE2 = 0x91 + HEADER_SIZE = 2 + FOOTER_SIZE = 1 + OVERHEAD = 3 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the FrameFormatConfig parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == FrameFormatConfigParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = FrameFormatConfigParserState.LOOKING_FOR_START2 + + elif self.state == FrameFormatConfigParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = FrameFormatConfigParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = FrameFormatConfigParserState.LOOKING_FOR_START2 + else: + self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 + + elif self.state == FrameFormatConfigParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = FrameFormatConfigParserState.GETTING_PAYLOAD + else: + self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 + else: + self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 + + elif self.state == FrameFormatConfigParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with FrameFormatConfig format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.extend(msg) + ck = fletcher_checksum(output, 2, 2 + len(msg) + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete FrameFormatConfig packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < FrameFormatConfig.OVERHEAD: + return result + + if buffer[0] != FrameFormatConfig.START_BYTE1: + return result + if buffer[1] != FrameFormatConfig.START_BYTE2: + return result + + msg_length = len(buffer) - FrameFormatConfig.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[FrameFormatConfig.HEADER_SIZE:len(buffer) - FrameFormatConfig.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/frame_parsers_gen.py b/src/struct_frame/boilerplate/py/frame_parsers_gen.py deleted file mode 100644 index 569a3bd7..00000000 --- a/src/struct_frame/boilerplate/py/frame_parsers_gen.py +++ /dev/null @@ -1,3180 +0,0 @@ -# Automatically generated frame parser -# Generated by 0.0.1 at Wed Dec 3 09:37:56 2025. - -from enum import Enum -from typing import Optional, Callable, Dict, List, Tuple, Union -from dataclasses import dataclass - -# Frame format type enumeration -class FrameFormatType(Enum): - MINIMAL_FRAME = 0 - BASIC_FRAME = 1 - BASIC_FRAME_NO_CRC = 2 - TINY_FRAME = 3 - TINY_FRAME_NO_CRC = 4 - MINIMAL_FRAME_WITH_LEN = 5 - MINIMAL_FRAME_WITH_LEN_NO_CRC = 6 - BASIC_FRAME_WITH_LEN = 7 - BASIC_FRAME_WITH_LEN_NO_CRC = 8 - TINY_FRAME_WITH_LEN = 9 - TINY_FRAME_WITH_LEN_NO_CRC = 10 - MINIMAL_FRAME_WITH_LEN16 = 11 - MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12 - BASIC_FRAME_WITH_LEN16 = 13 - BASIC_FRAME_WITH_LEN16_NO_CRC = 14 - TINY_FRAME_WITH_LEN16 = 15 - TINY_FRAME_WITH_LEN16_NO_CRC = 16 - BASIC_FRAME_WITH_SYS_COMP = 17 - UBX_FRAME = 18 - MAVLINK_V1_FRAME = 19 - MAVLINK_V2_FRAME = 20 - FRAME_FORMAT_CONFIG = 21 - - -def fletcher_checksum(buffer: Union[bytes, List[int]], start: int = 0, end: int = None) -> Tuple[int, int]: - """Calculate Fletcher-16 checksum over the given data""" - if end is None: - end = len(buffer) - - byte1 = 0 - byte2 = 0 - - for x in range(start, end): - byte1 = (byte1 + buffer[x]) % 256 - byte2 = (byte2 + byte1) % 256 - - return (byte1, byte2) - - -@dataclass -class FrameMsgInfo: - """Parse result containing message information""" - valid: bool = False - msg_id: int = 0 - msg_len: int = 0 - msg_data: bytes = b'' - - -# ============================================================================= -# MinimalFrame Frame Format -# ============================================================================= - -class MinimalFrameParserState(Enum): - GETTING_MSG_ID = 0 - GETTING_PAYLOAD = 1 - - -class MinimalFrame: - """ - MinimalFrame - Frame format parser and encoder - - Format: [MSG_ID] [MSG...] [CRC1] [CRC2] - """ - - HEADER_SIZE = 1 - FOOTER_SIZE = 2 - OVERHEAD = 3 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MinimalFrame parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MinimalFrameParserState.GETTING_MSG_ID - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MinimalFrameParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = MinimalFrameParserState.GETTING_PAYLOAD - else: - self.state = MinimalFrameParserState.GETTING_MSG_ID - else: - self.state = MinimalFrameParserState.GETTING_MSG_ID - - elif self.state == MinimalFrameParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 0, 0 + msg_length + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = MinimalFrameParserState.GETTING_MSG_ID - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MinimalFrame format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(msg_id) - output.extend(msg) - ck = fletcher_checksum(output, 0, 0 + len(msg) + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MinimalFrame packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MinimalFrame.OVERHEAD: - return result - - - msg_length = len(buffer) - MinimalFrame.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[0] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MinimalFrame.HEADER_SIZE:len(buffer) - MinimalFrame.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# BasicFrame Frame Format -# ============================================================================= - -class BasicFrameParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_PAYLOAD = 3 - - -class BasicFrame: - """ - BasicFrame - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x91 - HEADER_SIZE = 3 - FOOTER_SIZE = 2 - OVERHEAD = 5 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrame parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = BasicFrameParserState.GETTING_PAYLOAD - else: - self.state = BasicFrameParserState.LOOKING_FOR_START1 - else: - self.state = BasicFrameParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = BasicFrameParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrame format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.extend(msg) - ck = fletcher_checksum(output, 2, 2 + len(msg) + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrame packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrame.OVERHEAD: - return result - - if buffer[0] != BasicFrame.START_BYTE1: - return result - if buffer[1] != BasicFrame.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrame.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrame.HEADER_SIZE:len(buffer) - BasicFrame.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# BasicFrameNoCrc Frame Format -# ============================================================================= - -class BasicFrameNoCrcParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_PAYLOAD = 3 - - -class BasicFrameNoCrc: - """ - BasicFrameNoCrc - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x95] [MSG_ID] [MSG...] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x95 - HEADER_SIZE = 3 - FOOTER_SIZE = 0 - OVERHEAD = 3 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrameNoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameNoCrcParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameNoCrcParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameNoCrcParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameNoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = BasicFrameNoCrcParserState.GETTING_PAYLOAD - else: - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 - else: - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameNoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrameNoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrameNoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrameNoCrc.OVERHEAD: - return result - - if buffer[0] != BasicFrameNoCrc.START_BYTE1: - return result - if buffer[1] != BasicFrameNoCrc.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrameNoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrameNoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# TinyFrame Frame Format -# ============================================================================= - -class TinyFrameParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_PAYLOAD = 2 - - -class TinyFrame: - """ - TinyFrame - Frame format parser and encoder - - Format: [START_BYTE=0x70] [MSG_ID] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE = 0x70 - HEADER_SIZE = 2 - FOOTER_SIZE = 2 - OVERHEAD = 4 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the TinyFrame parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = TinyFrameParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == TinyFrameParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = TinyFrameParserState.GETTING_MSG_ID - - elif self.state == TinyFrameParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = TinyFrameParserState.GETTING_PAYLOAD - else: - self.state = TinyFrameParserState.LOOKING_FOR_START - else: - self.state = TinyFrameParserState.LOOKING_FOR_START - - elif self.state == TinyFrameParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = TinyFrameParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with TinyFrame format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.extend(msg) - ck = fletcher_checksum(output, 1, 1 + len(msg) + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete TinyFrame packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < TinyFrame.OVERHEAD: - return result - - if buffer[0] != TinyFrame.START_BYTE: - return result - - msg_length = len(buffer) - TinyFrame.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[TinyFrame.HEADER_SIZE:len(buffer) - TinyFrame.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# TinyFrameNoCrc Frame Format -# ============================================================================= - -class TinyFrameNoCrcParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_PAYLOAD = 2 - - -class TinyFrameNoCrc: - """ - TinyFrameNoCrc - Frame format parser and encoder - - Format: [START_BYTE=0x72] [MSG_ID] [MSG...] - """ - - START_BYTE = 0x72 - HEADER_SIZE = 2 - FOOTER_SIZE = 0 - OVERHEAD = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the TinyFrameNoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == TinyFrameNoCrcParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = TinyFrameNoCrcParserState.GETTING_MSG_ID - - elif self.state == TinyFrameNoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = TinyFrameNoCrcParserState.GETTING_PAYLOAD - else: - self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START - else: - self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START - - elif self.state == TinyFrameNoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with TinyFrameNoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete TinyFrameNoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < TinyFrameNoCrc.OVERHEAD: - return result - - if buffer[0] != TinyFrameNoCrc.START_BYTE: - return result - - msg_length = len(buffer) - TinyFrameNoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[TinyFrameNoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# MinimalFrameWithLen Frame Format -# ============================================================================= - -class MinimalFrameWithLenParserState(Enum): - GETTING_MSG_ID = 0 - GETTING_LENGTH = 1 - GETTING_PAYLOAD = 2 - - -class MinimalFrameWithLen: - """ - MinimalFrameWithLen - Frame format parser and encoder - - Format: [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - """ - - HEADER_SIZE = 2 - FOOTER_SIZE = 2 - OVERHEAD = 4 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MinimalFrameWithLen parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MinimalFrameWithLenParserState.GETTING_MSG_ID - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MinimalFrameWithLenParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = MinimalFrameWithLenParserState.GETTING_LENGTH - - elif self.state == MinimalFrameWithLenParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = MinimalFrameWithLenParserState.GETTING_PAYLOAD - - elif self.state == MinimalFrameWithLenParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 0, 0 + msg_length + 1 + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = MinimalFrameWithLenParserState.GETTING_MSG_ID - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MinimalFrameWithLen format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 0, 0 + len(msg) + 1 + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MinimalFrameWithLen packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MinimalFrameWithLen.OVERHEAD: - return result - - - msg_length = len(buffer) - MinimalFrameWithLen.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[0] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MinimalFrameWithLen.HEADER_SIZE:len(buffer) - MinimalFrameWithLen.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# MinimalFrameWithLenNoCrc Frame Format -# ============================================================================= - -class MinimalFrameWithLenNoCrcParserState(Enum): - GETTING_MSG_ID = 0 - GETTING_LENGTH = 1 - GETTING_PAYLOAD = 2 - - -class MinimalFrameWithLenNoCrc: - """ - MinimalFrameWithLenNoCrc - Frame format parser and encoder - - Format: [MSG_ID] [LEN] [MSG...] - """ - - HEADER_SIZE = 2 - FOOTER_SIZE = 0 - OVERHEAD = 2 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MinimalFrameWithLenNoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH - - elif self.state == MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD - - elif self.state == MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MinimalFrameWithLenNoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MinimalFrameWithLenNoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MinimalFrameWithLenNoCrc.OVERHEAD: - return result - - - msg_length = len(buffer) - MinimalFrameWithLenNoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[0] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MinimalFrameWithLenNoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# BasicFrameWithLen Frame Format -# ============================================================================= - -class BasicFrameWithLenParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_LENGTH = 3 - GETTING_PAYLOAD = 4 - - -class BasicFrameWithLen: - """ - BasicFrameWithLen - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x92] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x92 - HEADER_SIZE = 4 - FOOTER_SIZE = 2 - OVERHEAD = 6 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrameWithLen parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameWithLenParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameWithLenParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLenParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameWithLenParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameWithLenParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLenParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameWithLenParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameWithLenParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = BasicFrameWithLenParserState.GETTING_LENGTH - - elif self.state == BasicFrameWithLenParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = BasicFrameWithLenParserState.GETTING_PAYLOAD - - elif self.state == BasicFrameWithLenParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1 + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = BasicFrameWithLenParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrameWithLen format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 2, 2 + len(msg) + 1 + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrameWithLen packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrameWithLen.OVERHEAD: - return result - - if buffer[0] != BasicFrameWithLen.START_BYTE1: - return result - if buffer[1] != BasicFrameWithLen.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrameWithLen.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrameWithLen.HEADER_SIZE:len(buffer) - BasicFrameWithLen.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# BasicFrameWithLenNoCrc Frame Format -# ============================================================================= - -class BasicFrameWithLenNoCrcParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_LENGTH = 3 - GETTING_PAYLOAD = 4 - - -class BasicFrameWithLenNoCrc: - """ - BasicFrameWithLenNoCrc - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x96] [MSG_ID] [LEN] [MSG...] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x96 - HEADER_SIZE = 4 - FOOTER_SIZE = 0 - OVERHEAD = 4 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrameWithLenNoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = BasicFrameWithLenNoCrcParserState.GETTING_LENGTH - - elif self.state == BasicFrameWithLenNoCrcParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD - - elif self.state == BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrameWithLenNoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrameWithLenNoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrameWithLenNoCrc.OVERHEAD: - return result - - if buffer[0] != BasicFrameWithLenNoCrc.START_BYTE1: - return result - if buffer[1] != BasicFrameWithLenNoCrc.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrameWithLenNoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrameWithLenNoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# TinyFrameWithLen Frame Format -# ============================================================================= - -class TinyFrameWithLenParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_LENGTH = 2 - GETTING_PAYLOAD = 3 - - -class TinyFrameWithLen: - """ - TinyFrameWithLen - Frame format parser and encoder - - Format: [START_BYTE=0x71] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE = 0x71 - HEADER_SIZE = 3 - FOOTER_SIZE = 2 - OVERHEAD = 5 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the TinyFrameWithLen parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = TinyFrameWithLenParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == TinyFrameWithLenParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = TinyFrameWithLenParserState.GETTING_MSG_ID - - elif self.state == TinyFrameWithLenParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = TinyFrameWithLenParserState.GETTING_LENGTH - - elif self.state == TinyFrameWithLenParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = TinyFrameWithLenParserState.GETTING_PAYLOAD - - elif self.state == TinyFrameWithLenParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = TinyFrameWithLenParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with TinyFrameWithLen format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete TinyFrameWithLen packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < TinyFrameWithLen.OVERHEAD: - return result - - if buffer[0] != TinyFrameWithLen.START_BYTE: - return result - - msg_length = len(buffer) - TinyFrameWithLen.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[TinyFrameWithLen.HEADER_SIZE:len(buffer) - TinyFrameWithLen.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# TinyFrameWithLenNoCrc Frame Format -# ============================================================================= - -class TinyFrameWithLenNoCrcParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_LENGTH = 2 - GETTING_PAYLOAD = 3 - - -class TinyFrameWithLenNoCrc: - """ - TinyFrameWithLenNoCrc - Frame format parser and encoder - - Format: [START_BYTE=0x73] [MSG_ID] [LEN] [MSG...] - """ - - START_BYTE = 0x73 - HEADER_SIZE = 3 - FOOTER_SIZE = 0 - OVERHEAD = 3 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the TinyFrameWithLenNoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID - - elif self.state == TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = TinyFrameWithLenNoCrcParserState.GETTING_LENGTH - - elif self.state == TinyFrameWithLenNoCrcParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD - - elif self.state == TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with TinyFrameWithLenNoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete TinyFrameWithLenNoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < TinyFrameWithLenNoCrc.OVERHEAD: - return result - - if buffer[0] != TinyFrameWithLenNoCrc.START_BYTE: - return result - - msg_length = len(buffer) - TinyFrameWithLenNoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[TinyFrameWithLenNoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# MinimalFrameWithLen16 Frame Format -# ============================================================================= - -class MinimalFrameWithLen16ParserState(Enum): - GETTING_MSG_ID = 0 - GETTING_LENGTH = 1 - GETTING_PAYLOAD = 2 - - -class MinimalFrameWithLen16: - """ - MinimalFrameWithLen16 - Frame format parser and encoder - - Format: [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] - """ - - HEADER_SIZE = 3 - FOOTER_SIZE = 2 - OVERHEAD = 5 - LENGTH_BYTES = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MinimalFrameWithLen16 parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - self.length_lo = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MinimalFrameWithLen16ParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = MinimalFrameWithLen16ParserState.GETTING_LENGTH - - elif self.state == MinimalFrameWithLen16ParserState.GETTING_LENGTH: - self.buffer.append(byte) - if len(self.buffer) == 2: - self.length_lo = byte - else: - self.msg_length = self.length_lo | (byte << 8) - self.packet_size = self.OVERHEAD + self.msg_length - self.state = MinimalFrameWithLen16ParserState.GETTING_PAYLOAD - - elif self.state == MinimalFrameWithLen16ParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 0, 0 + msg_length + 1 + 2) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MinimalFrameWithLen16 format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.append((len(msg) >> 8) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 0, 0 + len(msg) + 1 + 2) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MinimalFrameWithLen16 packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MinimalFrameWithLen16.OVERHEAD: - return result - - - msg_length = len(buffer) - MinimalFrameWithLen16.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 2) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[0] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MinimalFrameWithLen16.HEADER_SIZE:len(buffer) - MinimalFrameWithLen16.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# MinimalFrameWithLen16NoCrc Frame Format -# ============================================================================= - -class MinimalFrameWithLen16NoCrcParserState(Enum): - GETTING_MSG_ID = 0 - GETTING_LENGTH = 1 - GETTING_PAYLOAD = 2 - - -class MinimalFrameWithLen16NoCrc: - """ - MinimalFrameWithLen16NoCrc - Frame format parser and encoder - - Format: [MSG_ID] [LEN16] [MSG...] - """ - - HEADER_SIZE = 3 - FOOTER_SIZE = 0 - OVERHEAD = 3 - LENGTH_BYTES = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MinimalFrameWithLen16NoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - self.length_lo = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH - - elif self.state == MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH: - self.buffer.append(byte) - if len(self.buffer) == 2: - self.length_lo = byte - else: - self.msg_length = self.length_lo | (byte << 8) - self.packet_size = self.OVERHEAD + self.msg_length - self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD - - elif self.state == MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MinimalFrameWithLen16NoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.append((len(msg) >> 8) & 0xFF) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MinimalFrameWithLen16NoCrc.OVERHEAD: - return result - - - msg_length = len(buffer) - MinimalFrameWithLen16NoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[0] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MinimalFrameWithLen16NoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# BasicFrameWithLen16 Frame Format -# ============================================================================= - -class BasicFrameWithLen16ParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_LENGTH = 3 - GETTING_PAYLOAD = 4 - - -class BasicFrameWithLen16: - """ - BasicFrameWithLen16 - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x93] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x93 - HEADER_SIZE = 5 - FOOTER_SIZE = 2 - OVERHEAD = 7 - LENGTH_BYTES = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrameWithLen16 parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - self.length_lo = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameWithLen16ParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameWithLen16ParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameWithLen16ParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameWithLen16ParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = BasicFrameWithLen16ParserState.GETTING_LENGTH - - elif self.state == BasicFrameWithLen16ParserState.GETTING_LENGTH: - self.buffer.append(byte) - if len(self.buffer) == 4: - self.length_lo = byte - else: - self.msg_length = self.length_lo | (byte << 8) - self.packet_size = self.OVERHEAD + self.msg_length - self.state = BasicFrameWithLen16ParserState.GETTING_PAYLOAD - - elif self.state == BasicFrameWithLen16ParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1 + 2) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrameWithLen16 format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.append((len(msg) >> 8) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 2, 2 + len(msg) + 1 + 2) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrameWithLen16 packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrameWithLen16.OVERHEAD: - return result - - if buffer[0] != BasicFrameWithLen16.START_BYTE1: - return result - if buffer[1] != BasicFrameWithLen16.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrameWithLen16.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 2) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrameWithLen16.HEADER_SIZE:len(buffer) - BasicFrameWithLen16.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# BasicFrameWithLen16NoCrc Frame Format -# ============================================================================= - -class BasicFrameWithLen16NoCrcParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_LENGTH = 3 - GETTING_PAYLOAD = 4 - - -class BasicFrameWithLen16NoCrc: - """ - BasicFrameWithLen16NoCrc - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x97] [MSG_ID] [LEN16] [MSG...] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x97 - HEADER_SIZE = 5 - FOOTER_SIZE = 0 - OVERHEAD = 5 - LENGTH_BYTES = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrameWithLen16NoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - self.length_lo = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH - - elif self.state == BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH: - self.buffer.append(byte) - if len(self.buffer) == 4: - self.length_lo = byte - else: - self.msg_length = self.length_lo | (byte << 8) - self.packet_size = self.OVERHEAD + self.msg_length - self.state = BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD - - elif self.state == BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrameWithLen16NoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.append((len(msg) >> 8) & 0xFF) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrameWithLen16NoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrameWithLen16NoCrc.OVERHEAD: - return result - - if buffer[0] != BasicFrameWithLen16NoCrc.START_BYTE1: - return result - if buffer[1] != BasicFrameWithLen16NoCrc.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrameWithLen16NoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrameWithLen16NoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# TinyFrameWithLen16 Frame Format -# ============================================================================= - -class TinyFrameWithLen16ParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_LENGTH = 2 - GETTING_PAYLOAD = 3 - - -class TinyFrameWithLen16: - """ - TinyFrameWithLen16 - Frame format parser and encoder - - Format: [START_BYTE=0x74] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE = 0x74 - HEADER_SIZE = 4 - FOOTER_SIZE = 2 - OVERHEAD = 6 - LENGTH_BYTES = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the TinyFrameWithLen16 parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - self.length_lo = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == TinyFrameWithLen16ParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = TinyFrameWithLen16ParserState.GETTING_MSG_ID - - elif self.state == TinyFrameWithLen16ParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = TinyFrameWithLen16ParserState.GETTING_LENGTH - - elif self.state == TinyFrameWithLen16ParserState.GETTING_LENGTH: - self.buffer.append(byte) - if len(self.buffer) == 3: - self.length_lo = byte - else: - self.msg_length = self.length_lo | (byte << 8) - self.packet_size = self.OVERHEAD + self.msg_length - self.state = TinyFrameWithLen16ParserState.GETTING_PAYLOAD - - elif self.state == TinyFrameWithLen16ParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 2) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with TinyFrameWithLen16 format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.append((len(msg) >> 8) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 2) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete TinyFrameWithLen16 packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < TinyFrameWithLen16.OVERHEAD: - return result - - if buffer[0] != TinyFrameWithLen16.START_BYTE: - return result - - msg_length = len(buffer) - TinyFrameWithLen16.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 2) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[TinyFrameWithLen16.HEADER_SIZE:len(buffer) - TinyFrameWithLen16.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# TinyFrameWithLen16NoCrc Frame Format -# ============================================================================= - -class TinyFrameWithLen16NoCrcParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_LENGTH = 2 - GETTING_PAYLOAD = 3 - - -class TinyFrameWithLen16NoCrc: - """ - TinyFrameWithLen16NoCrc - Frame format parser and encoder - - Format: [START_BYTE=0x75] [MSG_ID] [LEN16] [MSG...] - """ - - START_BYTE = 0x75 - HEADER_SIZE = 4 - FOOTER_SIZE = 0 - OVERHEAD = 4 - LENGTH_BYTES = 2 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the TinyFrameWithLen16NoCrc parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - self.length_lo = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID - - elif self.state == TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH - - elif self.state == TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH: - self.buffer.append(byte) - if len(self.buffer) == 3: - self.length_lo = byte - else: - self.msg_length = self.length_lo | (byte << 8) - self.packet_size = self.OVERHEAD + self.msg_length - self.state = TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD - - elif self.state == TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = self.packet_size - self.OVERHEAD - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) - self.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with TinyFrameWithLen16NoCrc format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.append((len(msg) >> 8) & 0xFF) - output.extend(msg) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete TinyFrameWithLen16NoCrc packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < TinyFrameWithLen16NoCrc.OVERHEAD: - return result - - if buffer[0] != TinyFrameWithLen16NoCrc.START_BYTE: - return result - - msg_length = len(buffer) - TinyFrameWithLen16NoCrc.OVERHEAD - - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[TinyFrameWithLen16NoCrc.HEADER_SIZE:]) - - return result - - -# ============================================================================= -# BasicFrameWithSysComp Frame Format -# ============================================================================= - -class BasicFrameWithSysCompParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_PAYLOAD = 3 - - -class BasicFrameWithSysComp: - """ - BasicFrameWithSysComp - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x94] [MSG_ID] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x94 - HEADER_SIZE = 3 - FOOTER_SIZE = 2 - OVERHEAD = 5 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the BasicFrameWithSysComp parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == BasicFrameWithSysCompParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2 - - elif self.state == BasicFrameWithSysCompParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = BasicFrameWithSysCompParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2 - else: - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameWithSysCompParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = BasicFrameWithSysCompParserState.GETTING_PAYLOAD - else: - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 - else: - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 - - elif self.state == BasicFrameWithSysCompParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with BasicFrameWithSysComp format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.extend(msg) - ck = fletcher_checksum(output, 2, 2 + len(msg) + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete BasicFrameWithSysComp packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < BasicFrameWithSysComp.OVERHEAD: - return result - - if buffer[0] != BasicFrameWithSysComp.START_BYTE1: - return result - if buffer[1] != BasicFrameWithSysComp.START_BYTE2: - return result - - msg_length = len(buffer) - BasicFrameWithSysComp.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[BasicFrameWithSysComp.HEADER_SIZE:len(buffer) - BasicFrameWithSysComp.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# UbxFrame Frame Format -# ============================================================================= - -class UbxFrameParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_LENGTH = 3 - GETTING_PAYLOAD = 4 - - -class UbxFrame: - """ - UbxFrame - Frame format parser and encoder - - Format: [SYNC1=0xB5] [SYNC2=0x62] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE1 = 0xB5 - START_BYTE2 = 0x62 - HEADER_SIZE = 5 - FOOTER_SIZE = 2 - OVERHEAD = 7 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the UbxFrame parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = UbxFrameParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == UbxFrameParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = UbxFrameParserState.LOOKING_FOR_START2 - - elif self.state == UbxFrameParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = UbxFrameParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = UbxFrameParserState.LOOKING_FOR_START2 - else: - self.state = UbxFrameParserState.LOOKING_FOR_START1 - - elif self.state == UbxFrameParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = UbxFrameParserState.GETTING_LENGTH - - elif self.state == UbxFrameParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = UbxFrameParserState.GETTING_PAYLOAD - - elif self.state == UbxFrameParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1 + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = UbxFrameParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with UbxFrame format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 2, 2 + len(msg) + 1 + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete UbxFrame packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < UbxFrame.OVERHEAD: - return result - - if buffer[0] != UbxFrame.START_BYTE1: - return result - if buffer[1] != UbxFrame.START_BYTE2: - return result - - msg_length = len(buffer) - UbxFrame.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[UbxFrame.HEADER_SIZE:len(buffer) - UbxFrame.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# MavlinkV1Frame Frame Format -# ============================================================================= - -class MavlinkV1FrameParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_LENGTH = 2 - GETTING_PAYLOAD = 3 - - -class MavlinkV1Frame: - """ - MavlinkV1Frame - Frame format parser and encoder - - Format: [STX=0xFE] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE = 0xFE - HEADER_SIZE = 3 - FOOTER_SIZE = 2 - OVERHEAD = 5 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MavlinkV1Frame parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MavlinkV1FrameParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MavlinkV1FrameParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = MavlinkV1FrameParserState.GETTING_MSG_ID - - elif self.state == MavlinkV1FrameParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = MavlinkV1FrameParserState.GETTING_LENGTH - - elif self.state == MavlinkV1FrameParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = MavlinkV1FrameParserState.GETTING_PAYLOAD - - elif self.state == MavlinkV1FrameParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = MavlinkV1FrameParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MavlinkV1Frame format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MavlinkV1Frame packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MavlinkV1Frame.OVERHEAD: - return result - - if buffer[0] != MavlinkV1Frame.START_BYTE: - return result - - msg_length = len(buffer) - MavlinkV1Frame.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MavlinkV1Frame.HEADER_SIZE:len(buffer) - MavlinkV1Frame.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# MavlinkV2Frame Frame Format -# ============================================================================= - -class MavlinkV2FrameParserState(Enum): - LOOKING_FOR_START = 0 - GETTING_MSG_ID = 1 - GETTING_LENGTH = 2 - GETTING_PAYLOAD = 3 - - -class MavlinkV2Frame: - """ - MavlinkV2Frame - Frame format parser and encoder - - Format: [STX=0xFD] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE = 0xFD - HEADER_SIZE = 5 - FOOTER_SIZE = 2 - OVERHEAD = 7 - LENGTH_BYTES = 1 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the MavlinkV2Frame parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = MavlinkV2FrameParserState.LOOKING_FOR_START - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - self.msg_length = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == MavlinkV2FrameParserState.LOOKING_FOR_START: - if byte == self.START_BYTE: - self.buffer = [byte] - self.state = MavlinkV2FrameParserState.GETTING_MSG_ID - - elif self.state == MavlinkV2FrameParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - self.state = MavlinkV2FrameParserState.GETTING_LENGTH - - elif self.state == MavlinkV2FrameParserState.GETTING_LENGTH: - self.buffer.append(byte) - self.msg_length = byte - self.packet_size = self.OVERHEAD + self.msg_length - self.state = MavlinkV2FrameParserState.GETTING_PAYLOAD - - elif self.state == MavlinkV2FrameParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = MavlinkV2FrameParserState.LOOKING_FOR_START - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with MavlinkV2Frame format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE) - output.append(msg_id) - output.append(len(msg) & 0xFF) - output.extend(msg) - ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete MavlinkV2Frame packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < MavlinkV2Frame.OVERHEAD: - return result - - if buffer[0] != MavlinkV2Frame.START_BYTE: - return result - - msg_length = len(buffer) - MavlinkV2Frame.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[1] - result.msg_len = msg_length - result.msg_data = bytes(buffer[MavlinkV2Frame.HEADER_SIZE:len(buffer) - MavlinkV2Frame.FOOTER_SIZE]) - - return result - - -# ============================================================================= -# FrameFormatConfig Frame Format -# ============================================================================= - -class FrameFormatConfigParserState(Enum): - LOOKING_FOR_START1 = 0 - LOOKING_FOR_START2 = 1 - GETTING_MSG_ID = 2 - GETTING_PAYLOAD = 3 - - -class FrameFormatConfig: - """ - FrameFormatConfig - Frame format parser and encoder - - Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x91 - HEADER_SIZE = 2 - FOOTER_SIZE = 1 - OVERHEAD = 3 - - def __init__(self, get_msg_length: Callable[[int], int] = None): - """ - Initialize the FrameFormatConfig parser - - Args: - get_msg_length: Callback function to get message length from msg_id - Required for formats without a length field - """ - self.get_msg_length = get_msg_length - self.reset() - - def reset(self): - """Reset parser state""" - self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 - self.buffer = [] - self.packet_size = 0 - self.msg_id = 0 - - def parse_byte(self, byte: int) -> FrameMsgInfo: - """ - Parse a single byte - - Returns: - FrameMsgInfo with valid=True when a complete valid message is received - """ - result = FrameMsgInfo() - - if self.state == FrameFormatConfigParserState.LOOKING_FOR_START1: - if byte == self.START_BYTE1: - self.buffer = [byte] - self.state = FrameFormatConfigParserState.LOOKING_FOR_START2 - - elif self.state == FrameFormatConfigParserState.LOOKING_FOR_START2: - if byte == self.START_BYTE2: - self.buffer.append(byte) - self.state = FrameFormatConfigParserState.GETTING_MSG_ID - elif byte == self.START_BYTE1: - self.buffer = [byte] - self.state = FrameFormatConfigParserState.LOOKING_FOR_START2 - else: - self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 - - elif self.state == FrameFormatConfigParserState.GETTING_MSG_ID: - self.buffer.append(byte) - self.msg_id = byte - if self.get_msg_length: - msg_length = self.get_msg_length(byte) - if msg_length is not None: - self.packet_size = self.OVERHEAD + msg_length - self.state = FrameFormatConfigParserState.GETTING_PAYLOAD - else: - self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 - else: - self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 - - elif self.state == FrameFormatConfigParserState.GETTING_PAYLOAD: - self.buffer.append(byte) - - if len(self.buffer) >= self.packet_size: - # Validate checksum - msg_length = self.packet_size - self.OVERHEAD - ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1) - if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: - result.valid = True - result.msg_id = self.msg_id - result.msg_len = msg_length - result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) - self.state = FrameFormatConfigParserState.LOOKING_FOR_START1 - - return result - - def encode(self, msg_id: int, msg: bytes) -> bytes: - """ - Encode a message with FrameFormatConfig format - - Args: - msg_id: Message ID - msg: Message data bytes - - Returns: - Encoded frame as bytes - """ - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - output.extend(msg) - ck = fletcher_checksum(output, 2, 2 + len(msg) + 1) - output.append(ck[0]) - output.append(ck[1]) - return bytes(output) - - def encode_msg(self, msg) -> bytes: - """Encode a message object (must have msg_id and pack() method)""" - return self.encode(msg.msg_id, msg.pack()) - - @staticmethod - def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: - """ - Validate a complete FrameFormatConfig packet in a buffer - - Args: - buffer: Buffer containing the complete packet - - Returns: - FrameMsgInfo with valid=True if packet is valid - """ - result = FrameMsgInfo() - - if len(buffer) < FrameFormatConfig.OVERHEAD: - return result - - if buffer[0] != FrameFormatConfig.START_BYTE1: - return result - if buffer[1] != FrameFormatConfig.START_BYTE2: - return result - - msg_length = len(buffer) - FrameFormatConfig.OVERHEAD - - # Validate checksum - ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1) - if ck[0] == buffer[-2] and ck[1] == buffer[-1]: - result.valid = True - result.msg_id = buffer[2] - result.msg_len = msg_length - result.msg_data = bytes(buffer[FrameFormatConfig.HEADER_SIZE:len(buffer) - FrameFormatConfig.FOOTER_SIZE]) - - return result - - diff --git a/src/struct_frame/boilerplate/py/mavlink_v1_frame.py b/src/struct_frame/boilerplate/py/mavlink_v1_frame.py new file mode 100644 index 00000000..f15713dd --- /dev/null +++ b/src/struct_frame/boilerplate/py/mavlink_v1_frame.py @@ -0,0 +1,146 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MavlinkV1Frame Frame Format +# ============================================================================= + +class MavlinkV1FrameParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_LENGTH = 2 + GETTING_PAYLOAD = 3 + + +class MavlinkV1Frame: + """ + MavlinkV1Frame - Frame format parser and encoder + + Format: [STX=0xFE] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE = 0xFE + HEADER_SIZE = 3 + FOOTER_SIZE = 2 + OVERHEAD = 5 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MavlinkV1Frame parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MavlinkV1FrameParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MavlinkV1FrameParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = MavlinkV1FrameParserState.GETTING_MSG_ID + + elif self.state == MavlinkV1FrameParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = MavlinkV1FrameParserState.GETTING_LENGTH + + elif self.state == MavlinkV1FrameParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = MavlinkV1FrameParserState.GETTING_PAYLOAD + + elif self.state == MavlinkV1FrameParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = MavlinkV1FrameParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MavlinkV1Frame format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MavlinkV1Frame packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MavlinkV1Frame.OVERHEAD: + return result + + if buffer[0] != MavlinkV1Frame.START_BYTE: + return result + + msg_length = len(buffer) - MavlinkV1Frame.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MavlinkV1Frame.HEADER_SIZE:len(buffer) - MavlinkV1Frame.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/mavlink_v2_frame.py b/src/struct_frame/boilerplate/py/mavlink_v2_frame.py new file mode 100644 index 00000000..039323f3 --- /dev/null +++ b/src/struct_frame/boilerplate/py/mavlink_v2_frame.py @@ -0,0 +1,146 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MavlinkV2Frame Frame Format +# ============================================================================= + +class MavlinkV2FrameParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_LENGTH = 2 + GETTING_PAYLOAD = 3 + + +class MavlinkV2Frame: + """ + MavlinkV2Frame - Frame format parser and encoder + + Format: [STX=0xFD] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE = 0xFD + HEADER_SIZE = 5 + FOOTER_SIZE = 2 + OVERHEAD = 7 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MavlinkV2Frame parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MavlinkV2FrameParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MavlinkV2FrameParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = MavlinkV2FrameParserState.GETTING_MSG_ID + + elif self.state == MavlinkV2FrameParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = MavlinkV2FrameParserState.GETTING_LENGTH + + elif self.state == MavlinkV2FrameParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = MavlinkV2FrameParserState.GETTING_PAYLOAD + + elif self.state == MavlinkV2FrameParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = MavlinkV2FrameParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MavlinkV2Frame format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MavlinkV2Frame packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MavlinkV2Frame.OVERHEAD: + return result + + if buffer[0] != MavlinkV2Frame.START_BYTE: + return result + + msg_length = len(buffer) - MavlinkV2Frame.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MavlinkV2Frame.HEADER_SIZE:len(buffer) - MavlinkV2Frame.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/minimal_frame.py b/src/struct_frame/boilerplate/py/minimal_frame.py new file mode 100644 index 00000000..48b39d8e --- /dev/null +++ b/src/struct_frame/boilerplate/py/minimal_frame.py @@ -0,0 +1,134 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MinimalFrame Frame Format +# ============================================================================= + +class MinimalFrameParserState(Enum): + GETTING_MSG_ID = 0 + GETTING_PAYLOAD = 1 + + +class MinimalFrame: + """ + MinimalFrame - Frame format parser and encoder + + Format: [MSG_ID] [MSG...] [CRC1] [CRC2] + """ + + HEADER_SIZE = 1 + FOOTER_SIZE = 2 + OVERHEAD = 3 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MinimalFrame parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MinimalFrameParserState.GETTING_MSG_ID + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MinimalFrameParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = MinimalFrameParserState.GETTING_PAYLOAD + else: + self.state = MinimalFrameParserState.GETTING_MSG_ID + else: + self.state = MinimalFrameParserState.GETTING_MSG_ID + + elif self.state == MinimalFrameParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 0, 0 + msg_length + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = MinimalFrameParserState.GETTING_MSG_ID + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MinimalFrame format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(msg_id) + output.extend(msg) + ck = fletcher_checksum(output, 0, 0 + len(msg) + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MinimalFrame packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MinimalFrame.OVERHEAD: + return result + + + msg_length = len(buffer) - MinimalFrame.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[0] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MinimalFrame.HEADER_SIZE:len(buffer) - MinimalFrame.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/minimal_frame_with_len.py b/src/struct_frame/boilerplate/py/minimal_frame_with_len.py new file mode 100644 index 00000000..e6a8346a --- /dev/null +++ b/src/struct_frame/boilerplate/py/minimal_frame_with_len.py @@ -0,0 +1,136 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MinimalFrameWithLen Frame Format +# ============================================================================= + +class MinimalFrameWithLenParserState(Enum): + GETTING_MSG_ID = 0 + GETTING_LENGTH = 1 + GETTING_PAYLOAD = 2 + + +class MinimalFrameWithLen: + """ + MinimalFrameWithLen - Frame format parser and encoder + + Format: [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + """ + + HEADER_SIZE = 2 + FOOTER_SIZE = 2 + OVERHEAD = 4 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MinimalFrameWithLen parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MinimalFrameWithLenParserState.GETTING_MSG_ID + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MinimalFrameWithLenParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = MinimalFrameWithLenParserState.GETTING_LENGTH + + elif self.state == MinimalFrameWithLenParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = MinimalFrameWithLenParserState.GETTING_PAYLOAD + + elif self.state == MinimalFrameWithLenParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 0, 0 + msg_length + 1 + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = MinimalFrameWithLenParserState.GETTING_MSG_ID + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MinimalFrameWithLen format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 0, 0 + len(msg) + 1 + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MinimalFrameWithLen packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MinimalFrameWithLen.OVERHEAD: + return result + + + msg_length = len(buffer) - MinimalFrameWithLen.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[0] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MinimalFrameWithLen.HEADER_SIZE:len(buffer) - MinimalFrameWithLen.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/minimal_frame_with_len16.py b/src/struct_frame/boilerplate/py/minimal_frame_with_len16.py new file mode 100644 index 00000000..0c620d5e --- /dev/null +++ b/src/struct_frame/boilerplate/py/minimal_frame_with_len16.py @@ -0,0 +1,141 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MinimalFrameWithLen16 Frame Format +# ============================================================================= + +class MinimalFrameWithLen16ParserState(Enum): + GETTING_MSG_ID = 0 + GETTING_LENGTH = 1 + GETTING_PAYLOAD = 2 + + +class MinimalFrameWithLen16: + """ + MinimalFrameWithLen16 - Frame format parser and encoder + + Format: [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] + """ + + HEADER_SIZE = 3 + FOOTER_SIZE = 2 + OVERHEAD = 5 + LENGTH_BYTES = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MinimalFrameWithLen16 parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + self.length_lo = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MinimalFrameWithLen16ParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = MinimalFrameWithLen16ParserState.GETTING_LENGTH + + elif self.state == MinimalFrameWithLen16ParserState.GETTING_LENGTH: + self.buffer.append(byte) + if len(self.buffer) == 2: + self.length_lo = byte + else: + self.msg_length = self.length_lo | (byte << 8) + self.packet_size = self.OVERHEAD + self.msg_length + self.state = MinimalFrameWithLen16ParserState.GETTING_PAYLOAD + + elif self.state == MinimalFrameWithLen16ParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 0, 0 + msg_length + 1 + 2) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MinimalFrameWithLen16 format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.append((len(msg) >> 8) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 0, 0 + len(msg) + 1 + 2) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MinimalFrameWithLen16 packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MinimalFrameWithLen16.OVERHEAD: + return result + + + msg_length = len(buffer) - MinimalFrameWithLen16.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 2) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[0] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MinimalFrameWithLen16.HEADER_SIZE:len(buffer) - MinimalFrameWithLen16.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/minimal_frame_with_len16_no_crc.py b/src/struct_frame/boilerplate/py/minimal_frame_with_len16_no_crc.py new file mode 100644 index 00000000..84067b28 --- /dev/null +++ b/src/struct_frame/boilerplate/py/minimal_frame_with_len16_no_crc.py @@ -0,0 +1,131 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MinimalFrameWithLen16NoCrc Frame Format +# ============================================================================= + +class MinimalFrameWithLen16NoCrcParserState(Enum): + GETTING_MSG_ID = 0 + GETTING_LENGTH = 1 + GETTING_PAYLOAD = 2 + + +class MinimalFrameWithLen16NoCrc: + """ + MinimalFrameWithLen16NoCrc - Frame format parser and encoder + + Format: [MSG_ID] [LEN16] [MSG...] + """ + + HEADER_SIZE = 3 + FOOTER_SIZE = 0 + OVERHEAD = 3 + LENGTH_BYTES = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MinimalFrameWithLen16NoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + self.length_lo = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH + + elif self.state == MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH: + self.buffer.append(byte) + if len(self.buffer) == 2: + self.length_lo = byte + else: + self.msg_length = self.length_lo | (byte << 8) + self.packet_size = self.OVERHEAD + self.msg_length + self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD + + elif self.state == MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MinimalFrameWithLen16NoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.append((len(msg) >> 8) & 0xFF) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MinimalFrameWithLen16NoCrc.OVERHEAD: + return result + + + msg_length = len(buffer) - MinimalFrameWithLen16NoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[0] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MinimalFrameWithLen16NoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/minimal_frame_with_len_no_crc.py b/src/struct_frame/boilerplate/py/minimal_frame_with_len_no_crc.py new file mode 100644 index 00000000..546ede0f --- /dev/null +++ b/src/struct_frame/boilerplate/py/minimal_frame_with_len_no_crc.py @@ -0,0 +1,126 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# MinimalFrameWithLenNoCrc Frame Format +# ============================================================================= + +class MinimalFrameWithLenNoCrcParserState(Enum): + GETTING_MSG_ID = 0 + GETTING_LENGTH = 1 + GETTING_PAYLOAD = 2 + + +class MinimalFrameWithLenNoCrc: + """ + MinimalFrameWithLenNoCrc - Frame format parser and encoder + + Format: [MSG_ID] [LEN] [MSG...] + """ + + HEADER_SIZE = 2 + FOOTER_SIZE = 0 + OVERHEAD = 2 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the MinimalFrameWithLenNoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH + + elif self.state == MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD + + elif self.state == MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with MinimalFrameWithLenNoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete MinimalFrameWithLenNoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < MinimalFrameWithLenNoCrc.OVERHEAD: + return result + + + msg_length = len(buffer) - MinimalFrameWithLenNoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[0] + result.msg_len = msg_length + result.msg_data = bytes(buffer[MinimalFrameWithLenNoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/tiny_frame.py b/src/struct_frame/boilerplate/py/tiny_frame.py new file mode 100644 index 00000000..05284669 --- /dev/null +++ b/src/struct_frame/boilerplate/py/tiny_frame.py @@ -0,0 +1,144 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# TinyFrame Frame Format +# ============================================================================= + +class TinyFrameParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_PAYLOAD = 2 + + +class TinyFrame: + """ + TinyFrame - Frame format parser and encoder + + Format: [START_BYTE=0x70] [MSG_ID] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE = 0x70 + HEADER_SIZE = 2 + FOOTER_SIZE = 2 + OVERHEAD = 4 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the TinyFrame parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = TinyFrameParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == TinyFrameParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = TinyFrameParserState.GETTING_MSG_ID + + elif self.state == TinyFrameParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = TinyFrameParserState.GETTING_PAYLOAD + else: + self.state = TinyFrameParserState.LOOKING_FOR_START + else: + self.state = TinyFrameParserState.LOOKING_FOR_START + + elif self.state == TinyFrameParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = TinyFrameParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with TinyFrame format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.extend(msg) + ck = fletcher_checksum(output, 1, 1 + len(msg) + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete TinyFrame packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < TinyFrame.OVERHEAD: + return result + + if buffer[0] != TinyFrame.START_BYTE: + return result + + msg_length = len(buffer) - TinyFrame.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[TinyFrame.HEADER_SIZE:len(buffer) - TinyFrame.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/tiny_frame_no_crc.py b/src/struct_frame/boilerplate/py/tiny_frame_no_crc.py new file mode 100644 index 00000000..cbf4d0c3 --- /dev/null +++ b/src/struct_frame/boilerplate/py/tiny_frame_no_crc.py @@ -0,0 +1,134 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# TinyFrameNoCrc Frame Format +# ============================================================================= + +class TinyFrameNoCrcParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_PAYLOAD = 2 + + +class TinyFrameNoCrc: + """ + TinyFrameNoCrc - Frame format parser and encoder + + Format: [START_BYTE=0x72] [MSG_ID] [MSG...] + """ + + START_BYTE = 0x72 + HEADER_SIZE = 2 + FOOTER_SIZE = 0 + OVERHEAD = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the TinyFrameNoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == TinyFrameNoCrcParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = TinyFrameNoCrcParserState.GETTING_MSG_ID + + elif self.state == TinyFrameNoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + if self.get_msg_length: + msg_length = self.get_msg_length(byte) + if msg_length is not None: + self.packet_size = self.OVERHEAD + msg_length + self.state = TinyFrameNoCrcParserState.GETTING_PAYLOAD + else: + self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START + else: + self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START + + elif self.state == TinyFrameNoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = TinyFrameNoCrcParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with TinyFrameNoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete TinyFrameNoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < TinyFrameNoCrc.OVERHEAD: + return result + + if buffer[0] != TinyFrameNoCrc.START_BYTE: + return result + + msg_length = len(buffer) - TinyFrameNoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[TinyFrameNoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/tiny_frame_with_len.py b/src/struct_frame/boilerplate/py/tiny_frame_with_len.py new file mode 100644 index 00000000..16ef3eeb --- /dev/null +++ b/src/struct_frame/boilerplate/py/tiny_frame_with_len.py @@ -0,0 +1,146 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# TinyFrameWithLen Frame Format +# ============================================================================= + +class TinyFrameWithLenParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_LENGTH = 2 + GETTING_PAYLOAD = 3 + + +class TinyFrameWithLen: + """ + TinyFrameWithLen - Frame format parser and encoder + + Format: [START_BYTE=0x71] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE = 0x71 + HEADER_SIZE = 3 + FOOTER_SIZE = 2 + OVERHEAD = 5 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the TinyFrameWithLen parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = TinyFrameWithLenParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == TinyFrameWithLenParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = TinyFrameWithLenParserState.GETTING_MSG_ID + + elif self.state == TinyFrameWithLenParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = TinyFrameWithLenParserState.GETTING_LENGTH + + elif self.state == TinyFrameWithLenParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = TinyFrameWithLenParserState.GETTING_PAYLOAD + + elif self.state == TinyFrameWithLenParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = TinyFrameWithLenParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with TinyFrameWithLen format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete TinyFrameWithLen packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < TinyFrameWithLen.OVERHEAD: + return result + + if buffer[0] != TinyFrameWithLen.START_BYTE: + return result + + msg_length = len(buffer) - TinyFrameWithLen.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[TinyFrameWithLen.HEADER_SIZE:len(buffer) - TinyFrameWithLen.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/tiny_frame_with_len16.py b/src/struct_frame/boilerplate/py/tiny_frame_with_len16.py new file mode 100644 index 00000000..86e861f5 --- /dev/null +++ b/src/struct_frame/boilerplate/py/tiny_frame_with_len16.py @@ -0,0 +1,151 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# TinyFrameWithLen16 Frame Format +# ============================================================================= + +class TinyFrameWithLen16ParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_LENGTH = 2 + GETTING_PAYLOAD = 3 + + +class TinyFrameWithLen16: + """ + TinyFrameWithLen16 - Frame format parser and encoder + + Format: [START_BYTE=0x74] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE = 0x74 + HEADER_SIZE = 4 + FOOTER_SIZE = 2 + OVERHEAD = 6 + LENGTH_BYTES = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the TinyFrameWithLen16 parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + self.length_lo = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == TinyFrameWithLen16ParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = TinyFrameWithLen16ParserState.GETTING_MSG_ID + + elif self.state == TinyFrameWithLen16ParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = TinyFrameWithLen16ParserState.GETTING_LENGTH + + elif self.state == TinyFrameWithLen16ParserState.GETTING_LENGTH: + self.buffer.append(byte) + if len(self.buffer) == 3: + self.length_lo = byte + else: + self.msg_length = self.length_lo | (byte << 8) + self.packet_size = self.OVERHEAD + self.msg_length + self.state = TinyFrameWithLen16ParserState.GETTING_PAYLOAD + + elif self.state == TinyFrameWithLen16ParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 1, 1 + msg_length + 1 + 2) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with TinyFrameWithLen16 format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.append((len(msg) >> 8) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 1, 1 + len(msg) + 1 + 2) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete TinyFrameWithLen16 packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < TinyFrameWithLen16.OVERHEAD: + return result + + if buffer[0] != TinyFrameWithLen16.START_BYTE: + return result + + msg_length = len(buffer) - TinyFrameWithLen16.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 2) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[TinyFrameWithLen16.HEADER_SIZE:len(buffer) - TinyFrameWithLen16.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/py/tiny_frame_with_len16_no_crc.py b/src/struct_frame/boilerplate/py/tiny_frame_with_len16_no_crc.py new file mode 100644 index 00000000..b00e879d --- /dev/null +++ b/src/struct_frame/boilerplate/py/tiny_frame_with_len16_no_crc.py @@ -0,0 +1,141 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# TinyFrameWithLen16NoCrc Frame Format +# ============================================================================= + +class TinyFrameWithLen16NoCrcParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_LENGTH = 2 + GETTING_PAYLOAD = 3 + + +class TinyFrameWithLen16NoCrc: + """ + TinyFrameWithLen16NoCrc - Frame format parser and encoder + + Format: [START_BYTE=0x75] [MSG_ID] [LEN16] [MSG...] + """ + + START_BYTE = 0x75 + HEADER_SIZE = 4 + FOOTER_SIZE = 0 + OVERHEAD = 4 + LENGTH_BYTES = 2 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the TinyFrameWithLen16NoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + self.length_lo = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID + + elif self.state == TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH + + elif self.state == TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH: + self.buffer.append(byte) + if len(self.buffer) == 3: + self.length_lo = byte + else: + self.msg_length = self.length_lo | (byte << 8) + self.packet_size = self.OVERHEAD + self.msg_length + self.state = TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD + + elif self.state == TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with TinyFrameWithLen16NoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.append((len(msg) >> 8) & 0xFF) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete TinyFrameWithLen16NoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < TinyFrameWithLen16NoCrc.OVERHEAD: + return result + + if buffer[0] != TinyFrameWithLen16NoCrc.START_BYTE: + return result + + msg_length = len(buffer) - TinyFrameWithLen16NoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[TinyFrameWithLen16NoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/tiny_frame_with_len_no_crc.py b/src/struct_frame/boilerplate/py/tiny_frame_with_len_no_crc.py new file mode 100644 index 00000000..6db4a26b --- /dev/null +++ b/src/struct_frame/boilerplate/py/tiny_frame_with_len_no_crc.py @@ -0,0 +1,136 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# TinyFrameWithLenNoCrc Frame Format +# ============================================================================= + +class TinyFrameWithLenNoCrcParserState(Enum): + LOOKING_FOR_START = 0 + GETTING_MSG_ID = 1 + GETTING_LENGTH = 2 + GETTING_PAYLOAD = 3 + + +class TinyFrameWithLenNoCrc: + """ + TinyFrameWithLenNoCrc - Frame format parser and encoder + + Format: [START_BYTE=0x73] [MSG_ID] [LEN] [MSG...] + """ + + START_BYTE = 0x73 + HEADER_SIZE = 3 + FOOTER_SIZE = 0 + OVERHEAD = 3 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the TinyFrameWithLenNoCrc parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START: + if byte == self.START_BYTE: + self.buffer = [byte] + self.state = TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID + + elif self.state == TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = TinyFrameWithLenNoCrcParserState.GETTING_LENGTH + + elif self.state == TinyFrameWithLenNoCrcParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD + + elif self.state == TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = self.packet_size - self.OVERHEAD + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:]) + self.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with TinyFrameWithLenNoCrc format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete TinyFrameWithLenNoCrc packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < TinyFrameWithLenNoCrc.OVERHEAD: + return result + + if buffer[0] != TinyFrameWithLenNoCrc.START_BYTE: + return result + + msg_length = len(buffer) - TinyFrameWithLenNoCrc.OVERHEAD + + result.valid = True + result.msg_id = buffer[1] + result.msg_len = msg_length + result.msg_data = bytes(buffer[TinyFrameWithLenNoCrc.HEADER_SIZE:]) + + return result diff --git a/src/struct_frame/boilerplate/py/ubx_frame.py b/src/struct_frame/boilerplate/py/ubx_frame.py new file mode 100644 index 00000000..3c09bc7a --- /dev/null +++ b/src/struct_frame/boilerplate/py/ubx_frame.py @@ -0,0 +1,161 @@ +# Automatically generated frame parser +# Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +from enum import Enum +from typing import Callable, List, Union +from .frame_base import FrameMsgInfo, fletcher_checksum + +# ============================================================================= +# UbxFrame Frame Format +# ============================================================================= + +class UbxFrameParserState(Enum): + LOOKING_FOR_START1 = 0 + LOOKING_FOR_START2 = 1 + GETTING_MSG_ID = 2 + GETTING_LENGTH = 3 + GETTING_PAYLOAD = 4 + + +class UbxFrame: + """ + UbxFrame - Frame format parser and encoder + + Format: [SYNC1=0xB5] [SYNC2=0x62] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + """ + + START_BYTE1 = 0xB5 + START_BYTE2 = 0x62 + HEADER_SIZE = 5 + FOOTER_SIZE = 2 + OVERHEAD = 7 + LENGTH_BYTES = 1 + + def __init__(self, get_msg_length: Callable[[int], int] = None): + """ + Initialize the UbxFrame parser + + Args: + get_msg_length: Callback function to get message length from msg_id + Required for formats without a length field + """ + self.get_msg_length = get_msg_length + self.reset() + + def reset(self): + """Reset parser state""" + self.state = UbxFrameParserState.LOOKING_FOR_START1 + self.buffer = [] + self.packet_size = 0 + self.msg_id = 0 + self.msg_length = 0 + + def parse_byte(self, byte: int) -> FrameMsgInfo: + """ + Parse a single byte + + Returns: + FrameMsgInfo with valid=True when a complete valid message is received + """ + result = FrameMsgInfo() + + if self.state == UbxFrameParserState.LOOKING_FOR_START1: + if byte == self.START_BYTE1: + self.buffer = [byte] + self.state = UbxFrameParserState.LOOKING_FOR_START2 + + elif self.state == UbxFrameParserState.LOOKING_FOR_START2: + if byte == self.START_BYTE2: + self.buffer.append(byte) + self.state = UbxFrameParserState.GETTING_MSG_ID + elif byte == self.START_BYTE1: + self.buffer = [byte] + self.state = UbxFrameParserState.LOOKING_FOR_START2 + else: + self.state = UbxFrameParserState.LOOKING_FOR_START1 + + elif self.state == UbxFrameParserState.GETTING_MSG_ID: + self.buffer.append(byte) + self.msg_id = byte + self.state = UbxFrameParserState.GETTING_LENGTH + + elif self.state == UbxFrameParserState.GETTING_LENGTH: + self.buffer.append(byte) + self.msg_length = byte + self.packet_size = self.OVERHEAD + self.msg_length + self.state = UbxFrameParserState.GETTING_PAYLOAD + + elif self.state == UbxFrameParserState.GETTING_PAYLOAD: + self.buffer.append(byte) + + if len(self.buffer) >= self.packet_size: + # Validate checksum + msg_length = self.packet_size - self.OVERHEAD + ck = fletcher_checksum(self.buffer, 2, 2 + msg_length + 1 + 1) + if ck[0] == self.buffer[-2] and ck[1] == self.buffer[-1]: + result.valid = True + result.msg_id = self.msg_id + result.msg_len = msg_length + result.msg_data = bytes(self.buffer[self.HEADER_SIZE:self.packet_size - self.FOOTER_SIZE]) + self.state = UbxFrameParserState.LOOKING_FOR_START1 + + return result + + def encode(self, msg_id: int, msg: bytes) -> bytes: + """ + Encode a message with UbxFrame format + + Args: + msg_id: Message ID + msg: Message data bytes + + Returns: + Encoded frame as bytes + """ + output = [] + output.append(self.START_BYTE1) + output.append(self.START_BYTE2) + output.append(msg_id) + output.append(len(msg) & 0xFF) + output.extend(msg) + ck = fletcher_checksum(output, 2, 2 + len(msg) + 1 + 1) + output.append(ck[0]) + output.append(ck[1]) + return bytes(output) + + def encode_msg(self, msg) -> bytes: + """Encode a message object (must have msg_id and pack() method)""" + return self.encode(msg.msg_id, msg.pack()) + + @staticmethod + def validate_packet(buffer: Union[bytes, List[int]]) -> FrameMsgInfo: + """ + Validate a complete UbxFrame packet in a buffer + + Args: + buffer: Buffer containing the complete packet + + Returns: + FrameMsgInfo with valid=True if packet is valid + """ + result = FrameMsgInfo() + + if len(buffer) < UbxFrame.OVERHEAD: + return result + + if buffer[0] != UbxFrame.START_BYTE1: + return result + if buffer[1] != UbxFrame.START_BYTE2: + return result + + msg_length = len(buffer) - UbxFrame.OVERHEAD + + # Validate checksum + ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1) + if ck[0] == buffer[-2] and ck[1] == buffer[-1]: + result.valid = True + result.msg_id = buffer[2] + result.msg_len = msg_length + result.msg_data = bytes(buffer[UbxFrame.HEADER_SIZE:len(buffer) - UbxFrame.FOOTER_SIZE]) + + return result diff --git a/src/struct_frame/boilerplate/ts/BasicFrame.ts b/src/struct_frame/boilerplate/ts/BasicFrame.ts new file mode 100644 index 00000000..ac657245 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrame.ts @@ -0,0 +1,172 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrame Frame Format +// ============================================================================= + +export enum BasicFrameParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_PAYLOAD = 3 +} + +/** + * BasicFrame - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] + */ +export class BasicFrame { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x91; + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 5; + + private state: BasicFrameParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrame parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameParserState.LOOKING_FOR_START1: + if (byte === BasicFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameParserState.LOOKING_FOR_START2: + if (byte === BasicFrame.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameParserState.GETTING_MSG_ID; + } else if (byte === BasicFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = BasicFrame.OVERHEAD + msg_length; + this.state = BasicFrameParserState.GETTING_PAYLOAD; + } else { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + } else { + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - BasicFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrame.HEADER_SIZE, this.packet_size - BasicFrame.FOOTER_SIZE)); + } + this.state = BasicFrameParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrame format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrame.START_BYTE1); + output.push(BasicFrame.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrame packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrame.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrame.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrame.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrame.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrame.HEADER_SIZE, buffer.length - BasicFrame.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/BasicFrameNoCrc.ts b/src/struct_frame/boilerplate/ts/BasicFrameNoCrc.ts new file mode 100644 index 00000000..fe101793 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrameNoCrc.ts @@ -0,0 +1,160 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrameNoCrc Frame Format +// ============================================================================= + +export enum BasicFrameNoCrcParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_PAYLOAD = 3 +} + +/** + * BasicFrameNoCrc - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x95] [MSG_ID] [MSG...] + */ +export class BasicFrameNoCrc { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x95; + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 3; + + private state: BasicFrameNoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrameNoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameNoCrcParserState.LOOKING_FOR_START1: + if (byte === BasicFrameNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameNoCrcParserState.LOOKING_FOR_START2: + if (byte === BasicFrameNoCrc.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameNoCrcParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = BasicFrameNoCrc.OVERHEAD + msg_length; + this.state = BasicFrameNoCrcParserState.GETTING_PAYLOAD; + } else { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + } else { + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - BasicFrameNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameNoCrc.HEADER_SIZE)); + this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrameNoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrameNoCrc.START_BYTE1); + output.push(BasicFrameNoCrc.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrameNoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameNoCrc.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameNoCrc.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameNoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/BasicFrameWithLen.ts b/src/struct_frame/boilerplate/ts/BasicFrameWithLen.ts new file mode 100644 index 00000000..6b26096f --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrameWithLen.ts @@ -0,0 +1,175 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrameWithLen Frame Format +// ============================================================================= + +export enum BasicFrameWithLenParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_LENGTH = 3, + GETTING_PAYLOAD = 4 +} + +/** + * BasicFrameWithLen - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x92] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + */ +export class BasicFrameWithLen { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x92; + static readonly HEADER_SIZE = 4; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 6; + static readonly LENGTH_BYTES = 1; + + private state: BasicFrameWithLenParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrameWithLen parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLenParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLen.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLenParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLen.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLenParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLen.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLenParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLenParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLenParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = BasicFrameWithLen.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLenParserState.GETTING_PAYLOAD; + break; + + case BasicFrameWithLenParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - BasicFrameWithLen.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen.HEADER_SIZE, this.packet_size - BasicFrameWithLen.FOOTER_SIZE)); + } + this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrameWithLen format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrameWithLen.START_BYTE1); + output.push(BasicFrameWithLen.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrameWithLen packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLen.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLen.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLen.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLen.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen.HEADER_SIZE, buffer.length - BasicFrameWithLen.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/BasicFrameWithLen16.ts b/src/struct_frame/boilerplate/ts/BasicFrameWithLen16.ts new file mode 100644 index 00000000..152d3e93 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrameWithLen16.ts @@ -0,0 +1,182 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrameWithLen16 Frame Format +// ============================================================================= + +export enum BasicFrameWithLen16ParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_LENGTH = 3, + GETTING_PAYLOAD = 4 +} + +/** + * BasicFrameWithLen16 - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x93] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] + */ +export class BasicFrameWithLen16 { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x93; + static readonly HEADER_SIZE = 5; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 7; + static readonly LENGTH_BYTES = 2; + + private state: BasicFrameWithLen16ParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private length_lo: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrameWithLen16 parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLen16ParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLen16.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLen16ParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLen16.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLen16ParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLen16.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLen16ParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLen16ParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLen16ParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 4) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = BasicFrameWithLen16.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLen16ParserState.GETTING_PAYLOAD; + } + break; + + case BasicFrameWithLen16ParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - BasicFrameWithLen16.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 2); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16.HEADER_SIZE, this.packet_size - BasicFrameWithLen16.FOOTER_SIZE)); + } + this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrameWithLen16 format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrameWithLen16.START_BYTE1); + output.push(BasicFrameWithLen16.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 2); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrameWithLen16 packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLen16.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLen16.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLen16.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLen16.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 2); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16.HEADER_SIZE, buffer.length - BasicFrameWithLen16.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/BasicFrameWithLen16NoCrc.ts b/src/struct_frame/boilerplate/ts/BasicFrameWithLen16NoCrc.ts new file mode 100644 index 00000000..077b29e0 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrameWithLen16NoCrc.ts @@ -0,0 +1,170 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrameWithLen16NoCrc Frame Format +// ============================================================================= + +export enum BasicFrameWithLen16NoCrcParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_LENGTH = 3, + GETTING_PAYLOAD = 4 +} + +/** + * BasicFrameWithLen16NoCrc - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x97] [MSG_ID] [LEN16] [MSG...] + */ +export class BasicFrameWithLen16NoCrc { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x97; + static readonly HEADER_SIZE = 5; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 5; + static readonly LENGTH_BYTES = 2; + + private state: BasicFrameWithLen16NoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private length_lo: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrameWithLen16NoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLen16NoCrc.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 4) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = BasicFrameWithLen16NoCrc.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; + } + break; + + case BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - BasicFrameWithLen16NoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16NoCrc.HEADER_SIZE)); + this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrameWithLen16NoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrameWithLen16NoCrc.START_BYTE1); + output.push(BasicFrameWithLen16NoCrc.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrameWithLen16NoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLen16NoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLen16NoCrc.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLen16NoCrc.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLen16NoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16NoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/BasicFrameWithLenNoCrc.ts b/src/struct_frame/boilerplate/ts/BasicFrameWithLenNoCrc.ts new file mode 100644 index 00000000..97c6ff3c --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrameWithLenNoCrc.ts @@ -0,0 +1,163 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrameWithLenNoCrc Frame Format +// ============================================================================= + +export enum BasicFrameWithLenNoCrcParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_LENGTH = 3, + GETTING_PAYLOAD = 4 +} + +/** + * BasicFrameWithLenNoCrc - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x96] [MSG_ID] [LEN] [MSG...] + */ +export class BasicFrameWithLenNoCrc { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x96; + static readonly HEADER_SIZE = 4; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 4; + static readonly LENGTH_BYTES = 1; + + private state: BasicFrameWithLenNoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrameWithLenNoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithLenNoCrc.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = BasicFrameWithLenNoCrcParserState.GETTING_LENGTH; + break; + + case BasicFrameWithLenNoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = BasicFrameWithLenNoCrc.OVERHEAD + this.msg_length; + this.state = BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD; + break; + + case BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - BasicFrameWithLenNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLenNoCrc.HEADER_SIZE)); + this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrameWithLenNoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrameWithLenNoCrc.START_BYTE1); + output.push(BasicFrameWithLenNoCrc.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrameWithLenNoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithLenNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithLenNoCrc.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithLenNoCrc.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithLenNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLenNoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/BasicFrameWithSysComp.ts b/src/struct_frame/boilerplate/ts/BasicFrameWithSysComp.ts new file mode 100644 index 00000000..57dd7a3b --- /dev/null +++ b/src/struct_frame/boilerplate/ts/BasicFrameWithSysComp.ts @@ -0,0 +1,172 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// BasicFrameWithSysComp Frame Format +// ============================================================================= + +export enum BasicFrameWithSysCompParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_PAYLOAD = 3 +} + +/** + * BasicFrameWithSysComp - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x94] [MSG_ID] [MSG...] [CRC1] [CRC2] + */ +export class BasicFrameWithSysComp { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x94; + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 5; + + private state: BasicFrameWithSysCompParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new BasicFrameWithSysComp parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case BasicFrameWithSysCompParserState.LOOKING_FOR_START1: + if (byte === BasicFrameWithSysComp.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; + } + break; + + case BasicFrameWithSysCompParserState.LOOKING_FOR_START2: + if (byte === BasicFrameWithSysComp.START_BYTE2) { + this.buffer.push(byte); + this.state = BasicFrameWithSysCompParserState.GETTING_MSG_ID; + } else if (byte === BasicFrameWithSysComp.START_BYTE1) { + this.buffer = [byte]; + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; + } else { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithSysCompParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = BasicFrameWithSysComp.OVERHEAD + msg_length; + this.state = BasicFrameWithSysCompParserState.GETTING_PAYLOAD; + } else { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + } else { + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + break; + + case BasicFrameWithSysCompParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - BasicFrameWithSysComp.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithSysComp.HEADER_SIZE, this.packet_size - BasicFrameWithSysComp.FOOTER_SIZE)); + } + this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with BasicFrameWithSysComp format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(BasicFrameWithSysComp.START_BYTE1); + output.push(BasicFrameWithSysComp.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete BasicFrameWithSysComp packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < BasicFrameWithSysComp.OVERHEAD) { + return result; + } + + if (buffer[0] !== BasicFrameWithSysComp.START_BYTE1) { + return result; + } + if (buffer[1] !== BasicFrameWithSysComp.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - BasicFrameWithSysComp.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithSysComp.HEADER_SIZE, buffer.length - BasicFrameWithSysComp.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/FrameFormatConfig.ts b/src/struct_frame/boilerplate/ts/FrameFormatConfig.ts new file mode 100644 index 00000000..76e80b2d --- /dev/null +++ b/src/struct_frame/boilerplate/ts/FrameFormatConfig.ts @@ -0,0 +1,172 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// FrameFormatConfig Frame Format +// ============================================================================= + +export enum FrameFormatConfigParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_PAYLOAD = 3 +} + +/** + * FrameFormatConfig - Frame format parser and encoder + * + * Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] + */ +export class FrameFormatConfig { + static readonly START_BYTE1 = 0x90; + static readonly START_BYTE2 = 0x91; + static readonly HEADER_SIZE = 2; + static readonly FOOTER_SIZE = 1; + static readonly OVERHEAD = 3; + + private state: FrameFormatConfigParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new FrameFormatConfig parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case FrameFormatConfigParserState.LOOKING_FOR_START1: + if (byte === FrameFormatConfig.START_BYTE1) { + this.buffer = [byte]; + this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; + } + break; + + case FrameFormatConfigParserState.LOOKING_FOR_START2: + if (byte === FrameFormatConfig.START_BYTE2) { + this.buffer.push(byte); + this.state = FrameFormatConfigParserState.GETTING_MSG_ID; + } else if (byte === FrameFormatConfig.START_BYTE1) { + this.buffer = [byte]; + this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; + } else { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + break; + + case FrameFormatConfigParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = FrameFormatConfig.OVERHEAD + msg_length; + this.state = FrameFormatConfigParserState.GETTING_PAYLOAD; + } else { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + } else { + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + break; + + case FrameFormatConfigParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - FrameFormatConfig.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(FrameFormatConfig.HEADER_SIZE, this.packet_size - FrameFormatConfig.FOOTER_SIZE)); + } + this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with FrameFormatConfig format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(FrameFormatConfig.START_BYTE1); + output.push(FrameFormatConfig.START_BYTE2); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete FrameFormatConfig packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < FrameFormatConfig.OVERHEAD) { + return result; + } + + if (buffer[0] !== FrameFormatConfig.START_BYTE1) { + return result; + } + if (buffer[1] !== FrameFormatConfig.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - FrameFormatConfig.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, FrameFormatConfig.HEADER_SIZE, buffer.length - FrameFormatConfig.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MavlinkV1Frame.ts b/src/struct_frame/boilerplate/ts/MavlinkV1Frame.ts new file mode 100644 index 00000000..e143ce51 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MavlinkV1Frame.ts @@ -0,0 +1,157 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MavlinkV1Frame Frame Format +// ============================================================================= + +export enum MavlinkV1FrameParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_LENGTH = 2, + GETTING_PAYLOAD = 3 +} + +/** + * MavlinkV1Frame - Frame format parser and encoder + * + * Format: [STX=0xFE] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + */ +export class MavlinkV1Frame { + static readonly START_BYTE = 0xFE; + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 5; + static readonly LENGTH_BYTES = 1; + + private state: MavlinkV1FrameParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MavlinkV1Frame parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MavlinkV1FrameParserState.LOOKING_FOR_START: + if (byte === MavlinkV1Frame.START_BYTE) { + this.buffer = [byte]; + this.state = MavlinkV1FrameParserState.GETTING_MSG_ID; + } + break; + + case MavlinkV1FrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MavlinkV1FrameParserState.GETTING_LENGTH; + break; + + case MavlinkV1FrameParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MavlinkV1Frame.OVERHEAD + this.msg_length; + this.state = MavlinkV1FrameParserState.GETTING_PAYLOAD; + break; + + case MavlinkV1FrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - MavlinkV1Frame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV1Frame.HEADER_SIZE, this.packet_size - MavlinkV1Frame.FOOTER_SIZE)); + } + this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with MavlinkV1Frame format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(MavlinkV1Frame.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete MavlinkV1Frame packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MavlinkV1Frame.OVERHEAD) { + return result; + } + + if (buffer[0] !== MavlinkV1Frame.START_BYTE) { + return result; + } + + const msg_length = buffer.length - MavlinkV1Frame.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV1Frame.HEADER_SIZE, buffer.length - MavlinkV1Frame.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MavlinkV2Frame.ts b/src/struct_frame/boilerplate/ts/MavlinkV2Frame.ts new file mode 100644 index 00000000..f80bb848 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MavlinkV2Frame.ts @@ -0,0 +1,157 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MavlinkV2Frame Frame Format +// ============================================================================= + +export enum MavlinkV2FrameParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_LENGTH = 2, + GETTING_PAYLOAD = 3 +} + +/** + * MavlinkV2Frame - Frame format parser and encoder + * + * Format: [STX=0xFD] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + */ +export class MavlinkV2Frame { + static readonly START_BYTE = 0xFD; + static readonly HEADER_SIZE = 5; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 7; + static readonly LENGTH_BYTES = 1; + + private state: MavlinkV2FrameParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MavlinkV2Frame parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MavlinkV2FrameParserState.LOOKING_FOR_START: + if (byte === MavlinkV2Frame.START_BYTE) { + this.buffer = [byte]; + this.state = MavlinkV2FrameParserState.GETTING_MSG_ID; + } + break; + + case MavlinkV2FrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MavlinkV2FrameParserState.GETTING_LENGTH; + break; + + case MavlinkV2FrameParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MavlinkV2Frame.OVERHEAD + this.msg_length; + this.state = MavlinkV2FrameParserState.GETTING_PAYLOAD; + break; + + case MavlinkV2FrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - MavlinkV2Frame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV2Frame.HEADER_SIZE, this.packet_size - MavlinkV2Frame.FOOTER_SIZE)); + } + this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with MavlinkV2Frame format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(MavlinkV2Frame.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete MavlinkV2Frame packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MavlinkV2Frame.OVERHEAD) { + return result; + } + + if (buffer[0] !== MavlinkV2Frame.START_BYTE) { + return result; + } + + const msg_length = buffer.length - MavlinkV2Frame.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV2Frame.HEADER_SIZE, buffer.length - MavlinkV2Frame.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MinimalFrame.ts b/src/struct_frame/boilerplate/ts/MinimalFrame.ts new file mode 100644 index 00000000..80168a91 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MinimalFrame.ts @@ -0,0 +1,141 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MinimalFrame Frame Format +// ============================================================================= + +export enum MinimalFrameParserState { + GETTING_MSG_ID = 0, + GETTING_PAYLOAD = 1 +} + +/** + * MinimalFrame - Frame format parser and encoder + * + * Format: [MSG_ID] [MSG...] [CRC1] [CRC2] + */ +export class MinimalFrame { + static readonly HEADER_SIZE = 1; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 3; + + private state: MinimalFrameParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MinimalFrame parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MinimalFrameParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = MinimalFrame.OVERHEAD + msg_length; + this.state = MinimalFrameParserState.GETTING_PAYLOAD; + } else { + this.state = MinimalFrameParserState.GETTING_MSG_ID; + } + } else { + this.state = MinimalFrameParserState.GETTING_MSG_ID; + } + break; + + case MinimalFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - MinimalFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrame.HEADER_SIZE, this.packet_size - MinimalFrame.FOOTER_SIZE)); + } + this.state = MinimalFrameParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + /** + * Encode a message with MinimalFrame format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 0, 0 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete MinimalFrame packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrame.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrame.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrame.HEADER_SIZE, buffer.length - MinimalFrame.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MinimalFrameWithLen.ts b/src/struct_frame/boilerplate/ts/MinimalFrameWithLen.ts new file mode 100644 index 00000000..63afedd5 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MinimalFrameWithLen.ts @@ -0,0 +1,144 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MinimalFrameWithLen Frame Format +// ============================================================================= + +export enum MinimalFrameWithLenParserState { + GETTING_MSG_ID = 0, + GETTING_LENGTH = 1, + GETTING_PAYLOAD = 2 +} + +/** + * MinimalFrameWithLen - Frame format parser and encoder + * + * Format: [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + */ +export class MinimalFrameWithLen { + static readonly HEADER_SIZE = 2; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 4; + static readonly LENGTH_BYTES = 1; + + private state: MinimalFrameWithLenParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MinimalFrameWithLen parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLenParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLenParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLenParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MinimalFrameWithLen.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLenParserState.GETTING_PAYLOAD; + break; + + case MinimalFrameWithLenParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - MinimalFrameWithLen.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen.HEADER_SIZE, this.packet_size - MinimalFrameWithLen.FOOTER_SIZE)); + } + this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + /** + * Encode a message with MinimalFrameWithLen format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete MinimalFrameWithLen packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLen.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLen.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen.HEADER_SIZE, buffer.length - MinimalFrameWithLen.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MinimalFrameWithLen16.ts b/src/struct_frame/boilerplate/ts/MinimalFrameWithLen16.ts new file mode 100644 index 00000000..bd8b3367 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MinimalFrameWithLen16.ts @@ -0,0 +1,151 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MinimalFrameWithLen16 Frame Format +// ============================================================================= + +export enum MinimalFrameWithLen16ParserState { + GETTING_MSG_ID = 0, + GETTING_LENGTH = 1, + GETTING_PAYLOAD = 2 +} + +/** + * MinimalFrameWithLen16 - Frame format parser and encoder + * + * Format: [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] + */ +export class MinimalFrameWithLen16 { + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 5; + static readonly LENGTH_BYTES = 2; + + private state: MinimalFrameWithLen16ParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private length_lo: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MinimalFrameWithLen16 parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLen16ParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLen16ParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLen16ParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 2) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = MinimalFrameWithLen16.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLen16ParserState.GETTING_PAYLOAD; + } + break; + + case MinimalFrameWithLen16ParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - MinimalFrameWithLen16.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 2); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16.HEADER_SIZE, this.packet_size - MinimalFrameWithLen16.FOOTER_SIZE)); + } + this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + /** + * Encode a message with MinimalFrameWithLen16 format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 2); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete MinimalFrameWithLen16 packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLen16.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLen16.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 2); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16.HEADER_SIZE, buffer.length - MinimalFrameWithLen16.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MinimalFrameWithLen16NoCrc.ts b/src/struct_frame/boilerplate/ts/MinimalFrameWithLen16NoCrc.ts new file mode 100644 index 00000000..466690f7 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MinimalFrameWithLen16NoCrc.ts @@ -0,0 +1,139 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MinimalFrameWithLen16NoCrc Frame Format +// ============================================================================= + +export enum MinimalFrameWithLen16NoCrcParserState { + GETTING_MSG_ID = 0, + GETTING_LENGTH = 1, + GETTING_PAYLOAD = 2 +} + +/** + * MinimalFrameWithLen16NoCrc - Frame format parser and encoder + * + * Format: [MSG_ID] [LEN16] [MSG...] + */ +export class MinimalFrameWithLen16NoCrc { + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 3; + static readonly LENGTH_BYTES = 2; + + private state: MinimalFrameWithLen16NoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private length_lo: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MinimalFrameWithLen16NoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 2) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = MinimalFrameWithLen16NoCrc.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; + } + break; + + case MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - MinimalFrameWithLen16NoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16NoCrc.HEADER_SIZE)); + this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + /** + * Encode a message with MinimalFrameWithLen16NoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLen16NoCrc.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLen16NoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16NoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/MinimalFrameWithLenNoCrc.ts b/src/struct_frame/boilerplate/ts/MinimalFrameWithLenNoCrc.ts new file mode 100644 index 00000000..b702f977 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/MinimalFrameWithLenNoCrc.ts @@ -0,0 +1,132 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// MinimalFrameWithLenNoCrc Frame Format +// ============================================================================= + +export enum MinimalFrameWithLenNoCrcParserState { + GETTING_MSG_ID = 0, + GETTING_LENGTH = 1, + GETTING_PAYLOAD = 2 +} + +/** + * MinimalFrameWithLenNoCrc - Frame format parser and encoder + * + * Format: [MSG_ID] [LEN] [MSG...] + */ +export class MinimalFrameWithLenNoCrc { + static readonly HEADER_SIZE = 2; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 2; + static readonly LENGTH_BYTES = 1; + + private state: MinimalFrameWithLenNoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new MinimalFrameWithLenNoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH; + break; + + case MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = MinimalFrameWithLenNoCrc.OVERHEAD + this.msg_length; + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD; + break; + + case MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - MinimalFrameWithLenNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLenNoCrc.HEADER_SIZE)); + this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; + } + break; + } + + return result; + } + + /** + * Encode a message with MinimalFrameWithLenNoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete MinimalFrameWithLenNoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < MinimalFrameWithLenNoCrc.OVERHEAD) { + return result; + } + + + const msg_length = buffer.length - MinimalFrameWithLenNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[0]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLenNoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/TinyFrame.ts b/src/struct_frame/boilerplate/ts/TinyFrame.ts new file mode 100644 index 00000000..385f5acb --- /dev/null +++ b/src/struct_frame/boilerplate/ts/TinyFrame.ts @@ -0,0 +1,154 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// TinyFrame Frame Format +// ============================================================================= + +export enum TinyFrameParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_PAYLOAD = 2 +} + +/** + * TinyFrame - Frame format parser and encoder + * + * Format: [START_BYTE=0x70] [MSG_ID] [MSG...] [CRC1] [CRC2] + */ +export class TinyFrame { + static readonly START_BYTE = 0x70; + static readonly HEADER_SIZE = 2; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 4; + + private state: TinyFrameParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new TinyFrame parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = TinyFrameParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameParserState.LOOKING_FOR_START: + if (byte === TinyFrame.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = TinyFrame.OVERHEAD + msg_length; + this.state = TinyFrameParserState.GETTING_PAYLOAD; + } else { + this.state = TinyFrameParserState.LOOKING_FOR_START; + } + } else { + this.state = TinyFrameParserState.LOOKING_FOR_START; + } + break; + + case TinyFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - TinyFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrame.HEADER_SIZE, this.packet_size - TinyFrame.FOOTER_SIZE)); + } + this.state = TinyFrameParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with TinyFrame format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(TinyFrame.START_BYTE); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete TinyFrame packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrame.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrame.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrame.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrame.HEADER_SIZE, buffer.length - TinyFrame.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/TinyFrameNoCrc.ts b/src/struct_frame/boilerplate/ts/TinyFrameNoCrc.ts new file mode 100644 index 00000000..23d04a7e --- /dev/null +++ b/src/struct_frame/boilerplate/ts/TinyFrameNoCrc.ts @@ -0,0 +1,142 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// TinyFrameNoCrc Frame Format +// ============================================================================= + +export enum TinyFrameNoCrcParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_PAYLOAD = 2 +} + +/** + * TinyFrameNoCrc - Frame format parser and encoder + * + * Format: [START_BYTE=0x72] [MSG_ID] [MSG...] + */ +export class TinyFrameNoCrc { + static readonly START_BYTE = 0x72; + static readonly HEADER_SIZE = 2; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 2; + + private state: TinyFrameNoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new TinyFrameNoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameNoCrcParserState.LOOKING_FOR_START: + if (byte === TinyFrameNoCrc.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameNoCrcParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + if (this.get_msg_length) { + const msg_length = this.get_msg_length(byte); + if (msg_length !== undefined) { + this.packet_size = TinyFrameNoCrc.OVERHEAD + msg_length; + this.state = TinyFrameNoCrcParserState.GETTING_PAYLOAD; + } else { + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + } + } else { + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + } + break; + + case TinyFrameNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - TinyFrameNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameNoCrc.HEADER_SIZE)); + this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with TinyFrameNoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(TinyFrameNoCrc.START_BYTE); + output.push(msg_id); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete TinyFrameNoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameNoCrc.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameNoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/TinyFrameWithLen.ts b/src/struct_frame/boilerplate/ts/TinyFrameWithLen.ts new file mode 100644 index 00000000..91550dad --- /dev/null +++ b/src/struct_frame/boilerplate/ts/TinyFrameWithLen.ts @@ -0,0 +1,157 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// TinyFrameWithLen Frame Format +// ============================================================================= + +export enum TinyFrameWithLenParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_LENGTH = 2, + GETTING_PAYLOAD = 3 +} + +/** + * TinyFrameWithLen - Frame format parser and encoder + * + * Format: [START_BYTE=0x71] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + */ +export class TinyFrameWithLen { + static readonly START_BYTE = 0x71; + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 5; + static readonly LENGTH_BYTES = 1; + + private state: TinyFrameWithLenParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new TinyFrameWithLen parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLenParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLen.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLenParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLenParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLenParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLenParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = TinyFrameWithLen.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLenParserState.GETTING_PAYLOAD; + break; + + case TinyFrameWithLenParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - TinyFrameWithLen.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen.HEADER_SIZE, this.packet_size - TinyFrameWithLen.FOOTER_SIZE)); + } + this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with TinyFrameWithLen format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(TinyFrameWithLen.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete TinyFrameWithLen packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLen.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLen.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLen.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen.HEADER_SIZE, buffer.length - TinyFrameWithLen.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/TinyFrameWithLen16.ts b/src/struct_frame/boilerplate/ts/TinyFrameWithLen16.ts new file mode 100644 index 00000000..91b9401c --- /dev/null +++ b/src/struct_frame/boilerplate/ts/TinyFrameWithLen16.ts @@ -0,0 +1,164 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// TinyFrameWithLen16 Frame Format +// ============================================================================= + +export enum TinyFrameWithLen16ParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_LENGTH = 2, + GETTING_PAYLOAD = 3 +} + +/** + * TinyFrameWithLen16 - Frame format parser and encoder + * + * Format: [START_BYTE=0x74] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] + */ +export class TinyFrameWithLen16 { + static readonly START_BYTE = 0x74; + static readonly HEADER_SIZE = 4; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 6; + static readonly LENGTH_BYTES = 2; + + private state: TinyFrameWithLen16ParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private length_lo: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new TinyFrameWithLen16 parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLen16ParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLen16.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLen16ParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLen16ParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLen16ParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLen16ParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 3) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = TinyFrameWithLen16.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLen16ParserState.GETTING_PAYLOAD; + } + break; + + case TinyFrameWithLen16ParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - TinyFrameWithLen16.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 2); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16.HEADER_SIZE, this.packet_size - TinyFrameWithLen16.FOOTER_SIZE)); + } + this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with TinyFrameWithLen16 format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(TinyFrameWithLen16.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 2); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete TinyFrameWithLen16 packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLen16.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLen16.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLen16.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 2); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16.HEADER_SIZE, buffer.length - TinyFrameWithLen16.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/TinyFrameWithLen16NoCrc.ts b/src/struct_frame/boilerplate/ts/TinyFrameWithLen16NoCrc.ts new file mode 100644 index 00000000..b2da0f82 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/TinyFrameWithLen16NoCrc.ts @@ -0,0 +1,152 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// TinyFrameWithLen16NoCrc Frame Format +// ============================================================================= + +export enum TinyFrameWithLen16NoCrcParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_LENGTH = 2, + GETTING_PAYLOAD = 3 +} + +/** + * TinyFrameWithLen16NoCrc - Frame format parser and encoder + * + * Format: [START_BYTE=0x75] [MSG_ID] [LEN16] [MSG...] + */ +export class TinyFrameWithLen16NoCrc { + static readonly START_BYTE = 0x75; + static readonly HEADER_SIZE = 4; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 4; + static readonly LENGTH_BYTES = 2; + + private state: TinyFrameWithLen16NoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private length_lo: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new TinyFrameWithLen16NoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + this.length_lo = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLen16NoCrc.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + if (this.buffer.length === 3) { + this.length_lo = byte; + } else { + this.msg_length = this.length_lo | (byte << 8); + this.packet_size = TinyFrameWithLen16NoCrc.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; + } + break; + + case TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - TinyFrameWithLen16NoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16NoCrc.HEADER_SIZE)); + this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with TinyFrameWithLen16NoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(TinyFrameWithLen16NoCrc.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + output.push((msg.length >> 8) & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete TinyFrameWithLen16NoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLen16NoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLen16NoCrc.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLen16NoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16NoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/TinyFrameWithLenNoCrc.ts b/src/struct_frame/boilerplate/ts/TinyFrameWithLenNoCrc.ts new file mode 100644 index 00000000..bf3727b6 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/TinyFrameWithLenNoCrc.ts @@ -0,0 +1,145 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// TinyFrameWithLenNoCrc Frame Format +// ============================================================================= + +export enum TinyFrameWithLenNoCrcParserState { + LOOKING_FOR_START = 0, + GETTING_MSG_ID = 1, + GETTING_LENGTH = 2, + GETTING_PAYLOAD = 3 +} + +/** + * TinyFrameWithLenNoCrc - Frame format parser and encoder + * + * Format: [START_BYTE=0x73] [MSG_ID] [LEN] [MSG...] + */ +export class TinyFrameWithLenNoCrc { + static readonly START_BYTE = 0x73; + static readonly HEADER_SIZE = 3; + static readonly FOOTER_SIZE = 0; + static readonly OVERHEAD = 3; + static readonly LENGTH_BYTES = 1; + + private state: TinyFrameWithLenNoCrcParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new TinyFrameWithLenNoCrc parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START: + if (byte === TinyFrameWithLenNoCrc.START_BYTE) { + this.buffer = [byte]; + this.state = TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID; + } + break; + + case TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = TinyFrameWithLenNoCrcParserState.GETTING_LENGTH; + break; + + case TinyFrameWithLenNoCrcParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = TinyFrameWithLenNoCrc.OVERHEAD + this.msg_length; + this.state = TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD; + break; + + case TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = this.packet_size - TinyFrameWithLenNoCrc.OVERHEAD; + result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLenNoCrc.HEADER_SIZE)); + this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; + } + break; + } + + return result; + } + + /** + * Encode a message with TinyFrameWithLenNoCrc format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(TinyFrameWithLenNoCrc.START_BYTE); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + return new Uint8Array(output); + } + + /** + * Validate a complete TinyFrameWithLenNoCrc packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < TinyFrameWithLenNoCrc.OVERHEAD) { + return result; + } + + if (buffer[0] !== TinyFrameWithLenNoCrc.START_BYTE) { + return result; + } + + const msg_length = buffer.length - TinyFrameWithLenNoCrc.OVERHEAD; + + result.valid = true; + result.msg_id = buffer[1]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLenNoCrc.HEADER_SIZE)); + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/UbxFrame.ts b/src/struct_frame/boilerplate/ts/UbxFrame.ts new file mode 100644 index 00000000..684d0fd7 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/UbxFrame.ts @@ -0,0 +1,175 @@ +// Automatically generated frame parser +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from './frame_base'; + +// ============================================================================= +// UbxFrame Frame Format +// ============================================================================= + +export enum UbxFrameParserState { + LOOKING_FOR_START1 = 0, + LOOKING_FOR_START2 = 1, + GETTING_MSG_ID = 2, + GETTING_LENGTH = 3, + GETTING_PAYLOAD = 4 +} + +/** + * UbxFrame - Frame format parser and encoder + * + * Format: [SYNC1=0xB5] [SYNC2=0x62] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] + */ +export class UbxFrame { + static readonly START_BYTE1 = 0xB5; + static readonly START_BYTE2 = 0x62; + static readonly HEADER_SIZE = 5; + static readonly FOOTER_SIZE = 2; + static readonly OVERHEAD = 7; + static readonly LENGTH_BYTES = 1; + + private state: UbxFrameParserState; + private buffer: number[]; + private packet_size: number; + private msg_id: number; + private msg_length: number; + private get_msg_length?: (msg_id: number) => number | undefined; + + /** + * Create a new UbxFrame parser + * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) + */ + constructor(get_msg_length?: (msg_id: number) => number | undefined) { + this.get_msg_length = get_msg_length; + this.state = UbxFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** Reset parser state */ + reset(): void { + this.state = UbxFrameParserState.LOOKING_FOR_START1; + this.buffer = []; + this.packet_size = 0; + this.msg_id = 0; + this.msg_length = 0; + } + + /** + * Parse a single byte + * @param byte The byte to parse + * @returns FrameMsgInfo with valid=true when a complete valid message is received + */ + parse_byte(byte: number): FrameMsgInfo { + const result = createFrameMsgInfo(); + + switch (this.state) { + case UbxFrameParserState.LOOKING_FOR_START1: + if (byte === UbxFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = UbxFrameParserState.LOOKING_FOR_START2; + } + break; + + case UbxFrameParserState.LOOKING_FOR_START2: + if (byte === UbxFrame.START_BYTE2) { + this.buffer.push(byte); + this.state = UbxFrameParserState.GETTING_MSG_ID; + } else if (byte === UbxFrame.START_BYTE1) { + this.buffer = [byte]; + this.state = UbxFrameParserState.LOOKING_FOR_START2; + } else { + this.state = UbxFrameParserState.LOOKING_FOR_START1; + } + break; + + case UbxFrameParserState.GETTING_MSG_ID: + this.buffer.push(byte); + this.msg_id = byte; + this.state = UbxFrameParserState.GETTING_LENGTH; + break; + + case UbxFrameParserState.GETTING_LENGTH: + this.buffer.push(byte); + this.msg_length = byte; + this.packet_size = UbxFrame.OVERHEAD + this.msg_length; + this.state = UbxFrameParserState.GETTING_PAYLOAD; + break; + + case UbxFrameParserState.GETTING_PAYLOAD: + this.buffer.push(byte); + + if (this.buffer.length >= this.packet_size) { + // Validate checksum + const msg_length = this.packet_size - UbxFrame.OVERHEAD; + const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { + result.valid = true; + result.msg_id = this.msg_id; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(this.buffer.slice(UbxFrame.HEADER_SIZE, this.packet_size - UbxFrame.FOOTER_SIZE)); + } + this.state = UbxFrameParserState.LOOKING_FOR_START1; + } + break; + } + + return result; + } + + /** + * Encode a message with UbxFrame format + * @param msg_id Message ID + * @param msg Message data + * @returns Encoded frame as Uint8Array + */ + static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { + const output: number[] = []; + output.push(UbxFrame.START_BYTE1); + output.push(UbxFrame.START_BYTE2); + output.push(msg_id); + output.push(msg.length & 0xFF); + for (let i = 0; i < msg.length; i++) { + output.push(msg[i]); + } + const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); + output.push(ck[0]); + output.push(ck[1]); + return new Uint8Array(output); + } + + /** + * Validate a complete UbxFrame packet in a buffer + * @param buffer Buffer containing the complete packet + * @returns FrameMsgInfo with valid=true if packet is valid + */ + static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { + const result = createFrameMsgInfo(); + + if (buffer.length < UbxFrame.OVERHEAD) { + return result; + } + + if (buffer[0] !== UbxFrame.START_BYTE1) { + return result; + } + if (buffer[1] !== UbxFrame.START_BYTE2) { + return result; + } + + const msg_length = buffer.length - UbxFrame.OVERHEAD; + + // Validate checksum + const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); + if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { + result.valid = true; + result.msg_id = buffer[2]; + result.msg_len = msg_length; + result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, UbxFrame.HEADER_SIZE, buffer.length - UbxFrame.FOOTER_SIZE)); + } + + return result; + } +} diff --git a/src/struct_frame/boilerplate/ts/frame_base.ts b/src/struct_frame/boilerplate/ts/frame_base.ts new file mode 100644 index 00000000..5b3c6745 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/frame_base.ts @@ -0,0 +1,63 @@ +// Automatically generated frame parser base utilities +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +// Frame format type enumeration +export enum FrameFormatType { + MINIMAL_FRAME = 0, + BASIC_FRAME = 1, + BASIC_FRAME_NO_CRC = 2, + TINY_FRAME = 3, + TINY_FRAME_NO_CRC = 4, + MINIMAL_FRAME_WITH_LEN = 5, + MINIMAL_FRAME_WITH_LEN_NO_CRC = 6, + BASIC_FRAME_WITH_LEN = 7, + BASIC_FRAME_WITH_LEN_NO_CRC = 8, + TINY_FRAME_WITH_LEN = 9, + TINY_FRAME_WITH_LEN_NO_CRC = 10, + MINIMAL_FRAME_WITH_LEN16 = 11, + MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12, + BASIC_FRAME_WITH_LEN16 = 13, + BASIC_FRAME_WITH_LEN16_NO_CRC = 14, + TINY_FRAME_WITH_LEN16 = 15, + TINY_FRAME_WITH_LEN16_NO_CRC = 16, + BASIC_FRAME_WITH_SYS_COMP = 17, + UBX_FRAME = 18, + MAVLINK_V1_FRAME = 19, + MAVLINK_V2_FRAME = 20, + FRAME_FORMAT_CONFIG = 21, +} + +// Fletcher-16 checksum calculation +export function fletcher_checksum(buffer: Uint8Array | number[], start: number = 0, end?: number): [number, number] { + if (end === undefined) { + end = buffer.length; + } + + let byte1 = 0; + let byte2 = 0; + + for (let i = start; i < end; i++) { + byte1 = (byte1 + buffer[i]) % 256; + byte2 = (byte2 + byte1) % 256; + } + + return [byte1, byte2]; +} + +// Parse result interface +export interface FrameMsgInfo { + valid: boolean; + msg_id: number; + msg_len: number; + msg_data: Uint8Array; +} + +// Create default FrameMsgInfo +export function createFrameMsgInfo(): FrameMsgInfo { + return { + valid: false, + msg_id: 0, + msg_len: 0, + msg_data: new Uint8Array(0) + }; +} diff --git a/src/struct_frame/boilerplate/ts/frame_parsers_gen.ts b/src/struct_frame/boilerplate/ts/frame_parsers_gen.ts deleted file mode 100644 index 6f224453..00000000 --- a/src/struct_frame/boilerplate/ts/frame_parsers_gen.ts +++ /dev/null @@ -1,3474 +0,0 @@ -// Automatically generated frame parser -// Generated by 0.0.1 at Wed Dec 3 09:37:56 2025. - -// Frame format type enumeration -export enum FrameFormatType { - MINIMAL_FRAME = 0, - BASIC_FRAME = 1, - BASIC_FRAME_NO_CRC = 2, - TINY_FRAME = 3, - TINY_FRAME_NO_CRC = 4, - MINIMAL_FRAME_WITH_LEN = 5, - MINIMAL_FRAME_WITH_LEN_NO_CRC = 6, - BASIC_FRAME_WITH_LEN = 7, - BASIC_FRAME_WITH_LEN_NO_CRC = 8, - TINY_FRAME_WITH_LEN = 9, - TINY_FRAME_WITH_LEN_NO_CRC = 10, - MINIMAL_FRAME_WITH_LEN16 = 11, - MINIMAL_FRAME_WITH_LEN16_NO_CRC = 12, - BASIC_FRAME_WITH_LEN16 = 13, - BASIC_FRAME_WITH_LEN16_NO_CRC = 14, - TINY_FRAME_WITH_LEN16 = 15, - TINY_FRAME_WITH_LEN16_NO_CRC = 16, - BASIC_FRAME_WITH_SYS_COMP = 17, - UBX_FRAME = 18, - MAVLINK_V1_FRAME = 19, - MAVLINK_V2_FRAME = 20, - FRAME_FORMAT_CONFIG = 21, -} - -// Fletcher-16 checksum calculation -export function fletcher_checksum(buffer: Uint8Array | number[], start: number = 0, end?: number): [number, number] { - if (end === undefined) { - end = buffer.length; - } - - let byte1 = 0; - let byte2 = 0; - - for (let i = start; i < end; i++) { - byte1 = (byte1 + buffer[i]) % 256; - byte2 = (byte2 + byte1) % 256; - } - - return [byte1, byte2]; -} - -// Parse result interface -export interface FrameMsgInfo { - valid: boolean; - msg_id: number; - msg_len: number; - msg_data: Uint8Array; -} - -// Create default FrameMsgInfo -export function createFrameMsgInfo(): FrameMsgInfo { - return { - valid: false, - msg_id: 0, - msg_len: 0, - msg_data: new Uint8Array(0) - }; -} - -// ============================================================================= -// MinimalFrame Frame Format -// ============================================================================= - -export enum MinimalFrameParserState { - GETTING_MSG_ID = 0, - GETTING_PAYLOAD = 1 -} - -/** - * MinimalFrame - Frame format parser and encoder - * - * Format: [MSG_ID] [MSG...] [CRC1] [CRC2] - */ -export class MinimalFrame { - static readonly HEADER_SIZE = 1; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 3; - - private state: MinimalFrameParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MinimalFrame parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MinimalFrameParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = MinimalFrame.OVERHEAD + msg_length; - this.state = MinimalFrameParserState.GETTING_PAYLOAD; - } else { - this.state = MinimalFrameParserState.GETTING_MSG_ID; - } - } else { - this.state = MinimalFrameParserState.GETTING_MSG_ID; - } - break; - - case MinimalFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - MinimalFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrame.HEADER_SIZE, this.packet_size - MinimalFrame.FOOTER_SIZE)); - } - this.state = MinimalFrameParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - /** - * Encode a message with MinimalFrame format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 0, 0 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete MinimalFrame packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrame.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrame.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrame.HEADER_SIZE, buffer.length - MinimalFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrame Frame Format -// ============================================================================= - -export enum BasicFrameParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_PAYLOAD = 3 -} - -/** - * BasicFrame - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - */ -export class BasicFrame { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x91; - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 5; - - private state: BasicFrameParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrame parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameParserState.LOOKING_FOR_START1: - if (byte === BasicFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameParserState.LOOKING_FOR_START2: - if (byte === BasicFrame.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameParserState.GETTING_MSG_ID; - } else if (byte === BasicFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = BasicFrame.OVERHEAD + msg_length; - this.state = BasicFrameParserState.GETTING_PAYLOAD; - } else { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - } else { - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - BasicFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrame.HEADER_SIZE, this.packet_size - BasicFrame.FOOTER_SIZE)); - } - this.state = BasicFrameParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrame format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrame.START_BYTE1); - output.push(BasicFrame.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrame packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrame.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrame.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrame.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrame.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrame.HEADER_SIZE, buffer.length - BasicFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrameNoCrc Frame Format -// ============================================================================= - -export enum BasicFrameNoCrcParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_PAYLOAD = 3 -} - -/** - * BasicFrameNoCrc - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x95] [MSG_ID] [MSG...] - */ -export class BasicFrameNoCrc { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x95; - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 3; - - private state: BasicFrameNoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrameNoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameNoCrcParserState.LOOKING_FOR_START1: - if (byte === BasicFrameNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameNoCrcParserState.LOOKING_FOR_START2: - if (byte === BasicFrameNoCrc.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameNoCrcParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = BasicFrameNoCrc.OVERHEAD + msg_length; - this.state = BasicFrameNoCrcParserState.GETTING_PAYLOAD; - } else { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - } else { - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - BasicFrameNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameNoCrc.HEADER_SIZE)); - this.state = BasicFrameNoCrcParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrameNoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrameNoCrc.START_BYTE1); - output.push(BasicFrameNoCrc.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrameNoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameNoCrc.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameNoCrc.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// TinyFrame Frame Format -// ============================================================================= - -export enum TinyFrameParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_PAYLOAD = 2 -} - -/** - * TinyFrame - Frame format parser and encoder - * - * Format: [START_BYTE=0x70] [MSG_ID] [MSG...] [CRC1] [CRC2] - */ -export class TinyFrame { - static readonly START_BYTE = 0x70; - static readonly HEADER_SIZE = 2; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 4; - - private state: TinyFrameParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new TinyFrame parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = TinyFrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameParserState.LOOKING_FOR_START: - if (byte === TinyFrame.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = TinyFrame.OVERHEAD + msg_length; - this.state = TinyFrameParserState.GETTING_PAYLOAD; - } else { - this.state = TinyFrameParserState.LOOKING_FOR_START; - } - } else { - this.state = TinyFrameParserState.LOOKING_FOR_START; - } - break; - - case TinyFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - TinyFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrame.HEADER_SIZE, this.packet_size - TinyFrame.FOOTER_SIZE)); - } - this.state = TinyFrameParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with TinyFrame format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(TinyFrame.START_BYTE); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete TinyFrame packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrame.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrame.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrame.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrame.HEADER_SIZE, buffer.length - TinyFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// TinyFrameNoCrc Frame Format -// ============================================================================= - -export enum TinyFrameNoCrcParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_PAYLOAD = 2 -} - -/** - * TinyFrameNoCrc - Frame format parser and encoder - * - * Format: [START_BYTE=0x72] [MSG_ID] [MSG...] - */ -export class TinyFrameNoCrc { - static readonly START_BYTE = 0x72; - static readonly HEADER_SIZE = 2; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 2; - - private state: TinyFrameNoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new TinyFrameNoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameNoCrcParserState.LOOKING_FOR_START: - if (byte === TinyFrameNoCrc.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameNoCrcParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = TinyFrameNoCrc.OVERHEAD + msg_length; - this.state = TinyFrameNoCrcParserState.GETTING_PAYLOAD; - } else { - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - } - } else { - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - } - break; - - case TinyFrameNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - TinyFrameNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameNoCrc.HEADER_SIZE)); - this.state = TinyFrameNoCrcParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with TinyFrameNoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(TinyFrameNoCrc.START_BYTE); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete TinyFrameNoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameNoCrc.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLen Frame Format -// ============================================================================= - -export enum MinimalFrameWithLenParserState { - GETTING_MSG_ID = 0, - GETTING_LENGTH = 1, - GETTING_PAYLOAD = 2 -} - -/** - * MinimalFrameWithLen - Frame format parser and encoder - * - * Format: [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - */ -export class MinimalFrameWithLen { - static readonly HEADER_SIZE = 2; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 4; - static readonly LENGTH_BYTES = 1; - - private state: MinimalFrameWithLenParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MinimalFrameWithLen parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLenParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLenParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLenParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MinimalFrameWithLen.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLenParserState.GETTING_PAYLOAD; - break; - - case MinimalFrameWithLenParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - MinimalFrameWithLen.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen.HEADER_SIZE, this.packet_size - MinimalFrameWithLen.FOOTER_SIZE)); - } - this.state = MinimalFrameWithLenParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - /** - * Encode a message with MinimalFrameWithLen format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete MinimalFrameWithLen packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLen.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLen.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen.HEADER_SIZE, buffer.length - MinimalFrameWithLen.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLenNoCrc Frame Format -// ============================================================================= - -export enum MinimalFrameWithLenNoCrcParserState { - GETTING_MSG_ID = 0, - GETTING_LENGTH = 1, - GETTING_PAYLOAD = 2 -} - -/** - * MinimalFrameWithLenNoCrc - Frame format parser and encoder - * - * Format: [MSG_ID] [LEN] [MSG...] - */ -export class MinimalFrameWithLenNoCrc { - static readonly HEADER_SIZE = 2; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 2; - static readonly LENGTH_BYTES = 1; - - private state: MinimalFrameWithLenNoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MinimalFrameWithLenNoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLenNoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MinimalFrameWithLenNoCrc.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD; - break; - - case MinimalFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - MinimalFrameWithLenNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLenNoCrc.HEADER_SIZE)); - this.state = MinimalFrameWithLenNoCrcParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - /** - * Encode a message with MinimalFrameWithLenNoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete MinimalFrameWithLenNoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLenNoCrc.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLenNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLenNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLen Frame Format -// ============================================================================= - -export enum BasicFrameWithLenParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_LENGTH = 3, - GETTING_PAYLOAD = 4 -} - -/** - * BasicFrameWithLen - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x92] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - */ -export class BasicFrameWithLen { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x92; - static readonly HEADER_SIZE = 4; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 6; - static readonly LENGTH_BYTES = 1; - - private state: BasicFrameWithLenParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrameWithLen parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLenParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLen.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLenParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLen.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLenParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLen.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLenParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLenParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLenParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = BasicFrameWithLen.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLenParserState.GETTING_PAYLOAD; - break; - - case BasicFrameWithLenParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - BasicFrameWithLen.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen.HEADER_SIZE, this.packet_size - BasicFrameWithLen.FOOTER_SIZE)); - } - this.state = BasicFrameWithLenParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrameWithLen format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrameWithLen.START_BYTE1); - output.push(BasicFrameWithLen.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrameWithLen packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLen.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLen.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLen.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLen.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen.HEADER_SIZE, buffer.length - BasicFrameWithLen.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLenNoCrc Frame Format -// ============================================================================= - -export enum BasicFrameWithLenNoCrcParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_LENGTH = 3, - GETTING_PAYLOAD = 4 -} - -/** - * BasicFrameWithLenNoCrc - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x96] [MSG_ID] [LEN] [MSG...] - */ -export class BasicFrameWithLenNoCrc { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x96; - static readonly HEADER_SIZE = 4; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 4; - static readonly LENGTH_BYTES = 1; - - private state: BasicFrameWithLenNoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrameWithLenNoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLenNoCrc.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLenNoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLenNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLenNoCrcParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLenNoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = BasicFrameWithLenNoCrc.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD; - break; - - case BasicFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - BasicFrameWithLenNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLenNoCrc.HEADER_SIZE)); - this.state = BasicFrameWithLenNoCrcParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrameWithLenNoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrameWithLenNoCrc.START_BYTE1); - output.push(BasicFrameWithLenNoCrc.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrameWithLenNoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLenNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLenNoCrc.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLenNoCrc.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLenNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLenNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLen Frame Format -// ============================================================================= - -export enum TinyFrameWithLenParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_LENGTH = 2, - GETTING_PAYLOAD = 3 -} - -/** - * TinyFrameWithLen - Frame format parser and encoder - * - * Format: [START_BYTE=0x71] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - */ -export class TinyFrameWithLen { - static readonly START_BYTE = 0x71; - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 5; - static readonly LENGTH_BYTES = 1; - - private state: TinyFrameWithLenParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new TinyFrameWithLen parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLenParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLen.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLenParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLenParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLenParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLenParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = TinyFrameWithLen.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLenParserState.GETTING_PAYLOAD; - break; - - case TinyFrameWithLenParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - TinyFrameWithLen.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen.HEADER_SIZE, this.packet_size - TinyFrameWithLen.FOOTER_SIZE)); - } - this.state = TinyFrameWithLenParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with TinyFrameWithLen format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(TinyFrameWithLen.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete TinyFrameWithLen packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLen.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLen.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLen.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen.HEADER_SIZE, buffer.length - TinyFrameWithLen.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLenNoCrc Frame Format -// ============================================================================= - -export enum TinyFrameWithLenNoCrcParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_LENGTH = 2, - GETTING_PAYLOAD = 3 -} - -/** - * TinyFrameWithLenNoCrc - Frame format parser and encoder - * - * Format: [START_BYTE=0x73] [MSG_ID] [LEN] [MSG...] - */ -export class TinyFrameWithLenNoCrc { - static readonly START_BYTE = 0x73; - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 3; - static readonly LENGTH_BYTES = 1; - - private state: TinyFrameWithLenNoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new TinyFrameWithLenNoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLenNoCrc.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLenNoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLenNoCrcParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLenNoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = TinyFrameWithLenNoCrc.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD; - break; - - case TinyFrameWithLenNoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - TinyFrameWithLenNoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLenNoCrc.HEADER_SIZE)); - this.state = TinyFrameWithLenNoCrcParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with TinyFrameWithLenNoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(TinyFrameWithLenNoCrc.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete TinyFrameWithLenNoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLenNoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLenNoCrc.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLenNoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLenNoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLen16 Frame Format -// ============================================================================= - -export enum MinimalFrameWithLen16ParserState { - GETTING_MSG_ID = 0, - GETTING_LENGTH = 1, - GETTING_PAYLOAD = 2 -} - -/** - * MinimalFrameWithLen16 - Frame format parser and encoder - * - * Format: [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] - */ -export class MinimalFrameWithLen16 { - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 5; - static readonly LENGTH_BYTES = 2; - - private state: MinimalFrameWithLen16ParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private length_lo: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MinimalFrameWithLen16 parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLen16ParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLen16ParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLen16ParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 2) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = MinimalFrameWithLen16.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLen16ParserState.GETTING_PAYLOAD; - } - break; - - case MinimalFrameWithLen16ParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - MinimalFrameWithLen16.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 0, 0 + msg_length + 1 + 2); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16.HEADER_SIZE, this.packet_size - MinimalFrameWithLen16.FOOTER_SIZE)); - } - this.state = MinimalFrameWithLen16ParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - /** - * Encode a message with MinimalFrameWithLen16 format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 0, 0 + msg.length + 1 + 2); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete MinimalFrameWithLen16 packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLen16.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLen16.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 0, 0 + msg_length + 1 + 2); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16.HEADER_SIZE, buffer.length - MinimalFrameWithLen16.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MinimalFrameWithLen16NoCrc Frame Format -// ============================================================================= - -export enum MinimalFrameWithLen16NoCrcParserState { - GETTING_MSG_ID = 0, - GETTING_LENGTH = 1, - GETTING_PAYLOAD = 2 -} - -/** - * MinimalFrameWithLen16NoCrc - Frame format parser and encoder - * - * Format: [MSG_ID] [LEN16] [MSG...] - */ -export class MinimalFrameWithLen16NoCrc { - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 3; - static readonly LENGTH_BYTES = 2; - - private state: MinimalFrameWithLen16NoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private length_lo: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MinimalFrameWithLen16NoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH; - break; - - case MinimalFrameWithLen16NoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 2) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = MinimalFrameWithLen16NoCrc.OVERHEAD + this.msg_length; - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; - } - break; - - case MinimalFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - MinimalFrameWithLen16NoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(MinimalFrameWithLen16NoCrc.HEADER_SIZE)); - this.state = MinimalFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - } - break; - } - - return result; - } - - /** - * Encode a message with MinimalFrameWithLen16NoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete MinimalFrameWithLen16NoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MinimalFrameWithLen16NoCrc.OVERHEAD) { - return result; - } - - - const msg_length = buffer.length - MinimalFrameWithLen16NoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[0]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MinimalFrameWithLen16NoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLen16 Frame Format -// ============================================================================= - -export enum BasicFrameWithLen16ParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_LENGTH = 3, - GETTING_PAYLOAD = 4 -} - -/** - * BasicFrameWithLen16 - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x93] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] - */ -export class BasicFrameWithLen16 { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x93; - static readonly HEADER_SIZE = 5; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 7; - static readonly LENGTH_BYTES = 2; - - private state: BasicFrameWithLen16ParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private length_lo: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrameWithLen16 parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLen16ParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLen16.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLen16ParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLen16.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLen16ParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLen16.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLen16ParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLen16ParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLen16ParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 4) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = BasicFrameWithLen16.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLen16ParserState.GETTING_PAYLOAD; - } - break; - - case BasicFrameWithLen16ParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - BasicFrameWithLen16.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 2); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16.HEADER_SIZE, this.packet_size - BasicFrameWithLen16.FOOTER_SIZE)); - } - this.state = BasicFrameWithLen16ParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrameWithLen16 format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrameWithLen16.START_BYTE1); - output.push(BasicFrameWithLen16.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 2); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrameWithLen16 packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLen16.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLen16.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLen16.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLen16.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 2); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16.HEADER_SIZE, buffer.length - BasicFrameWithLen16.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithLen16NoCrc Frame Format -// ============================================================================= - -export enum BasicFrameWithLen16NoCrcParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_LENGTH = 3, - GETTING_PAYLOAD = 4 -} - -/** - * BasicFrameWithLen16NoCrc - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x97] [MSG_ID] [LEN16] [MSG...] - */ -export class BasicFrameWithLen16NoCrc { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x97; - static readonly HEADER_SIZE = 5; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 5; - static readonly LENGTH_BYTES = 2; - - private state: BasicFrameWithLen16NoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private length_lo: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrameWithLen16NoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithLen16NoCrc.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithLen16NoCrc.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH; - break; - - case BasicFrameWithLen16NoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 4) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = BasicFrameWithLen16NoCrc.OVERHEAD + this.msg_length; - this.state = BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; - } - break; - - case BasicFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - BasicFrameWithLen16NoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithLen16NoCrc.HEADER_SIZE)); - this.state = BasicFrameWithLen16NoCrcParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrameWithLen16NoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrameWithLen16NoCrc.START_BYTE1); - output.push(BasicFrameWithLen16NoCrc.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrameWithLen16NoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithLen16NoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithLen16NoCrc.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithLen16NoCrc.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithLen16NoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithLen16NoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLen16 Frame Format -// ============================================================================= - -export enum TinyFrameWithLen16ParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_LENGTH = 2, - GETTING_PAYLOAD = 3 -} - -/** - * TinyFrameWithLen16 - Frame format parser and encoder - * - * Format: [START_BYTE=0x74] [MSG_ID] [LEN16] [MSG...] [CRC1] [CRC2] - */ -export class TinyFrameWithLen16 { - static readonly START_BYTE = 0x74; - static readonly HEADER_SIZE = 4; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 6; - static readonly LENGTH_BYTES = 2; - - private state: TinyFrameWithLen16ParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private length_lo: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new TinyFrameWithLen16 parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLen16ParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLen16.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLen16ParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLen16ParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLen16ParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLen16ParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 3) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = TinyFrameWithLen16.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLen16ParserState.GETTING_PAYLOAD; - } - break; - - case TinyFrameWithLen16ParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - TinyFrameWithLen16.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 2); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16.HEADER_SIZE, this.packet_size - TinyFrameWithLen16.FOOTER_SIZE)); - } - this.state = TinyFrameWithLen16ParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with TinyFrameWithLen16 format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(TinyFrameWithLen16.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 2); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete TinyFrameWithLen16 packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLen16.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLen16.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLen16.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 2); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16.HEADER_SIZE, buffer.length - TinyFrameWithLen16.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// TinyFrameWithLen16NoCrc Frame Format -// ============================================================================= - -export enum TinyFrameWithLen16NoCrcParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_LENGTH = 2, - GETTING_PAYLOAD = 3 -} - -/** - * TinyFrameWithLen16NoCrc - Frame format parser and encoder - * - * Format: [START_BYTE=0x75] [MSG_ID] [LEN16] [MSG...] - */ -export class TinyFrameWithLen16NoCrc { - static readonly START_BYTE = 0x75; - static readonly HEADER_SIZE = 4; - static readonly FOOTER_SIZE = 0; - static readonly OVERHEAD = 4; - static readonly LENGTH_BYTES = 2; - - private state: TinyFrameWithLen16NoCrcParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private length_lo: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new TinyFrameWithLen16NoCrc parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - this.length_lo = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START: - if (byte === TinyFrameWithLen16NoCrc.START_BYTE) { - this.buffer = [byte]; - this.state = TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID; - } - break; - - case TinyFrameWithLen16NoCrcParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH; - break; - - case TinyFrameWithLen16NoCrcParserState.GETTING_LENGTH: - this.buffer.push(byte); - if (this.buffer.length === 3) { - this.length_lo = byte; - } else { - this.msg_length = this.length_lo | (byte << 8); - this.packet_size = TinyFrameWithLen16NoCrc.OVERHEAD + this.msg_length; - this.state = TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD; - } - break; - - case TinyFrameWithLen16NoCrcParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = this.packet_size - TinyFrameWithLen16NoCrc.OVERHEAD; - result.msg_data = new Uint8Array(this.buffer.slice(TinyFrameWithLen16NoCrc.HEADER_SIZE)); - this.state = TinyFrameWithLen16NoCrcParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with TinyFrameWithLen16NoCrc format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(TinyFrameWithLen16NoCrc.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - output.push((msg.length >> 8) & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - return new Uint8Array(output); - } - - /** - * Validate a complete TinyFrameWithLen16NoCrc packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < TinyFrameWithLen16NoCrc.OVERHEAD) { - return result; - } - - if (buffer[0] !== TinyFrameWithLen16NoCrc.START_BYTE) { - return result; - } - - const msg_length = buffer.length - TinyFrameWithLen16NoCrc.OVERHEAD; - - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, TinyFrameWithLen16NoCrc.HEADER_SIZE)); - - return result; - } -} - - -// ============================================================================= -// BasicFrameWithSysComp Frame Format -// ============================================================================= - -export enum BasicFrameWithSysCompParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_PAYLOAD = 3 -} - -/** - * BasicFrameWithSysComp - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x94] [MSG_ID] [MSG...] [CRC1] [CRC2] - */ -export class BasicFrameWithSysComp { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x94; - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 5; - - private state: BasicFrameWithSysCompParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new BasicFrameWithSysComp parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case BasicFrameWithSysCompParserState.LOOKING_FOR_START1: - if (byte === BasicFrameWithSysComp.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; - } - break; - - case BasicFrameWithSysCompParserState.LOOKING_FOR_START2: - if (byte === BasicFrameWithSysComp.START_BYTE2) { - this.buffer.push(byte); - this.state = BasicFrameWithSysCompParserState.GETTING_MSG_ID; - } else if (byte === BasicFrameWithSysComp.START_BYTE1) { - this.buffer = [byte]; - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START2; - } else { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithSysCompParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = BasicFrameWithSysComp.OVERHEAD + msg_length; - this.state = BasicFrameWithSysCompParserState.GETTING_PAYLOAD; - } else { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - } else { - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - break; - - case BasicFrameWithSysCompParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - BasicFrameWithSysComp.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(BasicFrameWithSysComp.HEADER_SIZE, this.packet_size - BasicFrameWithSysComp.FOOTER_SIZE)); - } - this.state = BasicFrameWithSysCompParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with BasicFrameWithSysComp format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(BasicFrameWithSysComp.START_BYTE1); - output.push(BasicFrameWithSysComp.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete BasicFrameWithSysComp packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < BasicFrameWithSysComp.OVERHEAD) { - return result; - } - - if (buffer[0] !== BasicFrameWithSysComp.START_BYTE1) { - return result; - } - if (buffer[1] !== BasicFrameWithSysComp.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - BasicFrameWithSysComp.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, BasicFrameWithSysComp.HEADER_SIZE, buffer.length - BasicFrameWithSysComp.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// UbxFrame Frame Format -// ============================================================================= - -export enum UbxFrameParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_LENGTH = 3, - GETTING_PAYLOAD = 4 -} - -/** - * UbxFrame - Frame format parser and encoder - * - * Format: [SYNC1=0xB5] [SYNC2=0x62] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - */ -export class UbxFrame { - static readonly START_BYTE1 = 0xB5; - static readonly START_BYTE2 = 0x62; - static readonly HEADER_SIZE = 5; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 7; - static readonly LENGTH_BYTES = 1; - - private state: UbxFrameParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new UbxFrame parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = UbxFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = UbxFrameParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case UbxFrameParserState.LOOKING_FOR_START1: - if (byte === UbxFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = UbxFrameParserState.LOOKING_FOR_START2; - } - break; - - case UbxFrameParserState.LOOKING_FOR_START2: - if (byte === UbxFrame.START_BYTE2) { - this.buffer.push(byte); - this.state = UbxFrameParserState.GETTING_MSG_ID; - } else if (byte === UbxFrame.START_BYTE1) { - this.buffer = [byte]; - this.state = UbxFrameParserState.LOOKING_FOR_START2; - } else { - this.state = UbxFrameParserState.LOOKING_FOR_START1; - } - break; - - case UbxFrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = UbxFrameParserState.GETTING_LENGTH; - break; - - case UbxFrameParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = UbxFrame.OVERHEAD + this.msg_length; - this.state = UbxFrameParserState.GETTING_PAYLOAD; - break; - - case UbxFrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - UbxFrame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(UbxFrame.HEADER_SIZE, this.packet_size - UbxFrame.FOOTER_SIZE)); - } - this.state = UbxFrameParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with UbxFrame format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(UbxFrame.START_BYTE1); - output.push(UbxFrame.START_BYTE2); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete UbxFrame packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < UbxFrame.OVERHEAD) { - return result; - } - - if (buffer[0] !== UbxFrame.START_BYTE1) { - return result; - } - if (buffer[1] !== UbxFrame.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - UbxFrame.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, UbxFrame.HEADER_SIZE, buffer.length - UbxFrame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MavlinkV1Frame Frame Format -// ============================================================================= - -export enum MavlinkV1FrameParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_LENGTH = 2, - GETTING_PAYLOAD = 3 -} - -/** - * MavlinkV1Frame - Frame format parser and encoder - * - * Format: [STX=0xFE] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - */ -export class MavlinkV1Frame { - static readonly START_BYTE = 0xFE; - static readonly HEADER_SIZE = 3; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 5; - static readonly LENGTH_BYTES = 1; - - private state: MavlinkV1FrameParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MavlinkV1Frame parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MavlinkV1FrameParserState.LOOKING_FOR_START: - if (byte === MavlinkV1Frame.START_BYTE) { - this.buffer = [byte]; - this.state = MavlinkV1FrameParserState.GETTING_MSG_ID; - } - break; - - case MavlinkV1FrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MavlinkV1FrameParserState.GETTING_LENGTH; - break; - - case MavlinkV1FrameParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MavlinkV1Frame.OVERHEAD + this.msg_length; - this.state = MavlinkV1FrameParserState.GETTING_PAYLOAD; - break; - - case MavlinkV1FrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - MavlinkV1Frame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV1Frame.HEADER_SIZE, this.packet_size - MavlinkV1Frame.FOOTER_SIZE)); - } - this.state = MavlinkV1FrameParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with MavlinkV1Frame format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(MavlinkV1Frame.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete MavlinkV1Frame packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MavlinkV1Frame.OVERHEAD) { - return result; - } - - if (buffer[0] !== MavlinkV1Frame.START_BYTE) { - return result; - } - - const msg_length = buffer.length - MavlinkV1Frame.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV1Frame.HEADER_SIZE, buffer.length - MavlinkV1Frame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// MavlinkV2Frame Frame Format -// ============================================================================= - -export enum MavlinkV2FrameParserState { - LOOKING_FOR_START = 0, - GETTING_MSG_ID = 1, - GETTING_LENGTH = 2, - GETTING_PAYLOAD = 3 -} - -/** - * MavlinkV2Frame - Frame format parser and encoder - * - * Format: [STX=0xFD] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - */ -export class MavlinkV2Frame { - static readonly START_BYTE = 0xFD; - static readonly HEADER_SIZE = 5; - static readonly FOOTER_SIZE = 2; - static readonly OVERHEAD = 7; - static readonly LENGTH_BYTES = 1; - - private state: MavlinkV2FrameParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private msg_length: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new MavlinkV2Frame parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - this.msg_length = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case MavlinkV2FrameParserState.LOOKING_FOR_START: - if (byte === MavlinkV2Frame.START_BYTE) { - this.buffer = [byte]; - this.state = MavlinkV2FrameParserState.GETTING_MSG_ID; - } - break; - - case MavlinkV2FrameParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - this.state = MavlinkV2FrameParserState.GETTING_LENGTH; - break; - - case MavlinkV2FrameParserState.GETTING_LENGTH: - this.buffer.push(byte); - this.msg_length = byte; - this.packet_size = MavlinkV2Frame.OVERHEAD + this.msg_length; - this.state = MavlinkV2FrameParserState.GETTING_PAYLOAD; - break; - - case MavlinkV2FrameParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - MavlinkV2Frame.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(MavlinkV2Frame.HEADER_SIZE, this.packet_size - MavlinkV2Frame.FOOTER_SIZE)); - } - this.state = MavlinkV2FrameParserState.LOOKING_FOR_START; - } - break; - } - - return result; - } - - /** - * Encode a message with MavlinkV2Frame format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(MavlinkV2Frame.START_BYTE); - output.push(msg_id); - output.push(msg.length & 0xFF); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 1, 1 + msg.length + 1 + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete MavlinkV2Frame packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < MavlinkV2Frame.OVERHEAD) { - return result; - } - - if (buffer[0] !== MavlinkV2Frame.START_BYTE) { - return result; - } - - const msg_length = buffer.length - MavlinkV2Frame.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 1, 1 + msg_length + 1 + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[1]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, MavlinkV2Frame.HEADER_SIZE, buffer.length - MavlinkV2Frame.FOOTER_SIZE)); - } - - return result; - } -} - - -// ============================================================================= -// FrameFormatConfig Frame Format -// ============================================================================= - -export enum FrameFormatConfigParserState { - LOOKING_FOR_START1 = 0, - LOOKING_FOR_START2 = 1, - GETTING_MSG_ID = 2, - GETTING_PAYLOAD = 3 -} - -/** - * FrameFormatConfig - Frame format parser and encoder - * - * Format: [START_BYTE1=0x90] [START_BYTE2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - */ -export class FrameFormatConfig { - static readonly START_BYTE1 = 0x90; - static readonly START_BYTE2 = 0x91; - static readonly HEADER_SIZE = 2; - static readonly FOOTER_SIZE = 1; - static readonly OVERHEAD = 3; - - private state: FrameFormatConfigParserState; - private buffer: number[]; - private packet_size: number; - private msg_id: number; - private get_msg_length?: (msg_id: number) => number | undefined; - - /** - * Create a new FrameFormatConfig parser - * @param get_msg_length Callback to get message length from msg_id (required for non-length frames) - */ - constructor(get_msg_length?: (msg_id: number) => number | undefined) { - this.get_msg_length = get_msg_length; - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** Reset parser state */ - reset(): void { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - this.buffer = []; - this.packet_size = 0; - this.msg_id = 0; - } - - /** - * Parse a single byte - * @param byte The byte to parse - * @returns FrameMsgInfo with valid=true when a complete valid message is received - */ - parse_byte(byte: number): FrameMsgInfo { - const result = createFrameMsgInfo(); - - switch (this.state) { - case FrameFormatConfigParserState.LOOKING_FOR_START1: - if (byte === FrameFormatConfig.START_BYTE1) { - this.buffer = [byte]; - this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; - } - break; - - case FrameFormatConfigParserState.LOOKING_FOR_START2: - if (byte === FrameFormatConfig.START_BYTE2) { - this.buffer.push(byte); - this.state = FrameFormatConfigParserState.GETTING_MSG_ID; - } else if (byte === FrameFormatConfig.START_BYTE1) { - this.buffer = [byte]; - this.state = FrameFormatConfigParserState.LOOKING_FOR_START2; - } else { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - break; - - case FrameFormatConfigParserState.GETTING_MSG_ID: - this.buffer.push(byte); - this.msg_id = byte; - if (this.get_msg_length) { - const msg_length = this.get_msg_length(byte); - if (msg_length !== undefined) { - this.packet_size = FrameFormatConfig.OVERHEAD + msg_length; - this.state = FrameFormatConfigParserState.GETTING_PAYLOAD; - } else { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - } else { - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - break; - - case FrameFormatConfigParserState.GETTING_PAYLOAD: - this.buffer.push(byte); - - if (this.buffer.length >= this.packet_size) { - // Validate checksum - const msg_length = this.packet_size - FrameFormatConfig.OVERHEAD; - const ck = fletcher_checksum(this.buffer, 2, 2 + msg_length + 1); - if (ck[0] === this.buffer[this.buffer.length - 2] && ck[1] === this.buffer[this.buffer.length - 1]) { - result.valid = true; - result.msg_id = this.msg_id; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(this.buffer.slice(FrameFormatConfig.HEADER_SIZE, this.packet_size - FrameFormatConfig.FOOTER_SIZE)); - } - this.state = FrameFormatConfigParserState.LOOKING_FOR_START1; - } - break; - } - - return result; - } - - /** - * Encode a message with FrameFormatConfig format - * @param msg_id Message ID - * @param msg Message data - * @returns Encoded frame as Uint8Array - */ - static encode(msg_id: number, msg: Uint8Array | number[]): Uint8Array { - const output: number[] = []; - output.push(FrameFormatConfig.START_BYTE1); - output.push(FrameFormatConfig.START_BYTE2); - output.push(msg_id); - for (let i = 0; i < msg.length; i++) { - output.push(msg[i]); - } - const ck = fletcher_checksum(output, 2, 2 + msg.length + 1); - output.push(ck[0]); - output.push(ck[1]); - return new Uint8Array(output); - } - - /** - * Validate a complete FrameFormatConfig packet in a buffer - * @param buffer Buffer containing the complete packet - * @returns FrameMsgInfo with valid=true if packet is valid - */ - static validate_packet(buffer: Uint8Array | number[]): FrameMsgInfo { - const result = createFrameMsgInfo(); - - if (buffer.length < FrameFormatConfig.OVERHEAD) { - return result; - } - - if (buffer[0] !== FrameFormatConfig.START_BYTE1) { - return result; - } - if (buffer[1] !== FrameFormatConfig.START_BYTE2) { - return result; - } - - const msg_length = buffer.length - FrameFormatConfig.OVERHEAD; - - // Validate checksum - const ck = fletcher_checksum(buffer, 2, 2 + msg_length + 1); - if (ck[0] === buffer[buffer.length - 2] && ck[1] === buffer[buffer.length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_length; - result.msg_data = new Uint8Array(Array.prototype.slice.call(buffer, FrameFormatConfig.HEADER_SIZE, buffer.length - FrameFormatConfig.FOOTER_SIZE)); - } - - return result; - } -} - - diff --git a/src/struct_frame/boilerplate/ts/index.ts b/src/struct_frame/boilerplate/ts/index.ts new file mode 100644 index 00000000..1f3b8394 --- /dev/null +++ b/src/struct_frame/boilerplate/ts/index.ts @@ -0,0 +1,34 @@ +// Automatically generated frame parser package +// Generated by 0.0.1 at Wed Dec 3 17:57:16 2025. + +// Base utilities +export { + FrameFormatType, + FrameMsgInfo, + createFrameMsgInfo, + fletcher_checksum, +} from './frame_base'; + +// Individual frame format parsers +export { MinimalFrame, MinimalFrameParserState } from './MinimalFrame'; +export { BasicFrame, BasicFrameParserState } from './BasicFrame'; +export { BasicFrameNoCrc, BasicFrameNoCrcParserState } from './BasicFrameNoCrc'; +export { TinyFrame, TinyFrameParserState } from './TinyFrame'; +export { TinyFrameNoCrc, TinyFrameNoCrcParserState } from './TinyFrameNoCrc'; +export { MinimalFrameWithLen, MinimalFrameWithLenParserState } from './MinimalFrameWithLen'; +export { MinimalFrameWithLenNoCrc, MinimalFrameWithLenNoCrcParserState } from './MinimalFrameWithLenNoCrc'; +export { BasicFrameWithLen, BasicFrameWithLenParserState } from './BasicFrameWithLen'; +export { BasicFrameWithLenNoCrc, BasicFrameWithLenNoCrcParserState } from './BasicFrameWithLenNoCrc'; +export { TinyFrameWithLen, TinyFrameWithLenParserState } from './TinyFrameWithLen'; +export { TinyFrameWithLenNoCrc, TinyFrameWithLenNoCrcParserState } from './TinyFrameWithLenNoCrc'; +export { MinimalFrameWithLen16, MinimalFrameWithLen16ParserState } from './MinimalFrameWithLen16'; +export { MinimalFrameWithLen16NoCrc, MinimalFrameWithLen16NoCrcParserState } from './MinimalFrameWithLen16NoCrc'; +export { BasicFrameWithLen16, BasicFrameWithLen16ParserState } from './BasicFrameWithLen16'; +export { BasicFrameWithLen16NoCrc, BasicFrameWithLen16NoCrcParserState } from './BasicFrameWithLen16NoCrc'; +export { TinyFrameWithLen16, TinyFrameWithLen16ParserState } from './TinyFrameWithLen16'; +export { TinyFrameWithLen16NoCrc, TinyFrameWithLen16NoCrcParserState } from './TinyFrameWithLen16NoCrc'; +export { BasicFrameWithSysComp, BasicFrameWithSysCompParserState } from './BasicFrameWithSysComp'; +export { UbxFrame, UbxFrameParserState } from './UbxFrame'; +export { MavlinkV1Frame, MavlinkV1FrameParserState } from './MavlinkV1Frame'; +export { MavlinkV2Frame, MavlinkV2FrameParserState } from './MavlinkV2Frame'; +export { FrameFormatConfig, FrameFormatConfigParserState } from './FrameFormatConfig'; diff --git a/src/struct_frame/frame_parser_c_gen.py b/src/struct_frame/frame_parser_c_gen.py index a81e3ef2..b72f101d 100644 --- a/src/struct_frame/frame_parser_c_gen.py +++ b/src/struct_frame/frame_parser_c_gen.py @@ -26,10 +26,88 @@ def camel_to_upper_snake(name): class FrameParserCGen: """Generates C code for frame parsers""" - + + @staticmethod + def generate_base(formats): + """Generate the base C header file with common utilities""" + yield '/* Automatically generated frame parser base utilities */\n' + yield '/* Generated by %s at %s. */\n\n' % (version, time.asctime()) + yield '#pragma once\n\n' + yield '#include \n' + yield '#include \n' + yield '#include \n' + yield '#include \n\n' + + # Generate frame format enum + yield '/* Frame format type enumeration */\n' + yield 'typedef enum FrameFormatType {\n' + for i, fmt in enumerate(formats): + enum_name = camel_to_upper_snake(fmt.name) + yield f' FRAME_FORMAT_{enum_name} = {i},\n' + yield '} FrameFormatType;\n\n' + + # Generate checksum function + yield '/*===========================================================================\n' + yield ' * Checksum Calculation\n' + yield ' *===========================================================================*/\n\n' + yield '''typedef struct frame_checksum { + uint8_t byte1; + uint8_t byte2; +} frame_checksum_t; + +/** + * Calculate Fletcher-16 checksum over the given data + */ +static inline frame_checksum_t frame_fletcher_checksum(const uint8_t* data, size_t length) { + frame_checksum_t ck = {0, 0}; + for (size_t i = 0; i < length; i++) { + ck.byte1 = (uint8_t)(ck.byte1 + data[i]); + ck.byte2 = (uint8_t)(ck.byte2 + ck.byte1); + } + return ck; +} + +''' + + # Generate common result type + yield '''/* Parse result */ +typedef struct frame_msg_info { + bool valid; + uint8_t msg_id; + size_t msg_len; + uint8_t* msg_data; +} frame_msg_info_t; +''' + + @staticmethod + def generate_format_file(fmt): + """Generate a C header file for a single frame format""" + prefix = camel_to_snake(fmt.name) + PREFIX = camel_to_upper_snake(fmt.name) + + yield '/* Automatically generated frame parser */\n' + yield '/* Generated by %s at %s. */\n\n' % (version, time.asctime()) + yield '#pragma once\n\n' + yield '#include "frame_base.h"\n\n' + + yield from FrameParserCGen.generate_format(fmt) + + @staticmethod + def generate_main_header(formats): + """Generate main header that includes all frame format headers""" + yield '/* Automatically generated frame parser main header */\n' + yield '/* Generated by %s at %s. */\n\n' % (version, time.asctime()) + yield '#pragma once\n\n' + yield '/* Base utilities */\n' + yield '#include "frame_base.h"\n\n' + yield '/* Individual frame format parsers */\n' + for fmt in formats: + snake_name = camel_to_snake(fmt.name) + yield f'#include "{snake_name}.h"\n' + @staticmethod def generate_header(formats): - """Generate the complete frame parser header file""" + """Generate the complete frame parser header file (single file, legacy mode)""" yield '/* Automatically generated frame parser header */\n' yield '/* Generated by %s at %s. */\n\n' % (version, time.asctime()) yield '#pragma once\n\n' @@ -442,3 +520,28 @@ def generate_format(fmt): def generate_c_frame_parsers(formats): """Generate C frame parser code from frame format definitions""" return ''.join(FrameParserCGen.generate_header(formats)) + + +def generate_c_frame_parsers_multi(formats): + """ + Generate multiple C header files for frame parsers. + + Returns a dictionary mapping filename to content: + - frame_base.h: Base utilities (checksum, frame_msg_info_t, FrameFormatType) + - {snake_name}.h: Individual frame format headers + - frame_parsers.h: Main header that includes all frame formats + """ + files = {} + + # Generate base file + files['frame_base.h'] = ''.join(FrameParserCGen.generate_base(formats)) + + # Generate individual frame format files + for fmt in formats: + snake_name = camel_to_snake(fmt.name) + files[f'{snake_name}.h'] = ''.join(FrameParserCGen.generate_format_file(fmt)) + + # Generate main header + files['frame_parsers.h'] = ''.join(FrameParserCGen.generate_main_header(formats)) + + return files diff --git a/src/struct_frame/frame_parser_cpp_gen.py b/src/struct_frame/frame_parser_cpp_gen.py index 7ece1a65..0ccf6a4c 100644 --- a/src/struct_frame/frame_parser_cpp_gen.py +++ b/src/struct_frame/frame_parser_cpp_gen.py @@ -26,10 +26,90 @@ def camel_to_upper_snake(name): class FrameParserCppGen: """Generates C++ code for frame parsers""" - + + @staticmethod + def generate_base(formats): + """Generate the base C++ header file with common utilities""" + yield '/* Automatically generated frame parser base utilities */\n' + yield f'/* Generated by {version} at {time.asctime()}. */\n\n' + yield '#pragma once\n\n' + yield '#include \n' + yield '#include \n' + yield '#include \n' + yield '#include \n\n' + yield 'namespace FrameParsers {\n\n' + + # Generate frame format enum + yield '// Frame format type enumeration\n' + yield 'enum class FrameFormatType {\n' + for i, fmt in enumerate(formats): + enum_name = camel_to_upper_snake(fmt.name) + yield f' {enum_name} = {i},\n' + yield '};\n\n' + + # Generate checksum struct and function + yield '''// Checksum result +struct FrameChecksum { + uint8_t byte1; + uint8_t byte2; +}; + +// Fletcher-16 checksum calculation +inline FrameChecksum fletcher_checksum(const uint8_t* data, size_t length) { + FrameChecksum ck{0, 0}; + for (size_t i = 0; i < length; i++) { + ck.byte1 = static_cast(ck.byte1 + data[i]); + ck.byte2 = static_cast(ck.byte2 + ck.byte1); + } + return ck; +} + +''' + + # Generate common result struct + yield '''// Parse result +struct FrameMsgInfo { + bool valid; + uint8_t msg_id; + size_t msg_len; + uint8_t* msg_data; + + FrameMsgInfo() : valid(false), msg_id(0), msg_len(0), msg_data(nullptr) {} + FrameMsgInfo(bool v, uint8_t id, size_t len, uint8_t* data) + : valid(v), msg_id(id), msg_len(len), msg_data(data) {} +}; + +} // namespace FrameParsers +''' + + @staticmethod + def generate_format_file(fmt): + """Generate a C++ header file for a single frame format""" + yield '/* Automatically generated frame parser */\n' + yield f'/* Generated by {version} at {time.asctime()}. */\n\n' + yield '#pragma once\n\n' + yield '#include "frame_base.hpp"\n\n' + yield 'namespace FrameParsers {\n\n' + + yield from FrameParserCppGen.generate_format(fmt) + + yield '} // namespace FrameParsers\n' + + @staticmethod + def generate_main_header(formats): + """Generate main header that includes all frame format headers""" + yield '/* Automatically generated frame parser main header */\n' + yield f'/* Generated by {version} at {time.asctime()}. */\n\n' + yield '#pragma once\n\n' + yield '/* Base utilities */\n' + yield '#include "frame_base.hpp"\n\n' + yield '/* Individual frame format parsers */\n' + for fmt in formats: + yield f'#include "{fmt.name}.hpp"\n' + @staticmethod def generate_header(formats): - """Generate the complete frame parser header file""" + """Generate the complete frame parser header file (single file, legacy mode)""" yield '/* Automatically generated frame parser header */\n' yield f'/* Generated by {version} at {time.asctime()}. */\n\n' yield '#pragma once\n\n' @@ -457,3 +537,27 @@ def generate_format(fmt): def generate_cpp_frame_parsers(formats): """Generate C++ frame parser code from frame format definitions""" return ''.join(FrameParserCppGen.generate_header(formats)) + + +def generate_cpp_frame_parsers_multi(formats): + """ + Generate multiple C++ header files for frame parsers. + + Returns a dictionary mapping filename to content: + - frame_base.hpp: Base utilities (checksum, FrameMsgInfo, FrameFormatType) + - {ClassName}.hpp: Individual frame format headers + - frame_parsers.hpp: Main header that includes all frame formats + """ + files = {} + + # Generate base file + files['frame_base.hpp'] = ''.join(FrameParserCppGen.generate_base(formats)) + + # Generate individual frame format files + for fmt in formats: + files[f'{fmt.name}.hpp'] = ''.join(FrameParserCppGen.generate_format_file(fmt)) + + # Generate main header + files['frame_parsers.hpp'] = ''.join(FrameParserCppGen.generate_main_header(formats)) + + return files diff --git a/src/struct_frame/frame_parser_py_gen.py b/src/struct_frame/frame_parser_py_gen.py index 19ff6010..c376bd42 100644 --- a/src/struct_frame/frame_parser_py_gen.py +++ b/src/struct_frame/frame_parser_py_gen.py @@ -26,10 +26,95 @@ def camel_to_upper_snake(name): class FrameParserPyGen: """Generates Python code for frame parsers""" - + + @staticmethod + def generate_base(formats): + """Generate the base Python file with common utilities""" + yield '# Automatically generated frame parser base utilities\n' + yield f'# Generated by {version} at {time.asctime()}.\n\n' + yield 'from enum import Enum\n' + yield 'from typing import List, Tuple, Union\n' + yield 'from dataclasses import dataclass\n\n' + + # Generate frame format enum + yield '# Frame format type enumeration\n' + yield 'class FrameFormatType(Enum):\n' + for i, fmt in enumerate(formats): + enum_name = camel_to_upper_snake(fmt.name) + yield f' {enum_name} = {i}\n' + yield '\n\n' + + # Generate checksum function + yield '''def fletcher_checksum(buffer: Union[bytes, List[int]], start: int = 0, end: int = None) -> Tuple[int, int]: + """Calculate Fletcher-16 checksum over the given data""" + if end is None: + end = len(buffer) + + byte1 = 0 + byte2 = 0 + + for x in range(start, end): + byte1 = (byte1 + buffer[x]) % 256 + byte2 = (byte2 + byte1) % 256 + + return (byte1, byte2) + + +''' + + # Generate common result class + yield '''@dataclass +class FrameMsgInfo: + """Parse result containing message information""" + valid: bool = False + msg_id: int = 0 + msg_len: int = 0 + msg_data: bytes = b\'\' +''' + + @staticmethod + def generate_format_file(fmt): + """Generate a Python file for a single frame format""" + yield '# Automatically generated frame parser\n' + yield f'# Generated by {version} at {time.asctime()}.\n\n' + yield 'from enum import Enum\n' + yield 'from typing import Callable, List, Union\n' + yield 'from .frame_base import FrameMsgInfo, fletcher_checksum\n\n' + + yield from FrameParserPyGen.generate_format(fmt) + + @staticmethod + def generate_init(formats): + """Generate __init__.py that exports all frame formats""" + yield '# Automatically generated frame parser package\n' + yield f'# Generated by {version} at {time.asctime()}.\n\n' + yield '# Base utilities\n' + yield 'from .frame_base import (\n' + yield ' FrameFormatType,\n' + yield ' FrameMsgInfo,\n' + yield ' fletcher_checksum,\n' + yield ')\n\n' + + yield '# Individual frame format parsers\n' + for fmt in formats: + snake_name = camel_to_snake(fmt.name) + yield f'from .{snake_name} import {fmt.name}, {fmt.name}ParserState\n' + + yield '\n# Re-export all frame formats\n' + yield '__all__ = [\n' + yield ' # Base utilities\n' + yield ' "FrameFormatType",\n' + yield ' "FrameMsgInfo",\n' + yield ' "fletcher_checksum",\n' + yield ' # Frame formats\n' + for fmt in formats: + yield f' "{fmt.name}",\n' + yield f' "{fmt.name}ParserState",\n' + yield ']\n' + @staticmethod def generate(formats): - """Generate the complete frame parser Python file""" + """Generate the complete frame parser Python file (single file, legacy mode)""" yield '# Automatically generated frame parser\n' yield f'# Generated by {version} at {time.asctime()}.\n\n' yield 'from enum import Enum\n' @@ -368,3 +453,28 @@ def generate_format(fmt): def generate_py_frame_parsers(formats): """Generate Python frame parser code from frame format definitions""" return ''.join(FrameParserPyGen.generate(formats)) + + +def generate_py_frame_parsers_multi(formats): + """ + Generate multiple Python files for frame parsers. + + Returns a dictionary mapping filename to content: + - frame_base.py: Base utilities (checksum, FrameMsgInfo, FrameFormatType) + - {snake_name}.py: Individual frame format files + - __init__.py: Package init that exports all frame formats + """ + files = {} + + # Generate base file + files['frame_base.py'] = ''.join(FrameParserPyGen.generate_base(formats)) + + # Generate individual frame format files + for fmt in formats: + snake_name = camel_to_snake(fmt.name) + files[f'{snake_name}.py'] = ''.join(FrameParserPyGen.generate_format_file(fmt)) + + # Generate __init__.py + files['__init__.py'] = ''.join(FrameParserPyGen.generate_init(formats)) + + return files diff --git a/src/struct_frame/frame_parser_ts_gen.py b/src/struct_frame/frame_parser_ts_gen.py index 573c27eb..83e7d7b4 100644 --- a/src/struct_frame/frame_parser_ts_gen.py +++ b/src/struct_frame/frame_parser_ts_gen.py @@ -26,10 +26,90 @@ def camel_to_upper_snake(name): class FrameParserTsGen: """Generates TypeScript code for frame parsers""" - + + @staticmethod + def generate_base(formats): + """Generate the base TypeScript file with common utilities""" + yield '// Automatically generated frame parser base utilities\n' + yield f'// Generated by {version} at {time.asctime()}.\n\n' + + # Generate frame format enum + yield '// Frame format type enumeration\n' + yield 'export enum FrameFormatType {\n' + for i, fmt in enumerate(formats): + enum_name = camel_to_upper_snake(fmt.name) + yield f' {enum_name} = {i},\n' + yield '}\n\n' + + # Generate checksum function + yield '''// Fletcher-16 checksum calculation +export function fletcher_checksum(buffer: Uint8Array | number[], start: number = 0, end?: number): [number, number] { + if (end === undefined) { + end = buffer.length; + } + + let byte1 = 0; + let byte2 = 0; + + for (let i = start; i < end; i++) { + byte1 = (byte1 + buffer[i]) % 256; + byte2 = (byte2 + byte1) % 256; + } + + return [byte1, byte2]; +} + +''' + + # Generate common result interface + yield '''// Parse result interface +export interface FrameMsgInfo { + valid: boolean; + msg_id: number; + msg_len: number; + msg_data: Uint8Array; +} + +// Create default FrameMsgInfo +export function createFrameMsgInfo(): FrameMsgInfo { + return { + valid: false, + msg_id: 0, + msg_len: 0, + msg_data: new Uint8Array(0) + }; +} +''' + + @staticmethod + def generate_format_file(fmt): + """Generate a TypeScript file for a single frame format""" + yield '// Automatically generated frame parser\n' + yield f'// Generated by {version} at {time.asctime()}.\n\n' + yield 'import { FrameMsgInfo, createFrameMsgInfo, fletcher_checksum } from \'./frame_base\';\n\n' + + yield from FrameParserTsGen.generate_format(fmt) + + @staticmethod + def generate_index(formats): + """Generate index.ts that exports all frame formats""" + yield '// Automatically generated frame parser package\n' + yield f'// Generated by {version} at {time.asctime()}.\n\n' + yield '// Base utilities\n' + yield 'export {\n' + yield ' FrameFormatType,\n' + yield ' FrameMsgInfo,\n' + yield ' createFrameMsgInfo,\n' + yield ' fletcher_checksum,\n' + yield '} from \'./frame_base\';\n\n' + + yield '// Individual frame format parsers\n' + for fmt in formats: + yield f'export {{ {fmt.name}, {fmt.name}ParserState }} from \'./{fmt.name}\';\n' + @staticmethod def generate(formats): - """Generate the complete frame parser TypeScript file""" + """Generate the complete frame parser TypeScript file (single file, legacy mode)""" yield '// Automatically generated frame parser\n' yield f'// Generated by {version} at {time.asctime()}.\n\n' @@ -397,12 +477,120 @@ def generate_ts_frame_parsers(formats): return ''.join(FrameParserTsGen.generate(formats)) +def generate_ts_frame_parsers_multi(formats): + """ + Generate multiple TypeScript files for frame parsers. + + Returns a dictionary mapping filename to content: + - frame_base.ts: Base utilities (checksum, FrameMsgInfo, FrameFormatType) + - {ClassName}.ts: Individual frame format files + - index.ts: Package index that exports all frame formats + """ + files = {} + + # Generate base file + files['frame_base.ts'] = ''.join(FrameParserTsGen.generate_base(formats)) + + # Generate individual frame format files + for fmt in formats: + files[f'{fmt.name}.ts'] = ''.join(FrameParserTsGen.generate_format_file(fmt)) + + # Generate index.ts + files['index.ts'] = ''.join(FrameParserTsGen.generate_index(formats)) + + return files + + class FrameParserJsGen: """Generates JavaScript code for frame parsers (no TypeScript annotations)""" - + + @staticmethod + def generate_base(formats): + """Generate the base JavaScript file with common utilities""" + yield '// Automatically generated frame parser base utilities\n' + yield f'// Generated by {version} at {time.asctime()}.\n\n' + + # Generate frame format enum as object + yield '// Frame format type enumeration\n' + yield 'const FrameFormatType = {\n' + for i, fmt in enumerate(formats): + enum_name = camel_to_upper_snake(fmt.name) + yield f' {enum_name}: {i},\n' + yield '};\n\n' + + # Generate checksum function + yield '''// Fletcher-16 checksum calculation +function fletcher_checksum(buffer, start = 0, end = undefined) { + if (end === undefined) { + end = buffer.length; + } + + let byte1 = 0; + let byte2 = 0; + + for (let i = start; i < end; i++) { + byte1 = (byte1 + buffer[i]) % 256; + byte2 = (byte2 + byte1) % 256; + } + + return [byte1, byte2]; +} + +// Create default FrameMsgInfo +function createFrameMsgInfo() { + return { + valid: false, + msg_id: 0, + msg_len: 0, + msg_data: new Uint8Array(0) + }; +} + +module.exports = { + FrameFormatType, + fletcher_checksum, + createFrameMsgInfo, +}; +''' + + @staticmethod + def generate_format_file(fmt): + """Generate a JavaScript file for a single frame format""" + yield '// Automatically generated frame parser\n' + yield f'// Generated by {version} at {time.asctime()}.\n\n' + yield 'const { createFrameMsgInfo, fletcher_checksum } = require(\'./frame_base\');\n\n' + + yield from FrameParserJsGen.generate_format(fmt) + + yield '\nmodule.exports = {\n' + yield f' {fmt.name},\n' + yield f' {fmt.name}ParserState,\n' + yield '};\n' + + @staticmethod + def generate_index(formats): + """Generate index.js that exports all frame formats""" + yield '// Automatically generated frame parser package\n' + yield f'// Generated by {version} at {time.asctime()}.\n\n' + yield '// Base utilities\n' + yield 'const frameBase = require(\'./frame_base\');\n\n' + + yield '// Individual frame format parsers\n' + for fmt in formats: + yield f'const {camel_to_snake(fmt.name)} = require(\'./{fmt.name}\');\n' + + yield '\nmodule.exports = {\n' + yield ' // Base utilities\n' + yield ' ...frameBase,\n' + yield ' // Frame formats\n' + for fmt in formats: + snake_name = camel_to_snake(fmt.name) + yield f' ...{snake_name},\n' + yield '};\n' + @staticmethod def generate(formats): - """Generate the complete frame parser JavaScript file""" + """Generate the complete frame parser JavaScript file (single file, legacy mode)""" yield '// Automatically generated frame parser\n' yield f'// Generated by {version} at {time.asctime()}.\n\n' @@ -719,3 +907,27 @@ def generate_format(fmt): def generate_js_frame_parsers(formats): """Generate JavaScript frame parser code from frame format definitions""" return ''.join(FrameParserJsGen.generate(formats)) + + +def generate_js_frame_parsers_multi(formats): + """ + Generate multiple JavaScript files for frame parsers. + + Returns a dictionary mapping filename to content: + - frame_base.js: Base utilities (checksum, FrameMsgInfo, FrameFormatType) + - {ClassName}.js: Individual frame format files + - index.js: Package index that exports all frame formats + """ + files = {} + + # Generate base file + files['frame_base.js'] = ''.join(FrameParserJsGen.generate_base(formats)) + + # Generate individual frame format files + for fmt in formats: + files[f'{fmt.name}.js'] = ''.join(FrameParserJsGen.generate_format_file(fmt)) + + # Generate index.js + files['index.js'] = ''.join(FrameParserJsGen.generate_index(formats)) + + return files diff --git a/src/struct_frame/generate.py b/src/struct_frame/generate.py index 3991e47c..111dd93a 100644 --- a/src/struct_frame/generate.py +++ b/src/struct_frame/generate.py @@ -729,25 +729,16 @@ def main(): # When --frame_formats is provided, the frame parser boilerplate files are # replaced by the generated frame parsers, so we only copy utility files. - # Otherwise, copy only essential boilerplate files. - - # Files to copy for each language (frame_parsers_gen files are always copied) - # TypeScript/JavaScript need struct_base and struct_frame utilities - essential_files = { - 'c': ['frame_parsers_gen.h'], - 'cpp': ['frame_parsers_gen.hpp'], - 'ts': ['frame_parsers_gen.ts', 'struct_base.ts', 'struct_frame.ts', 'struct_frame_types.ts'], - 'js': ['frame_parsers_gen.js', 'struct_base.js', 'struct_frame.js', 'struct_frame_types.js'], - 'py': ['frame_parsers_gen.py', '__init__.py'] - } + # Otherwise, copy all boilerplate files (now multi-file structure). # Utility files that should be copied even when generating custom frame parsers + # (files that are not frame format specific) utility_files = { - 'c': [], - 'cpp': [], - 'ts': ['struct_base.ts', 'struct_frame.ts', 'struct_frame_types.ts'], - 'js': ['struct_base.js', 'struct_frame.js', 'struct_frame_types.js'], - 'py': ['__init__.py'] + 'c': ['frame_base.h'], + 'cpp': ['frame_base.hpp'], + 'ts': ['struct_base.ts', 'struct_frame.ts', 'struct_frame_types.ts', 'frame_base.ts'], + 'js': ['struct_base.js', 'struct_frame.js', 'struct_frame_types.js', 'frame_base.js'], + 'py': [] # __init__.py will be generated with the custom frame formats } def copy_files_list(src_dir, dst_dir, files_to_copy): @@ -760,6 +751,17 @@ def copy_files_list(src_dir, dst_dir, files_to_copy): if os.path.isfile(src_path): shutil.copy2(src_path, dst_path) + def copy_all_files(src_dir, dst_dir): + """Copy all files from src_dir to dst_dir""" + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + if os.path.exists(src_dir): + for item in os.listdir(src_dir): + src_path = os.path.join(src_dir, item) + dst_path = os.path.join(dst_dir, item) + if os.path.isfile(src_path): + shutil.copy2(src_path, dst_path) + if args.frame_formats: # When generating custom frame parsers, only copy utility files # (the generated frame parsers will be written separately) @@ -788,31 +790,31 @@ def copy_files_list(src_dir, dst_dir, files_to_copy): os.path.join(dir_path, "boilerplate/cpp"), args.cpp_path[0], utility_files['cpp']) else: - # Copy essential boilerplate files (default behavior) + # Copy all boilerplate files (multi-file structure) if (args.build_c): - copy_files_list( + copy_all_files( os.path.join(dir_path, "boilerplate/c"), - args.c_path[0], essential_files['c']) + args.c_path[0]) if (args.build_ts): - copy_files_list( + copy_all_files( os.path.join(dir_path, "boilerplate/ts"), - args.ts_path[0], essential_files['ts']) + args.ts_path[0]) if (args.build_js): - copy_files_list( + copy_all_files( os.path.join(dir_path, "boilerplate/js"), - args.js_path[0], essential_files['js']) + args.js_path[0]) if (args.build_py): - copy_files_list( + copy_all_files( os.path.join(dir_path, "boilerplate/py"), - args.py_path[0], essential_files['py']) + args.py_path[0]) if (args.build_cpp): - copy_files_list( + copy_all_files( os.path.join(dir_path, "boilerplate/cpp"), - args.cpp_path[0], essential_files['cpp']) + args.cpp_path[0]) # No boilerplate for GraphQL currently diff --git a/src/struct_frame/generate_boilerplate.py b/src/struct_frame/generate_boilerplate.py index dfb117a2..15e3c3c4 100644 --- a/src/struct_frame/generate_boilerplate.py +++ b/src/struct_frame/generate_boilerplate.py @@ -32,10 +32,11 @@ sys.path.insert(0, parent_dir) from struct_frame.frame_format import parse_frame_formats -from struct_frame.frame_parser_c_gen import generate_c_frame_parsers -from struct_frame.frame_parser_py_gen import generate_py_frame_parsers -from struct_frame.frame_parser_ts_gen import generate_ts_frame_parsers, generate_js_frame_parsers -from struct_frame.frame_parser_cpp_gen import generate_cpp_frame_parsers +from struct_frame.frame_parser_c_gen import generate_c_frame_parsers, generate_c_frame_parsers_multi +from struct_frame.frame_parser_py_gen import generate_py_frame_parsers, generate_py_frame_parsers_multi +from struct_frame.frame_parser_ts_gen import (generate_ts_frame_parsers, generate_js_frame_parsers, + generate_ts_frame_parsers_multi, generate_js_frame_parsers_multi) +from struct_frame.frame_parser_cpp_gen import generate_cpp_frame_parsers, generate_cpp_frame_parsers_multi def get_default_frame_formats_path(): @@ -61,7 +62,8 @@ def write_file(path, content): def generate_boilerplate_to_paths(frame_formats_file, c_path=None, ts_path=None, - js_path=None, py_path=None, cpp_path=None): + js_path=None, py_path=None, cpp_path=None, + multi_file=True): """ Generate frame parser boilerplate code from a frame_formats.proto file. @@ -72,6 +74,7 @@ def generate_boilerplate_to_paths(frame_formats_file, c_path=None, ts_path=None, js_path: Output directory for JavaScript code (if None, skip JS generation) py_path: Output directory for Python code (if None, skip Python generation) cpp_path: Output directory for C++ code (if None, skip C++ generation) + multi_file: If True, generate multiple files per language (default: True) Returns: dict: Dictionary mapping output paths to generated content @@ -80,24 +83,49 @@ def generate_boilerplate_to_paths(frame_formats_file, c_path=None, ts_path=None, files = {} if c_path: - name = os.path.join(c_path, "frame_parsers_gen.h") - files[name] = generate_c_frame_parsers(formats) + if multi_file: + c_files = generate_c_frame_parsers_multi(formats) + for filename, content in c_files.items(): + files[os.path.join(c_path, filename)] = content + else: + name = os.path.join(c_path, "frame_parsers_gen.h") + files[name] = generate_c_frame_parsers(formats) if ts_path: - name = os.path.join(ts_path, "frame_parsers_gen.ts") - files[name] = generate_ts_frame_parsers(formats) + if multi_file: + ts_files = generate_ts_frame_parsers_multi(formats) + for filename, content in ts_files.items(): + files[os.path.join(ts_path, filename)] = content + else: + name = os.path.join(ts_path, "frame_parsers_gen.ts") + files[name] = generate_ts_frame_parsers(formats) if js_path: - name = os.path.join(js_path, "frame_parsers_gen.js") - files[name] = generate_js_frame_parsers(formats) + if multi_file: + js_files = generate_js_frame_parsers_multi(formats) + for filename, content in js_files.items(): + files[os.path.join(js_path, filename)] = content + else: + name = os.path.join(js_path, "frame_parsers_gen.js") + files[name] = generate_js_frame_parsers(formats) if py_path: - name = os.path.join(py_path, "frame_parsers_gen.py") - files[name] = generate_py_frame_parsers(formats) + if multi_file: + py_files = generate_py_frame_parsers_multi(formats) + for filename, content in py_files.items(): + files[os.path.join(py_path, filename)] = content + else: + name = os.path.join(py_path, "frame_parsers_gen.py") + files[name] = generate_py_frame_parsers(formats) if cpp_path: - name = os.path.join(cpp_path, "frame_parsers_gen.hpp") - files[name] = generate_cpp_frame_parsers(formats) + if multi_file: + cpp_files = generate_cpp_frame_parsers_multi(formats) + for filename, content in cpp_files.items(): + files[os.path.join(cpp_path, filename)] = content + else: + name = os.path.join(cpp_path, "frame_parsers_gen.hpp") + files[name] = generate_cpp_frame_parsers(formats) return files diff --git a/tests/c/test_arrays.c b/tests/c/test_arrays.c index 308a3e10..68293c96 100644 --- a/tests/c/test_arrays.c +++ b/tests/c/test_arrays.c @@ -3,7 +3,7 @@ #include #include "comprehensive_arrays.sf.h" -#include "frame_parsers_gen.h" +#include "frame_parsers.h" void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { printf("\n"); diff --git a/tests/c/test_basic_types.c b/tests/c/test_basic_types.c index 4a8f00c8..620845f2 100644 --- a/tests/c/test_basic_types.c +++ b/tests/c/test_basic_types.c @@ -3,7 +3,7 @@ #include #include "basic_types.sf.h" -#include "frame_parsers_gen.h" +#include "frame_parsers.h" void print_failure_details(const char* label, const BasicTypesBasicTypesMessage* expected, const BasicTypesBasicTypesMessage* actual, diff --git a/tests/c/test_cross_platform_deserialization.c b/tests/c/test_cross_platform_deserialization.c index 0add2ff4..dbc30d3f 100644 --- a/tests/c/test_cross_platform_deserialization.c +++ b/tests/c/test_cross_platform_deserialization.c @@ -4,7 +4,7 @@ #include #include "serialization_test.sf.h" -#include "frame_parsers_gen.h" +#include "frame_parsers.h" void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { printf("\n"); diff --git a/tests/c/test_cross_platform_serialization.c b/tests/c/test_cross_platform_serialization.c index 2dd26e76..dcdf2ffd 100644 --- a/tests/c/test_cross_platform_serialization.c +++ b/tests/c/test_cross_platform_serialization.c @@ -3,7 +3,7 @@ #include #include "serialization_test.sf.h" -#include "frame_parsers_gen.h" +#include "frame_parsers.h" void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { printf("\n"); diff --git a/tests/cpp/test_arrays.cpp b/tests/cpp/test_arrays.cpp index 6d45e091..e6e1cbf9 100644 --- a/tests/cpp/test_arrays.cpp +++ b/tests/cpp/test_arrays.cpp @@ -1,5 +1,5 @@ #include "comprehensive_arrays.sf.hpp" -#include "frame_parsers_gen.hpp" +#include "frame_parsers.hpp" #include #include diff --git a/tests/cpp/test_basic_types.cpp b/tests/cpp/test_basic_types.cpp index 338c5ca7..252ff2d7 100644 --- a/tests/cpp/test_basic_types.cpp +++ b/tests/cpp/test_basic_types.cpp @@ -1,5 +1,5 @@ #include "basic_types.sf.hpp" -#include "frame_parsers_gen.hpp" +#include "frame_parsers.hpp" #include #include diff --git a/tests/cpp/test_cross_platform_deserialization.cpp b/tests/cpp/test_cross_platform_deserialization.cpp index 98b18874..160c43a2 100644 --- a/tests/cpp/test_cross_platform_deserialization.cpp +++ b/tests/cpp/test_cross_platform_deserialization.cpp @@ -4,7 +4,7 @@ #include #include "serialization_test.sf.hpp" -#include "frame_parsers_gen.hpp" +#include "frame_parsers.hpp" void print_failure_details(const char* label) { std::cout << "\n============================================================\n"; diff --git a/tests/cpp/test_cross_platform_serialization.cpp b/tests/cpp/test_cross_platform_serialization.cpp index fa407aed..9d142b72 100644 --- a/tests/cpp/test_cross_platform_serialization.cpp +++ b/tests/cpp/test_cross_platform_serialization.cpp @@ -1,5 +1,5 @@ #include "serialization_test.sf.hpp" -#include "frame_parsers_gen.hpp" +#include "frame_parsers.hpp" #include #include #include