diff --git a/src/struct_frame/boilerplate/c/basic_frame.h b/src/struct_frame/boilerplate/c/basic_frame.h deleted file mode 100644 index 20a2c365..00000000 --- a/src/struct_frame/boilerplate/c/basic_frame.h +++ /dev/null @@ -1,406 +0,0 @@ -/* - * BasicFrame - Simple frame format with CRC - * - * Format: [START1=0x90] [START2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - * - * This frame format requires a message ID to message length lookup function - * since the length is not included in the packet. - * - * Use Case: When all message lengths are known at compile time and bandwidth - * efficiency is important. - */ - -#pragma once - -#include -#include -#include -#include - -/* Frame constants */ -#define BASIC_FRAME_START_BYTE1 0x90 -#define BASIC_FRAME_START_BYTE2 0x91 -#define BASIC_FRAME_HEADER_SIZE 3 /* start1 + start2 + msg_id */ -#define BASIC_FRAME_FOOTER_SIZE 2 /* crc1 + crc2 */ -#define BASIC_FRAME_OVERHEAD (BASIC_FRAME_HEADER_SIZE + BASIC_FRAME_FOOTER_SIZE) - -/* Checksum result */ -typedef struct basic_frame_checksum { - uint8_t byte1; - uint8_t byte2; -} basic_frame_checksum_t; - -/* Parse result */ -typedef struct basic_frame_msg_info { - bool valid; - uint8_t msg_id; - uint8_t msg_len; - uint8_t* msg_data; -} basic_frame_msg_info_t; - -/* Parser state enumeration */ -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; - -/* 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 */ - bool (*get_msg_length)(uint8_t msg_id, size_t* length); -} basic_frame_parser_t; - -/* 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; /* Stored for finish() */ -} basic_frame_encode_buffer_t; - -/*=========================================================================== - * Checksum Calculation - *===========================================================================*/ - -/** - * Calculate Fletcher-16 checksum over the given data - */ -static inline basic_frame_checksum_t basic_frame_checksum(const uint8_t* data, size_t length) { - basic_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; -} - -/*=========================================================================== - * Encoding Functions - *===========================================================================*/ - -/** - * Initialize an encode buffer - */ -static inline void basic_frame_encode_init(basic_frame_encode_buffer_t* buf, uint8_t* data, size_t max_size) { - buf->data = data; - buf->max_size = max_size; - buf->size = 0; - buf->in_progress = false; - buf->reserved_msg_size = 0; -} - -/** - * Reset the encode buffer - */ -static inline void basic_frame_encode_reset(basic_frame_encode_buffer_t* buf) { - buf->size = 0; - buf->in_progress = false; - buf->reserved_msg_size = 0; -} - -/** - * Encode a message into the buffer - * 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; - } - - /* Write header */ - 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 over msg_id + msg data */ - basic_frame_checksum_t ck = basic_frame_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; -} - -/** - * Encode a message using the encode buffer structure - */ -static inline bool basic_frame_encode_msg(basic_frame_encode_buffer_t* buf, - uint8_t msg_id, const void* msg, size_t msg_size) { - if (buf->in_progress) { - return false; - } - - size_t written = basic_frame_encode(buf->data + buf->size, - buf->max_size - buf->size, - msg_id, (const uint8_t*)msg, msg_size); - if (written == 0) { - return false; - } - - buf->size += written; - return true; -} - -/** - * Reserve space in buffer for zero-copy encoding - * Returns pointer to message data area, or NULL on failure - */ -static inline uint8_t* basic_frame_encode_reserve(basic_frame_encode_buffer_t* buf, - uint8_t msg_id, size_t msg_size) { - if (buf->in_progress) { - return NULL; - } - - size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; - if (buf->size + total_size > buf->max_size) { - return NULL; - } - - uint8_t* packet_start = buf->data + buf->size; - - /* Write header */ - packet_start[0] = BASIC_FRAME_START_BYTE1; - packet_start[1] = BASIC_FRAME_START_BYTE2; - packet_start[2] = msg_id; - - buf->in_progress = true; - buf->reserved_msg_size = msg_size; - return packet_start + BASIC_FRAME_HEADER_SIZE; -} - -/** - * Finish a reserved encoding by adding checksum - */ -static inline bool basic_frame_encode_finish(basic_frame_encode_buffer_t* buf) { - if (!buf->in_progress) { - return false; - } - - uint8_t* packet_start = buf->data + buf->size; - size_t msg_size = buf->reserved_msg_size; - - /* Calculate checksum over msg_id + msg data */ - basic_frame_checksum_t ck = basic_frame_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; - - buf->size += BASIC_FRAME_OVERHEAD + msg_size; - buf->in_progress = false; - return true; -} - -/*=========================================================================== - * Decoding/Parsing Functions - *===========================================================================*/ - -/** - * Initialize a parser - * - * @param parser Parser structure to initialize - * @param buffer Buffer for storing incoming packet data - * @param buffer_size Maximum size of the buffer - * @param get_msg_length User-provided function to map msg_id to msg_length - */ -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 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 - * Returns a msg_info with valid=true when a complete valid message is received - */ -static inline basic_frame_msg_info_t basic_frame_parse_byte(basic_frame_parser_t* parser, uint8_t byte) { - basic_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) { - /* Could be new packet starting */ - parser->buffer[0] = byte; - parser->buffer_index = 1; - } else { - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_GETTING_MSG_ID: - parser->buffer[2] = byte; - parser->buffer_index = 3; - parser->msg_id = byte; - - /* Get message length from user-provided function */ - 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 { - /* Packet too large for buffer */ - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - } else { - /* Unknown message ID */ - 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) { - /* Packet complete, validate checksum */ - size_t msg_length = parser->packet_size - BASIC_FRAME_OVERHEAD; - basic_frame_checksum_t ck = basic_frame_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 = (uint8_t)msg_length; - result.msg_data = parser->buffer + BASIC_FRAME_HEADER_SIZE; - } - - parser->state = BASIC_FRAME_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Parse a buffer of bytes - * Continues parsing from r_loc and returns when a message is found or buffer is exhausted - * Updates r_loc to the position after the found message - * Returns msg_info with valid=true when a complete valid message is found - */ -static inline basic_frame_msg_info_t basic_frame_parse_buffer(basic_frame_parser_t* parser, - const uint8_t* data, size_t data_size, - size_t* r_loc) { - basic_frame_msg_info_t result = {false, 0, 0, NULL}; - - while (*r_loc < data_size) { - result = basic_frame_parse_byte(parser, data[*r_loc]); - (*r_loc)++; - if (result.valid) { - return result; - } - } - - return result; -} - -/** - * Validate a complete packet in a buffer - * Useful for validating data received all at once - */ -static inline basic_frame_msg_info_t basic_frame_validate_packet(const uint8_t* buffer, size_t length) { - basic_frame_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_OVERHEAD) { - return result; - } - - /* Check start bytes */ - if (buffer[0] != BASIC_FRAME_START_BYTE1 || buffer[1] != BASIC_FRAME_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_OVERHEAD; - - /* Validate checksum */ - basic_frame_checksum_t ck = basic_frame_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 = (uint8_t)msg_length; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_HEADER_SIZE); - } - - return result; -} - -/*=========================================================================== - * Helper Macros for Message Types - *===========================================================================*/ - -/** - * Generate helper functions for a specific message type - * - * Usage: BASIC_FRAME_MESSAGE_HELPERS(my_message, MyMessage, 10, 1) - * - * This creates: - * - my_message_encode(buf, msg) - Encode message to buffer - * - my_message_reserve(buf, &msg_ptr) - Reserve space for zero-copy - * - my_message_finish(buf) - Finish reserved encoding - * - my_message_get(info) - Get message copy from parse result - * - my_message_get_ref(info) - Get message pointer from parse result - */ -#define BASIC_FRAME_MESSAGE_HELPERS(funcname, typename, msg_size, msg_id) \ - static inline bool funcname##_encode(basic_frame_encode_buffer_t* buf, const typename* msg) { \ - return basic_frame_encode_msg(buf, (msg_id), msg, (msg_size)); \ - } \ - static inline bool funcname##_reserve(basic_frame_encode_buffer_t* buf, typename** msg) { \ - uint8_t* ptr = basic_frame_encode_reserve(buf, (msg_id), (msg_size)); \ - if (ptr) { \ - *msg = (typename*)ptr; \ - return true; \ - } \ - return false; \ - } \ - static inline bool funcname##_finish(basic_frame_encode_buffer_t* buf) { \ - return basic_frame_encode_finish(buf); \ - } \ - static inline typename funcname##_get(basic_frame_msg_info_t info) { \ - return *(typename*)(info.msg_data); \ - } \ - static inline typename* funcname##_get_ref(basic_frame_msg_info_t info) { \ - return (typename*)(info.msg_data); \ - } diff --git a/src/struct_frame/boilerplate/c/basic_frame_with_len.h b/src/struct_frame/boilerplate/c/basic_frame_with_len.h deleted file mode 100644 index c9024498..00000000 --- a/src/struct_frame/boilerplate/c/basic_frame_with_len.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * BasicFrameWithLen - Frame format with embedded length and CRC - * - * Format: [START1=0x90] [START2=0x92] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - * - * This frame format includes the message length in the packet header, - * so no msg_id to length lookup is required. - * - * Use Case: When message lengths may vary or are not known at compile time. - */ - -#pragma once - -#include -#include -#include -#include - -/* Frame 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 /* start1 + start2 + msg_id + len */ -#define BASIC_FRAME_WITH_LEN_FOOTER_SIZE 2 /* crc1 + crc2 */ -#define BASIC_FRAME_WITH_LEN_OVERHEAD (BASIC_FRAME_WITH_LEN_HEADER_SIZE + BASIC_FRAME_WITH_LEN_FOOTER_SIZE) -#define BASIC_FRAME_WITH_LEN_MAX_MSG_SIZE 255 /* Limited by 1-byte length field */ - -/* Checksum result */ -typedef struct basic_frame_with_len_checksum { - uint8_t byte1; - uint8_t byte2; -} basic_frame_with_len_checksum_t; - -/* Parse result */ -typedef struct basic_frame_with_len_msg_info { - bool valid; - uint8_t msg_id; - uint8_t msg_len; - uint8_t* msg_data; -} basic_frame_with_len_msg_info_t; - -/* Parser state enumeration */ -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; - -/* 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; - uint8_t msg_len; -} basic_frame_with_len_parser_t; - -/* Encode buffer structure */ -typedef struct basic_frame_with_len_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; - uint8_t reserved_msg_size; /* Stored for finish() */ -} basic_frame_with_len_encode_buffer_t; - -/*=========================================================================== - * Checksum Calculation - *===========================================================================*/ - -/** - * Calculate Fletcher-16 checksum over the given data - */ -static inline basic_frame_with_len_checksum_t basic_frame_with_len_checksum(const uint8_t* data, size_t length) { - basic_frame_with_len_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; -} - -/*=========================================================================== - * Encoding Functions - *===========================================================================*/ - -/** - * Initialize an encode buffer - */ -static inline void basic_frame_with_len_encode_init(basic_frame_with_len_encode_buffer_t* buf, - uint8_t* data, size_t max_size) { - buf->data = data; - buf->max_size = max_size; - buf->size = 0; - buf->in_progress = false; - buf->reserved_msg_size = 0; -} - -/** - * Reset the encode buffer - */ -static inline void basic_frame_with_len_encode_reset(basic_frame_with_len_encode_buffer_t* buf) { - buf->size = 0; - buf->in_progress = false; - buf->reserved_msg_size = 0; -} - -/** - * Encode a message into the buffer - * 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, uint8_t msg_size) { - size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buffer_size < total_size) { - return 0; - } - - /* Write header */ - buffer[0] = BASIC_FRAME_WITH_LEN_START_BYTE1; - buffer[1] = BASIC_FRAME_WITH_LEN_START_BYTE2; - buffer[2] = msg_id; - buffer[3] = msg_size; - - /* Write message data */ - if (msg_size > 0 && msg != NULL) { - memcpy(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - /* Calculate checksum over msg_id + len + msg data */ - basic_frame_with_len_checksum_t ck = basic_frame_with_len_checksum(buffer + 2, msg_size + 2); - 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; -} - -/** - * Encode a message using the encode buffer structure - */ -static inline bool basic_frame_with_len_encode_msg(basic_frame_with_len_encode_buffer_t* buf, - uint8_t msg_id, const void* msg, uint8_t msg_size) { - if (buf->in_progress) { - return false; - } - - size_t written = basic_frame_with_len_encode(buf->data + buf->size, - buf->max_size - buf->size, - msg_id, (const uint8_t*)msg, msg_size); - if (written == 0) { - return false; - } - - buf->size += written; - return true; -} - -/** - * Reserve space in buffer for zero-copy encoding - * Returns pointer to message data area, or NULL on failure - */ -static inline uint8_t* basic_frame_with_len_encode_reserve(basic_frame_with_len_encode_buffer_t* buf, - uint8_t msg_id, uint8_t msg_size) { - if (buf->in_progress) { - return NULL; - } - - size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (buf->size + total_size > buf->max_size) { - return NULL; - } - - uint8_t* packet_start = buf->data + buf->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] = msg_size; - - buf->in_progress = true; - buf->reserved_msg_size = msg_size; - return packet_start + BASIC_FRAME_WITH_LEN_HEADER_SIZE; -} - -/** - * Finish a reserved encoding by adding checksum - */ -static inline bool basic_frame_with_len_encode_finish(basic_frame_with_len_encode_buffer_t* buf) { - if (!buf->in_progress) { - return false; - } - - uint8_t* packet_start = buf->data + buf->size; - uint8_t msg_size = buf->reserved_msg_size; - - /* Calculate checksum over msg_id + len + msg data */ - basic_frame_with_len_checksum_t ck = basic_frame_with_len_checksum(packet_start + 2, msg_size + 2); - 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; - - buf->size += BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - buf->in_progress = false; - return true; -} - -/*=========================================================================== - * Decoding/Parsing Functions - *===========================================================================*/ - -/** - * Initialize a parser - * - * @param parser Parser structure to initialize - * @param buffer Buffer for storing incoming packet data - * @param buffer_size Maximum size of the buffer - */ -static inline void basic_frame_with_len_parser_init(basic_frame_with_len_parser_t* parser, - uint8_t* buffer, size_t buffer_size) { - 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_len = 0; -} - -/** - * Reset 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_len = 0; -} - -/** - * Parse a single byte - * Returns a msg_info with valid=true when a complete valid message is received - */ -static inline basic_frame_with_len_msg_info_t basic_frame_with_len_parse_byte( - basic_frame_with_len_parser_t* parser, uint8_t byte) { - - basic_frame_with_len_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) { - /* Could be new packet starting */ - parser->buffer[0] = byte; - parser->buffer_index = 1; - } else { - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - } - break; - - case BASIC_FRAME_WITH_LEN_GETTING_MSG_ID: - parser->buffer[2] = byte; - parser->buffer_index = 3; - parser->msg_id = byte; - parser->state = BASIC_FRAME_WITH_LEN_GETTING_LENGTH; - break; - - case BASIC_FRAME_WITH_LEN_GETTING_LENGTH: - parser->buffer[3] = byte; - parser->buffer_index = 4; - parser->msg_len = byte; - parser->packet_size = BASIC_FRAME_WITH_LEN_OVERHEAD + byte; - - if (parser->packet_size <= parser->buffer_max_size) { - parser->state = BASIC_FRAME_WITH_LEN_GETTING_PAYLOAD; - } else { - /* Packet too large for buffer */ - 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) { - /* Packet complete, validate checksum */ - basic_frame_with_len_checksum_t ck = basic_frame_with_len_checksum( - parser->buffer + 2, parser->msg_len + 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 = parser->msg_len; - result.msg_data = parser->buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE; - } - - parser->state = BASIC_FRAME_WITH_LEN_LOOKING_FOR_START1; - } - break; - } - - return result; -} - -/** - * Parse a buffer of bytes - * Continues parsing from r_loc and returns when a message is found or buffer is exhausted - * Updates r_loc to the position after the found message - * Returns msg_info with valid=true when a complete valid message is found - */ -static inline basic_frame_with_len_msg_info_t basic_frame_with_len_parse_buffer( - basic_frame_with_len_parser_t* parser, - const uint8_t* data, size_t data_size, - size_t* r_loc) { - - basic_frame_with_len_msg_info_t result = {false, 0, 0, NULL}; - - while (*r_loc < data_size) { - result = basic_frame_with_len_parse_byte(parser, data[*r_loc]); - (*r_loc)++; - if (result.valid) { - return result; - } - } - - return result; -} - -/** - * Validate a complete packet in a buffer - * Useful for validating data received all at once - */ -static inline basic_frame_with_len_msg_info_t basic_frame_with_len_validate_packet( - const uint8_t* buffer, size_t length) { - - basic_frame_with_len_msg_info_t result = {false, 0, 0, NULL}; - - if (length < BASIC_FRAME_WITH_LEN_OVERHEAD) { - return result; - } - - /* Check start bytes */ - if (buffer[0] != BASIC_FRAME_WITH_LEN_START_BYTE1 || - buffer[1] != BASIC_FRAME_WITH_LEN_START_BYTE2) { - return result; - } - - uint8_t msg_len = buffer[3]; - size_t expected_length = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_len; - - if (length != expected_length) { - return result; - } - - /* Validate checksum over msg_id + len + msg data */ - basic_frame_with_len_checksum_t ck = basic_frame_with_len_checksum(buffer + 2, msg_len + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_len; - result.msg_data = (uint8_t*)(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - -/*=========================================================================== - * Helper Macros for Message Types - *===========================================================================*/ - -/** - * Generate helper functions for a specific message type - * - * Usage: BASIC_FRAME_WITH_LEN_MESSAGE_HELPERS(my_message, MyMessage, 10, 1) - * - * This creates: - * - my_message_encode(buf, msg) - Encode message to buffer - * - my_message_reserve(buf, &msg_ptr) - Reserve space for zero-copy - * - my_message_finish(buf) - Finish reserved encoding - * - my_message_get(info) - Get message copy from parse result - * - my_message_get_ref(info) - Get message pointer from parse result - */ -#define BASIC_FRAME_WITH_LEN_MESSAGE_HELPERS(funcname, typename, msg_size, msg_id) \ - static inline bool funcname##_encode(basic_frame_with_len_encode_buffer_t* buf, const typename* msg) { \ - return basic_frame_with_len_encode_msg(buf, (msg_id), msg, (msg_size)); \ - } \ - static inline bool funcname##_reserve(basic_frame_with_len_encode_buffer_t* buf, typename** msg) { \ - uint8_t* ptr = basic_frame_with_len_encode_reserve(buf, (msg_id), (msg_size)); \ - if (ptr) { \ - *msg = (typename*)ptr; \ - return true; \ - } \ - return false; \ - } \ - static inline bool funcname##_finish(basic_frame_with_len_encode_buffer_t* buf) { \ - return basic_frame_with_len_encode_finish(buf); \ - } \ - static inline typename funcname##_get(basic_frame_with_len_msg_info_t info) { \ - return *(typename*)(info.msg_data); \ - } \ - static inline typename* funcname##_get_ref(basic_frame_with_len_msg_info_t info) { \ - return (typename*)(info.msg_data); \ - } diff --git a/src/struct_frame/boilerplate/c/struct_frame.h b/src/struct_frame/boilerplate/c/struct_frame.h deleted file mode 100644 index 7e55ed16..00000000 --- a/src/struct_frame/boilerplate/c/struct_frame.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -#include "stdbool.h" -#include "stdint.h" -#include "string.h" -#include "struct_frame_types.h" - -static inline struct checksum_t fletcher_checksum_calculation(uint8_t* buffer, uint8_t data_length) { - checksum_t checksum = {0}; - - for (int i = 0; i < data_length; i++) { - checksum.byte1 += buffer[i]; - checksum.byte2 += checksum.byte1; - } - return checksum; -} - -static inline bool msg_encode(msg_encode_buffer* buffer, packet_format_t* format, void* msg, uint8_t msg_id, - uint8_t msg_size) { - if (buffer->in_progress) { - return false; - } - buffer->in_progress = true; - buffer->size += format->encode(buffer->data, msg_id, (uint8_t*)msg, msg_size); - buffer->in_progress = false; - return true; -} - -static inline uint8_t* msg_reserve(msg_encode_buffer* buffer, packet_format_t* format, uint8_t msg_id, - uint8_t msg_size) { - if (buffer->in_progress) { - return NULL; - } - buffer->in_progress = true; - uint8_t* out = format->encode_reserve(buffer->data, msg_id, msg_size); - return out; -} - -static inline bool msg_finish(msg_encode_buffer* buffer, packet_format_t* format, uint8_t msg_size) { - if (buffer->in_progress == false) { - return false; - } - - buffer->size += format->encode_finsish(buffer->data, msg_size); - buffer->in_progress = false; - return true; -} - -#define MESSAGE_HELPER(funcname, name, msg_size, msg_id) \ - static inline bool funcname##_encode(msg_encode_buffer* buffer, packet_format_t* format, name* name##_obj) { \ - return msg_encode(buffer, format, name##_obj, msg_id, msg_size); \ - } \ - static inline bool funcname##_reserve(msg_encode_buffer* buffer, packet_format_t* format, name** msg) { \ - void* ptr = msg_reserve(buffer, format, msg_id, msg_size); \ - if (ptr) { \ - *msg = (name*)ptr; \ - return true; \ - } \ - return false; \ - } \ - static inline bool funcname##_finish(msg_encode_buffer* buffer, packet_format_t* format) { \ - return msg_finish(buffer, format, msg_size); \ - } \ - static inline name funcname##_get_from_buffer(uint8_t* buffer) { \ - name msg = *(name*)(buffer); \ - return msg; \ - } \ - static inline name funcname##_get(msg_info_t result) { \ - name msg = *(name*)(result.msg_loc); \ - return msg; \ - } \ - static inline name* funcname##_get_ref_from_buffer(uint8_t* buffer) { return (name*)(buffer); } \ - static inline name* funcname##_get_ref(msg_info_t result) { return (name*)(result.msg_loc); } diff --git a/src/struct_frame/boilerplate/c/struct_frame_cpp.h b/src/struct_frame/boilerplate/c/struct_frame_cpp.h deleted file mode 100644 index 6436a240..00000000 --- a/src/struct_frame/boilerplate/c/struct_frame_cpp.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "struct_frame_parser.h" -#include "struct_frame_types.h" - -class StructFrameDevice : public msg_encode_buffer { - public: - StructFrameDevice(packet_format_t formats[], packet_definitions_t defines[]) - : msg_encode_buffer{0, 0, 0}, - packet_state_{LOOKING_FOR_START_BYTE, 0, formats, defines, nullptr, 0, 0, 0, false, 0} {} - - void RunRx() { - GetArray(packet_state_.buffer, packet_state_.buffer_size); - if (packet_state_.buffer && packet_state_.buffer_size) { - while (!packet_state_.finished) { - msg_info_t info = parse_buffer(&packet_state_); - if (info.valid) { - HandleResult(info); - } - } - } - } - - void RunTx() { PutArray(msg_encode_buffer::data, msg_encode_buffer::max_size, msg_encode_buffer::size); } - - protected: - void Init() { - size_t dummy = 0; - PutArray(msg_encode_buffer::data, msg_encode_buffer::max_size, dummy); - } - - // Put Array must accept the full buffer of data and returns a pointer to either a new buffer or the same buffer - // that is free - virtual void PutArray(uint8_t *&buffer, size_t &max_length, size_t &length) = 0; - - // Get array, a pointer to an array and refernce to the array length is pased and mutated by this function - virtual void GetArray(uint8_t *&buffer, size_t &length) = 0; - - virtual void HandleResult(msg_info_t info) = 0; - packet_state_t packet_state_; -}; diff --git a/src/struct_frame/boilerplate/c/struct_frame_default_frame.h b/src/struct_frame/boilerplate/c/struct_frame_default_frame.h deleted file mode 100644 index e7a7ab1e..00000000 --- a/src/struct_frame/boilerplate/c/struct_frame_default_frame.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#include "stdint.h" -#include "struct_frame.h" -#include "struct_frame_parser.h" -#include "struct_frame_types.h" - -#define BASIC_FRAME_HEADER_LENGTH 2 -#define BASIC_FRAME_FOOTER_LENGTH 2 - -bool basic_frame_check_start_bytes(uint8_t c) { return c == 0x90; } - -bool basic_frame_process_header_byte(uint8_t c, size_t length) { return length >= BASIC_FRAME_HEADER_LENGTH; } - -size_t basic_frame_get_msg_id(uint8_t* data) { return data[1]; } - -size_t basic_frame_get_full_packet_length(size_t msg_length) { - return msg_length + BASIC_FRAME_HEADER_LENGTH + BASIC_FRAME_FOOTER_LENGTH; -} - -msg_info_t basic_frame_validate_packet(uint8_t* data, size_t packet_length) { - size_t msg_size = packet_length - BASIC_FRAME_HEADER_LENGTH - BASIC_FRAME_FOOTER_LENGTH; - checksum_t ck = fletcher_checksum_calculation(data + 1, msg_size + 1); - - msg_info_t info = {false, (uint8_t)msg_size, data[1], data + 2}; - if (ck.byte1 == data[packet_length - 2] && ck.byte2 == data[packet_length - 1]) { - info.valid = true; - } - return info; -}; - -uint8_t basic_frame_finish(uint8_t* buffer, uint8_t msg_size) { - checksum_t ck = fletcher_checksum_calculation(buffer + 1, msg_size + 1); - - buffer[msg_size + BASIC_FRAME_HEADER_LENGTH] = ck.byte1; - buffer[msg_size + BASIC_FRAME_HEADER_LENGTH + 1] = ck.byte2; - return msg_size + BASIC_FRAME_HEADER_LENGTH + BASIC_FRAME_FOOTER_LENGTH; -} - -size_t basic_frame_encode(uint8_t* buffer, uint8_t msg_id, uint8_t* msg, uint8_t msg_size) { - buffer[0] = 0x90; - buffer[1] = msg_id; - memcpy(buffer + 2, msg, msg_size); - return basic_frame_finish(buffer, msg_size); -} - -uint8_t* basic_frame_reserve(uint8_t* buffer, uint8_t msg_id, uint8_t msg_size) { - buffer[0] = 0x90; - buffer[1] = msg_id; - return buffer + 2; -} - -static packet_format_t default_frame_format = {.check_start_bytes = basic_frame_check_start_bytes, - .process_header_byte = basic_frame_process_header_byte, - .get_msg_id = basic_frame_get_msg_id, - .get_full_packet_length = basic_frame_get_full_packet_length, - .validate_packet = basic_frame_validate_packet, - .encode = basic_frame_encode, - .encode_reserve = basic_frame_reserve, - .encode_finsish = basic_frame_finish}; diff --git a/src/struct_frame/boilerplate/c/struct_frame_gen.h b/src/struct_frame/boilerplate/c/struct_frame_gen.h deleted file mode 100644 index 0f7fea14..00000000 --- a/src/struct_frame/boilerplate/c/struct_frame_gen.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// bool getMessageLength(size_t id, size_t *length) { -// *length = 10; -// return false; -// } -// -// packet_format_t packetFormats[10]; -// -// packet_format_t *getPacketFormat(packet_format_t *formats, size_t formats_length, uint8_t c) { -// for (int i = 0; i++; i < formats_length) { -// if (formats[i].check_start_bytes(c)) { -// return &formats[i]; -// } -// } -// return NULL; -// } diff --git a/src/struct_frame/boilerplate/c/struct_frame_parser.h b/src/struct_frame/boilerplate/c/struct_frame_parser.h deleted file mode 100644 index 2a1adc78..00000000 --- a/src/struct_frame/boilerplate/c/struct_frame_parser.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once -#include "stdint.h" -#include "struct_frame_types.h" - -// https://github.com/serge-sans-paille/frozen - -static inline msg_info_t parse_buffer(packet_state_t *packet_state) { - packet_state->state = LOOKING_FOR_START_BYTE; - packet_state->finished = false; - for (size_t i = packet_state->r_loc; i < packet_state->buffer_size; i++) { - uint8_t c = packet_state->buffer[i]; - switch (packet_state->state) { - case LOOKING_FOR_START_BYTE: - packet_state->format = packet_state->defines->get_packet_formats(c); - if (packet_state->format) { - packet_state->packet_start_index = i; - if (packet_state->format->process_header_byte(c, true)) { - packet_state->state = GETTING_PAYLOAD; - } else { - packet_state->state = GETTING_HEADER; - } - } - break; - - case GETTING_HEADER: - if (packet_state->format->process_header_byte(c, false)) { - size_t msg_id = packet_state->format->get_msg_id(packet_state->buffer + packet_state->packet_start_index); - size_t length = 0; - if (packet_state->defines->get_message_length(msg_id, &length)) { - packet_state->packet_size = packet_state->format->get_full_packet_length(length); - packet_state->state = GETTING_PAYLOAD; - } else { - packet_state->state = LOOKING_FOR_START_BYTE; - } - } - break; - - case GETTING_PAYLOAD: - if ((packet_state->packet_start_index + packet_state->packet_size) > packet_state->buffer_size) { - packet_state->state = LOOKING_FOR_START_BYTE; - msg_info_t info = packet_state->format->validate_packet( - packet_state->buffer + packet_state->packet_start_index, packet_state->packet_size); - packet_state->r_loc += i; - return info; - } else { - packet_state->state = LOOKING_FOR_START_BYTE; - } - - break; - - default: - break; - } - } - packet_state->finished = true; - packet_state->r_loc = 0; - - msg_info_t info = {0, 0, 0, 0}; - return info; -} - -msg_info_t parse_char(packet_state_t *state, const uint8_t c) { - state->buffer[state->buffer_size] = c; - state->buffer_size = (state->buffer_size + 1) % state->buffer_max_size; - - switch (state->state) { - case LOOKING_FOR_START_BYTE:; - state->format = state->defines->get_packet_formats(c); - if (state->format) { - state->buffer[0] = state->buffer[state->buffer_size]; - state->buffer_size = 0; - if (state->format->process_header_byte(c, true)) { - state->state = GETTING_PAYLOAD; - } else { - state->state = GETTING_HEADER; - } - } - break; - - case GETTING_HEADER: - if (state->format->process_header_byte(c, false)) { - size_t msg_id = state->format->get_msg_id(state->buffer); - size_t length = 0; - if (state->defines->get_message_length(msg_id, &length)) { - state->packet_size = state->format->get_full_packet_length(length); - state->state = GETTING_PAYLOAD; - } else { - state->state = LOOKING_FOR_START_BYTE; - } - } - break; - - case GETTING_PAYLOAD: - if (state->buffer_size >= state->packet_size) { - state->state = LOOKING_FOR_START_BYTE; - msg_info_t info = state->format->validate_packet(state->buffer, state->buffer_size); - return info; - } - break; - - default: - break; - } - - msg_info_t info = {0, 0, 0, 0}; - return info; -} diff --git a/src/struct_frame/boilerplate/c/struct_frame_types.h b/src/struct_frame/boilerplate/c/struct_frame_types.h deleted file mode 100644 index e53d4349..00000000 --- a/src/struct_frame/boilerplate/c/struct_frame_types.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include "stdbool.h" -#include "stdint.h" - -// https://github.com/serge-sans-paille/frozen -// https://www.npmjs.com/package/typed-struct - -// #define default_parser {1, 0, 0x90} -// -// #define zero_initialized_parser_result {default_parser, false, 0, 0, false, {0, 0}} -// -// #define CREATE_DEFAULT_STRUCT_BUFFER(name, size) -// uint8_t name##_buffer[size]; -// struct_buffer name = {default_parser, name##_buffer, size, 0, false, 0, LOOKING_FOR_START_BYTE, 0, {false, 0, 0}}; - -typedef struct checksum_t { - uint8_t byte1; - uint8_t byte2; -} checksum_t; - -typedef struct msg_info_t { - bool valid; - uint8_t len; - uint8_t msg_id; - uint8_t* msg_loc; -} msg_info_t; - -typedef struct _packet_format { - bool (*check_start_bytes)(uint8_t); - bool (*process_header_byte)(uint8_t, size_t); - size_t (*get_msg_id)(uint8_t* data); - size_t (*get_full_packet_length)(size_t); - struct msg_info_t (*validate_packet)(uint8_t*, size_t); - size_t (*encode)(uint8_t* buffer, uint8_t msg_id, uint8_t* msg, uint8_t msg_size); - uint8_t* (*encode_reserve)(uint8_t* buffer, uint8_t msg_id, uint8_t msg_size); - uint8_t (*encode_finsish)(uint8_t* buffer, uint8_t msg_size); - -} packet_format_t; - -enum parser_state_enum { LOOKING_FOR_START_BYTE = 0, GETTING_HEADER = 1, GETTING_PAYLOAD = 2 }; - -typedef struct _definitions { - bool (*get_message_length)(size_t, size_t*); - packet_format_t* (*get_packet_formats)(uint8_t); -} packet_definitions_t; - -typedef struct packet_state_t { - enum parser_state_enum state; - size_t packet_size; - packet_format_t* format; - packet_definitions_t* defines; - - uint8_t* buffer; - size_t buffer_size; - - // for parse buffer - size_t buffer_max_size; - size_t packet_start_index; - bool finished; - size_t r_loc; -} packet_state_t; - -typedef struct _msg_encode_buffer { - uint8_t* data; - size_t max_size; - size_t size; - bool in_progress; -} msg_encode_buffer; - -typedef struct _struct_frame_parse_char_impl { - // Used for framing and parsing - packet_format_t packet_format; - packet_state_t parser_state; - -} struct_frame_parse_char_impl; diff --git a/src/struct_frame/boilerplate/cpp/basic_frame.hpp b/src/struct_frame/boilerplate/cpp/basic_frame.hpp deleted file mode 100644 index 27004904..00000000 --- a/src/struct_frame/boilerplate/cpp/basic_frame.hpp +++ /dev/null @@ -1,393 +0,0 @@ -/* - * BasicFrame - Simple frame format with CRC (C++ version) - * - * Format: [START1=0x90] [START2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - * - * This frame format requires a message ID to message length lookup function - * since the length is not included in the packet. - * - * Use Case: When all message lengths are known at compile time and bandwidth - * efficiency is important. - */ - -#pragma once - -#include -#include -#include -#include - -namespace StructFrame { - -/* Frame 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; /* start1 + start2 + msg_id */ -constexpr size_t BASIC_FRAME_FOOTER_SIZE = 2; /* crc1 + crc2 */ -constexpr size_t BASIC_FRAME_OVERHEAD = BASIC_FRAME_HEADER_SIZE + BASIC_FRAME_FOOTER_SIZE; - -/* Checksum result */ -struct BasicFrameChecksum { - uint8_t byte1; - uint8_t byte2; -}; - -/* Parse result */ -struct BasicFrameMsgInfo { - bool valid; - uint8_t msg_id; - uint8_t msg_len; - uint8_t* msg_data; - - BasicFrameMsgInfo() : valid(false), msg_id(0), msg_len(0), msg_data(nullptr) {} - BasicFrameMsgInfo(bool v, uint8_t id, uint8_t len, uint8_t* data) - : valid(v), msg_id(id), msg_len(len), msg_data(data) {} -}; - -/* Parser state enumeration */ -enum class BasicFrameParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingPayload = 3 -}; - -/*=========================================================================== - * Checksum Calculation - *===========================================================================*/ - -/** - * Calculate Fletcher-16 checksum over the given data - */ -inline BasicFrameChecksum basic_frame_checksum(const uint8_t* data, size_t length) { - BasicFrameChecksum 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; -} - -/*=========================================================================== - * Encode Buffer Class - *===========================================================================*/ - -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 over msg_id + msg data */ - BasicFrameChecksum ck = basic_frame_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; - } - - /** - * Reserve space in buffer for zero-copy encoding - * Returns pointer to message data area, or nullptr on failure - */ - uint8_t* reserve(uint8_t msg_id, size_t msg_size) { - if (in_progress_) { - return nullptr; - } - - size_t total_size = BASIC_FRAME_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) { - return nullptr; - } - - 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; - - in_progress_ = true; - reserved_msg_size_ = msg_size; - return packet_start + BASIC_FRAME_HEADER_SIZE; - } - - /** - * Finish a reserved encoding by adding checksum - */ - bool finish() { - if (!in_progress_) { - return false; - } - - uint8_t* packet_start = data_ + size_; - - /* Calculate checksum over msg_id + msg data */ - BasicFrameChecksum ck = basic_frame_checksum(packet_start + 2, reserved_msg_size_ + 1); - packet_start[BASIC_FRAME_HEADER_SIZE + reserved_msg_size_] = ck.byte1; - packet_start[BASIC_FRAME_HEADER_SIZE + reserved_msg_size_ + 1] = ck.byte2; - - size_ += BASIC_FRAME_OVERHEAD + reserved_msg_size_; - in_progress_ = false; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; - size_t reserved_msg_size_ = 0; -}; - -/*=========================================================================== - * Parser Class - *===========================================================================*/ - -class BasicFrameParser { -public: - using MsgLengthCallback = std::function; - - BasicFrameParser(uint8_t* buffer, size_t buffer_size, MsgLengthCallback msg_length_cb) - : 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 a BasicFrameMsgInfo with valid=true when a complete valid message is received - */ - BasicFrameMsgInfo parse_byte(uint8_t byte) { - BasicFrameMsgInfo 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; - } else { - state_ = BasicFrameParserState::LookingForStart1; - } - break; - - case BasicFrameParserState::GettingMsgId: { - buffer_[2] = byte; - buffer_index_ = 3; - 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_) { - size_t msg_length = packet_size_ - BASIC_FRAME_OVERHEAD; - BasicFrameChecksum ck = basic_frame_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 = static_cast(msg_length); - result.msg_data = buffer_ + BASIC_FRAME_HEADER_SIZE; - } - - state_ = BasicFrameParserState::LookingForStart1; - } - break; - } - - return result; - } - - /** - * Parse a buffer of bytes - */ - BasicFrameMsgInfo parse_buffer(const uint8_t* data, size_t data_size, size_t& r_loc) { - BasicFrameMsgInfo result; - - while (r_loc < data_size) { - result = parse_byte(data[r_loc]); - r_loc++; - if (result.valid) { - return result; - } - } - - 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_; -}; - -/*=========================================================================== - * Static Helper Functions - *===========================================================================*/ - -/** - * Encode a message directly into a buffer - * 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); - } - - BasicFrameChecksum ck = basic_frame_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 packet in a buffer - */ -inline BasicFrameMsgInfo basic_frame_validate_packet(const uint8_t* buffer, size_t length) { - BasicFrameMsgInfo result; - - if (length < BASIC_FRAME_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_START_BYTE1 || buffer[1] != BASIC_FRAME_START_BYTE2) { - return result; - } - - size_t msg_length = length - BASIC_FRAME_OVERHEAD; - - BasicFrameChecksum ck = basic_frame_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 = static_cast(msg_length); - result.msg_data = const_cast(buffer + BASIC_FRAME_HEADER_SIZE); - } - - return result; -} - -/*=========================================================================== - * Message Helper Template - *===========================================================================*/ - -/** - * Template helper for message encoding/decoding - */ -template -struct BasicFrameMessageHelper { - static constexpr uint8_t MSG_ID = MsgId; - static constexpr size_t MSG_SIZE = MsgSize; - - static bool encode(BasicFrameEncodeBuffer& buf, const T& msg) { - return buf.encode(MSG_ID, &msg, MSG_SIZE); - } - - static T* reserve(BasicFrameEncodeBuffer& buf) { - return reinterpret_cast(buf.reserve(MSG_ID, MSG_SIZE)); - } - - static bool finish(BasicFrameEncodeBuffer& buf) { - return buf.finish(); - } - - static T get(const BasicFrameMsgInfo& info) { - return *reinterpret_cast(info.msg_data); - } - - static T* get_ref(const BasicFrameMsgInfo& info) { - return reinterpret_cast(info.msg_data); - } -}; - -} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/basic_frame_with_len.hpp b/src/struct_frame/boilerplate/cpp/basic_frame_with_len.hpp deleted file mode 100644 index 66662f6b..00000000 --- a/src/struct_frame/boilerplate/cpp/basic_frame_with_len.hpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - * BasicFrameWithLen - Frame format with embedded length and CRC (C++ version) - * - * Format: [START1=0x90] [START2=0x92] [MSG_ID] [LEN] [MSG...] [CRC1] [CRC2] - * - * This frame format includes the message length in the packet header, - * so no msg_id to length lookup is required. - * - * Use Case: When message lengths may vary or are not known at compile time. - */ - -#pragma once - -#include -#include -#include - -namespace StructFrame { - -/* Frame 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; /* start1 + start2 + msg_id + len */ -constexpr size_t BASIC_FRAME_WITH_LEN_FOOTER_SIZE = 2; /* crc1 + crc2 */ -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_MAX_MSG_SIZE = 255; /* Limited by 1-byte length field */ - -/* Checksum result */ -struct BasicFrameWithLenChecksum { - uint8_t byte1; - uint8_t byte2; -}; - -/* Parse result */ -struct BasicFrameWithLenMsgInfo { - bool valid; - uint8_t msg_id; - uint8_t msg_len; - uint8_t* msg_data; - - BasicFrameWithLenMsgInfo() : valid(false), msg_id(0), msg_len(0), msg_data(nullptr) {} - BasicFrameWithLenMsgInfo(bool v, uint8_t id, uint8_t len, uint8_t* data) - : valid(v), msg_id(id), msg_len(len), msg_data(data) {} -}; - -/* Parser state enumeration */ -enum class BasicFrameWithLenParserState : uint8_t { - LookingForStart1 = 0, - LookingForStart2 = 1, - GettingMsgId = 2, - GettingLength = 3, - GettingPayload = 4 -}; - -/*=========================================================================== - * Checksum Calculation - *===========================================================================*/ - -/** - * Calculate Fletcher-16 checksum over the given data - */ -inline BasicFrameWithLenChecksum basic_frame_with_len_checksum(const uint8_t* data, size_t length) { - BasicFrameWithLenChecksum 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; -} - -/*=========================================================================== - * Encode Buffer Class - *===========================================================================*/ - -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, uint8_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] = 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 over msg_id + len + msg data */ - BasicFrameWithLenChecksum ck = basic_frame_with_len_checksum(packet_start + 2, msg_size + 2); - 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; - } - - /** - * Reserve space in buffer for zero-copy encoding - * Returns pointer to message data area, or nullptr on failure - */ - uint8_t* reserve(uint8_t msg_id, uint8_t msg_size) { - if (in_progress_) { - return nullptr; - } - - size_t total_size = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_size; - if (size_ + total_size > max_size_) { - return nullptr; - } - - 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] = msg_size; - - in_progress_ = true; - reserved_msg_size_ = msg_size; - return packet_start + BASIC_FRAME_WITH_LEN_HEADER_SIZE; - } - - /** - * Finish a reserved encoding by adding checksum - */ - bool finish() { - if (!in_progress_) { - return false; - } - - uint8_t* packet_start = data_ + size_; - - /* Calculate checksum over msg_id + len + msg data */ - BasicFrameWithLenChecksum ck = basic_frame_with_len_checksum(packet_start + 2, reserved_msg_size_ + 2); - packet_start[BASIC_FRAME_WITH_LEN_HEADER_SIZE + reserved_msg_size_] = ck.byte1; - packet_start[BASIC_FRAME_WITH_LEN_HEADER_SIZE + reserved_msg_size_ + 1] = ck.byte2; - - size_ += BASIC_FRAME_WITH_LEN_OVERHEAD + reserved_msg_size_; - in_progress_ = false; - return true; - } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; - uint8_t reserved_msg_size_ = 0; -}; - -/*=========================================================================== - * Parser Class - *===========================================================================*/ - -class BasicFrameWithLenParser { -public: - BasicFrameWithLenParser(uint8_t* buffer, size_t buffer_size) - : state_(BasicFrameWithLenParserState::LookingForStart1), - buffer_(buffer), - buffer_max_size_(buffer_size), - buffer_index_(0), - packet_size_(0), - msg_id_(0), - msg_len_(0) {} - - void reset() { - state_ = BasicFrameWithLenParserState::LookingForStart1; - buffer_index_ = 0; - packet_size_ = 0; - msg_id_ = 0; - msg_len_ = 0; - } - - /** - * Parse a single byte - * Returns a BasicFrameWithLenMsgInfo with valid=true when a complete valid message is received - */ - BasicFrameWithLenMsgInfo parse_byte(uint8_t byte) { - BasicFrameWithLenMsgInfo 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; - } else { - state_ = BasicFrameWithLenParserState::LookingForStart1; - } - break; - - case BasicFrameWithLenParserState::GettingMsgId: - buffer_[2] = byte; - buffer_index_ = 3; - msg_id_ = byte; - state_ = BasicFrameWithLenParserState::GettingLength; - break; - - case BasicFrameWithLenParserState::GettingLength: - buffer_[3] = byte; - buffer_index_ = 4; - msg_len_ = byte; - packet_size_ = BASIC_FRAME_WITH_LEN_OVERHEAD + byte; - - 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_) { - BasicFrameWithLenChecksum ck = basic_frame_with_len_checksum(buffer_ + 2, msg_len_ + 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_len_; - result.msg_data = buffer_ + BASIC_FRAME_WITH_LEN_HEADER_SIZE; - } - - state_ = BasicFrameWithLenParserState::LookingForStart1; - } - break; - } - - return result; - } - - /** - * Parse a buffer of bytes - */ - BasicFrameWithLenMsgInfo parse_buffer(const uint8_t* data, size_t data_size, size_t& r_loc) { - BasicFrameWithLenMsgInfo result; - - while (r_loc < data_size) { - result = parse_byte(data[r_loc]); - r_loc++; - if (result.valid) { - return result; - } - } - - 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_; - uint8_t msg_len_; -}; - -/*=========================================================================== - * Static Helper Functions - *===========================================================================*/ - -/** - * Encode a message directly into a buffer - * 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, uint8_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] = msg_size; - - if (msg_size > 0 && msg != nullptr) { - std::memcpy(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE, msg, msg_size); - } - - BasicFrameWithLenChecksum ck = basic_frame_with_len_checksum(buffer + 2, msg_size + 2); - 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 packet in a buffer - */ -inline BasicFrameWithLenMsgInfo basic_frame_with_len_validate_packet(const uint8_t* buffer, size_t length) { - BasicFrameWithLenMsgInfo result; - - if (length < BASIC_FRAME_WITH_LEN_OVERHEAD) { - return result; - } - - if (buffer[0] != BASIC_FRAME_WITH_LEN_START_BYTE1 || - buffer[1] != BASIC_FRAME_WITH_LEN_START_BYTE2) { - return result; - } - - uint8_t msg_len = buffer[3]; - size_t expected_length = BASIC_FRAME_WITH_LEN_OVERHEAD + msg_len; - - if (length != expected_length) { - return result; - } - - BasicFrameWithLenChecksum ck = basic_frame_with_len_checksum(buffer + 2, msg_len + 2); - if (ck.byte1 == buffer[length - 2] && ck.byte2 == buffer[length - 1]) { - result.valid = true; - result.msg_id = buffer[2]; - result.msg_len = msg_len; - result.msg_data = const_cast(buffer + BASIC_FRAME_WITH_LEN_HEADER_SIZE); - } - - return result; -} - -/*=========================================================================== - * Message Helper Template - *===========================================================================*/ - -/** - * Template helper for message encoding/decoding with BasicFrameWithLen - */ -template -struct BasicFrameWithLenMessageHelper { - static constexpr uint8_t MSG_ID = MsgId; - static constexpr uint8_t MSG_SIZE = MsgSize; - - static bool encode(BasicFrameWithLenEncodeBuffer& buf, const T& msg) { - return buf.encode(MSG_ID, &msg, MSG_SIZE); - } - - static T* reserve(BasicFrameWithLenEncodeBuffer& buf) { - return reinterpret_cast(buf.reserve(MSG_ID, MSG_SIZE)); - } - - static bool finish(BasicFrameWithLenEncodeBuffer& buf) { - return buf.finish(); - } - - static T get(const BasicFrameWithLenMsgInfo& info) { - return *reinterpret_cast(info.msg_data); - } - - static T* get_ref(const BasicFrameWithLenMsgInfo& info) { - return reinterpret_cast(info.msg_data); - } -}; - -} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/struct_frame.hpp b/src/struct_frame/boilerplate/cpp/struct_frame.hpp deleted file mode 100644 index 793fd58d..00000000 --- a/src/struct_frame/boilerplate/cpp/struct_frame.hpp +++ /dev/null @@ -1,197 +0,0 @@ -#pragma once - -#include "struct_frame_types.hpp" -#include -#include - -namespace StructFrame { - -// Basic packet format class (similar to Python's BasicPacket) -class BasicPacket : public PacketFormat { -public: - BasicPacket(uint8_t start_byte = 0x90, size_t header_length = 2, size_t footer_length = 2) - : start_byte_(start_byte), - header_length_(header_length), - footer_length_(footer_length), - desired_packet_length_(0) {} - - bool check_start_byte(uint8_t byte) override { - return byte == start_byte_; - } - - bool process_header_byte(uint8_t byte, size_t index) override { - if (index < header_length_) { - header_buffer_[index] = byte; - return (index + 1) >= header_length_; - } - return false; - } - - size_t get_msg_id(const uint8_t* data) override { - return data[1]; // Message ID is at index 1 - } - - size_t get_full_packet_length(size_t msg_length) override { - desired_packet_length_ = header_length_ + footer_length_ + msg_length; - return desired_packet_length_; - } - - MessageInfo validate_packet(const uint8_t* buffer, size_t length) override { - MessageInfo info{false, 0, 0, nullptr}; - - if (length < header_length_ + footer_length_) { - return info; - } - - size_t msg_length = length - header_length_ - footer_length_; - - // Calculate checksum on msg_id + msg data (buffer + 1 includes msg_id byte) - Checksum calc = fletcher_checksum(buffer + 1, msg_length + 1); - - // Validate checksum - if (calc.byte1 == buffer[length - 2] && calc.byte2 == buffer[length - 1]) { - info.valid = true; - info.length = static_cast(msg_length); - info.msg_id = buffer[1]; - info.msg_location = const_cast(buffer + header_length_); - } - - return info; - } - - size_t encode(uint8_t* buffer, uint8_t msg_id, const uint8_t* msg, uint8_t msg_size) override { - buffer[0] = start_byte_; - buffer[1] = msg_id; - - if (msg_size > 0) { - std::memcpy(buffer + 2, msg, msg_size); - } - - // Calculate checksum on msg_id + msg data (consistent with C and Python) - Checksum checksum = fletcher_checksum(buffer + 1, msg_size + 1); - buffer[2 + msg_size] = checksum.byte1; - buffer[2 + msg_size + 1] = checksum.byte2; - - return header_length_ + msg_size + footer_length_; - } - - uint8_t* encode_reserve(uint8_t* buffer, uint8_t msg_id, uint8_t msg_size) override { - buffer[0] = start_byte_; - buffer[1] = msg_id; - return buffer + header_length_; - } - - uint8_t encode_finish(uint8_t* buffer, uint8_t msg_size) override { - // Calculate checksum on msg_id + msg data (buffer + 1 includes msg_id byte) - Checksum checksum = fletcher_checksum(buffer + 1, msg_size + 1); - buffer[header_length_ + msg_size] = checksum.byte1; - buffer[header_length_ + msg_size + 1] = checksum.byte2; - return header_length_ + msg_size + footer_length_; - } - -private: - uint8_t start_byte_; - size_t header_length_; - size_t footer_length_; - size_t desired_packet_length_; - uint8_t header_buffer_[256]; -}; - -// Frame parser (similar to Python's FrameParser) -class FrameParser { -public: - using MessageLengthCallback = std::function; - - FrameParser(PacketFormat* format, MessageLengthCallback msg_length_callback) - : format_(format), - msg_length_callback_(msg_length_callback), - state_(ParserState::LookingForStartByte), - header_index_(0), - packet_index_(0), - packet_size_(0) {} - - MessageInfo parse_byte(uint8_t byte) { - MessageInfo invalid_info{false, 0, 0, nullptr}; - - switch (state_) { - case ParserState::LookingForStartByte: - if (format_->check_start_byte(byte)) { - packet_buffer_[0] = byte; - header_index_ = 1; - state_ = ParserState::GettingHeader; - } - break; - - case ParserState::GettingHeader: - packet_buffer_[header_index_++] = byte; - - if (format_->process_header_byte(byte, header_index_ - 1)) { - size_t msg_id = format_->get_msg_id(packet_buffer_); - size_t msg_length = 0; - - if (msg_length_callback_(msg_id, &msg_length)) { - packet_size_ = format_->get_full_packet_length(msg_length); - packet_index_ = header_index_; - state_ = ParserState::GettingPayload; - } else { - state_ = ParserState::LookingForStartByte; - } - } - break; - - case ParserState::GettingPayload: - packet_buffer_[packet_index_++] = byte; - - if (packet_index_ >= packet_size_) { - state_ = ParserState::LookingForStartByte; - return format_->validate_packet(packet_buffer_, packet_size_); - } - break; - } - - return invalid_info; - } - - void reset() { - state_ = ParserState::LookingForStartByte; - header_index_ = 0; - packet_index_ = 0; - packet_size_ = 0; - } - -private: - PacketFormat* format_; - MessageLengthCallback msg_length_callback_; - ParserState state_; - size_t header_index_; - size_t packet_index_; - size_t packet_size_; - uint8_t packet_buffer_[512]; // Reasonable max packet size -}; - -// Message encoder/decoder helper template -template -class MessageHelper { -public: - static bool encode(EncodeBuffer& buffer, PacketFormat* format, const T& msg, uint8_t msg_id, uint8_t msg_size) { - return buffer.encode(format, msg_id, &msg, msg_size); - } - - static T* reserve(EncodeBuffer& buffer, PacketFormat* format, uint8_t msg_id, uint8_t msg_size) { - return reinterpret_cast(buffer.reserve(format, msg_id, msg_size)); - } - - static bool finish(EncodeBuffer& buffer, PacketFormat* format, uint8_t msg_size) { - return buffer.finish(format, msg_size); - } - - static T get(const MessageInfo& info) { - return *reinterpret_cast(info.msg_location); - } - - static T* get_ref(const MessageInfo& info) { - return reinterpret_cast(info.msg_location); - } -}; - -} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_parser.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_parser.hpp deleted file mode 100644 index 4d12e813..00000000 --- a/src/struct_frame/boilerplate/cpp/struct_frame_parser.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include "struct_frame_types.hpp" -#include "struct_frame.hpp" - -namespace StructFrame { - -// Parse buffer function for processing multiple bytes at once -inline MessageInfo parse_buffer(ParserStateData* state) { - MessageInfo invalid_info{false, 0, 0, nullptr}; - - if (!state->buffer || state->buffer_size == 0) { - return invalid_info; - } - - while (state->read_location < state->buffer_size && !state->finished) { - uint8_t byte = state->buffer[state->read_location++]; - - switch (state->state) { - case ParserState::LookingForStartByte: - if (state->format->check_start_byte(byte)) { - state->packet_start_index = state->read_location - 1; - state->state = ParserState::GettingHeader; - state->packet_size = 1; - } - break; - - case ParserState::GettingHeader: - state->packet_size++; - if (state->format->process_header_byte(byte, state->packet_size - 1)) { - size_t msg_id = state->format->get_msg_id(state->buffer + state->packet_start_index); - size_t msg_length = 0; - - // Need external callback to get message length - // This would be implemented by the user - state->packet_size = state->format->get_full_packet_length(msg_length); - state->state = ParserState::GettingPayload; - } - break; - - case ParserState::GettingPayload: - if (state->read_location - state->packet_start_index >= state->packet_size) { - state->state = ParserState::LookingForStartByte; - MessageInfo info = state->format->validate_packet( - state->buffer + state->packet_start_index, - state->packet_size - ); - - if (state->read_location >= state->buffer_size) { - state->finished = true; - } - - return info; - } - break; - } - } - - if (state->read_location >= state->buffer_size) { - state->finished = true; - } - - return invalid_info; -} - -// Device base class for implementing communication devices -class Device { -public: - Device(PacketFormat* format, uint8_t* tx_buffer, size_t tx_buffer_size) - : format_(format), - encode_buffer_(tx_buffer, tx_buffer_size), - parser_(format, [this](size_t msg_id, size_t* size) { - return this->get_message_length(msg_id, size); - }) {} - - virtual ~Device() = default; - - // Process received data - void process_rx_data(uint8_t* buffer, size_t length) { - for (size_t i = 0; i < length; ++i) { - MessageInfo info = parser_.parse_byte(buffer[i]); - if (info.valid) { - handle_message(info); - } - } - } - - // Get encode buffer for message transmission - EncodeBuffer& get_encode_buffer() { - return encode_buffer_; - } - - // Get the transmit buffer data - uint8_t* get_tx_data() { - return encode_buffer_.data(); - } - - size_t get_tx_size() const { - return encode_buffer_.size(); - } - - void reset_tx_buffer() { - encode_buffer_.reset(); - } - -protected: - // Must be implemented by derived classes - virtual bool get_message_length(size_t msg_id, size_t* size) = 0; - virtual void handle_message(const MessageInfo& info) = 0; - - PacketFormat* format_; - EncodeBuffer encode_buffer_; - FrameParser parser_; -}; - -} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/cpp/struct_frame_types.hpp b/src/struct_frame/boilerplate/cpp/struct_frame_types.hpp deleted file mode 100644 index a868216b..00000000 --- a/src/struct_frame/boilerplate/cpp/struct_frame_types.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace StructFrame { - -// Checksum structure -struct Checksum { - uint8_t byte1; - uint8_t byte2; -}; - -// Message information structure -struct MessageInfo { - bool valid; - uint8_t length; - uint8_t msg_id; - uint8_t* msg_location; -}; - -// Parser states -enum class ParserState : uint8_t { - LookingForStartByte = 0, - GettingHeader = 1, - GettingPayload = 2 -}; - -// Fletcher checksum calculation -inline Checksum fletcher_checksum(const uint8_t* buffer, size_t length) { - Checksum checksum{0, 0}; - - for (size_t i = 0; i < length; i++) { - checksum.byte1 += buffer[i]; - checksum.byte2 += checksum.byte1; - } - - return checksum; -} - -// Base packet format interface -class PacketFormat { -public: - virtual ~PacketFormat() = default; - - virtual bool check_start_byte(uint8_t byte) = 0; - virtual bool process_header_byte(uint8_t byte, size_t index) = 0; - virtual size_t get_msg_id(const uint8_t* data) = 0; - virtual size_t get_full_packet_length(size_t msg_length) = 0; - virtual MessageInfo validate_packet(const uint8_t* buffer, size_t length) = 0; - virtual size_t encode(uint8_t* buffer, uint8_t msg_id, const uint8_t* msg, uint8_t msg_size) = 0; - virtual uint8_t* encode_reserve(uint8_t* buffer, uint8_t msg_id, uint8_t msg_size) = 0; - virtual uint8_t encode_finish(uint8_t* buffer, uint8_t msg_size) = 0; -}; - -// Encoder buffer for message encoding -class EncodeBuffer { -public: - EncodeBuffer(uint8_t* buffer, size_t max_size) - : data_(buffer), max_size_(max_size), size_(0), in_progress_(false) {} - - bool encode(PacketFormat* format, uint8_t msg_id, const void* msg, uint8_t msg_size) { - if (in_progress_) { - return false; - } - in_progress_ = true; - size_ += format->encode(data_, msg_id, static_cast(msg), msg_size); - in_progress_ = false; - return true; - } - - uint8_t* reserve(PacketFormat* format, uint8_t msg_id, uint8_t msg_size) { - if (in_progress_) { - return nullptr; - } - in_progress_ = true; - return format->encode_reserve(data_, msg_id, msg_size); - } - - bool finish(PacketFormat* format, uint8_t msg_size) { - if (!in_progress_) { - return false; - } - size_ += format->encode_finish(data_, msg_size); - in_progress_ = false; - return true; - } - - uint8_t* data() { return data_; } - size_t size() const { return size_; } - size_t max_size() const { return max_size_; } - void reset() { size_ = 0; in_progress_ = false; } - -private: - uint8_t* data_; - size_t max_size_; - size_t size_; - bool in_progress_; -}; - -// Packet parser state -struct ParserStateData { - ParserState state; - size_t packet_size; - PacketFormat* format; - uint8_t* buffer; - size_t buffer_size; - size_t buffer_max_size; - size_t packet_start_index; - bool finished; - size_t read_location; -}; - -} // namespace StructFrame diff --git a/src/struct_frame/boilerplate/js/struct_frame_gen.js b/src/struct_frame/boilerplate/js/struct_frame_gen.js deleted file mode 100644 index e2bb36f5..00000000 --- a/src/struct_frame/boilerplate/js/struct_frame_gen.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Struct frame message length aggregator for JavaScript. - * Human-readable JavaScript version of the TypeScript boilerplate. - */ -"use strict"; - -// This file should be updated to import and aggregate all generated .sf files -// For now, it returns 0 for unknown message IDs, which allows the parser to handle unknown messages gracefully -// In a production setup, you should import all your .sf files and call their get_message_length functions - -function get_message_length(msg_id) { - // TODO: Import and aggregate all .sf files - // Example: - // const module1 = require('./module1.sf'); - // const module2 = require('./module2.sf'); - // const length = module1.get_message_length(msg_id) || module2.get_message_length(msg_id); - // return length; - - // Returning 0 for unknown message IDs allows graceful handling of unsupported messages - return 0; -} -module.exports.get_message_length = get_message_length; diff --git a/src/struct_frame/boilerplate/js/struct_frame_parser.js b/src/struct_frame/boilerplate/js/struct_frame_parser.js deleted file mode 100644 index 632380be..00000000 --- a/src/struct_frame/boilerplate/js/struct_frame_parser.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Struct frame parser for JavaScript. - * Human-readable JavaScript version of the TypeScript boilerplate. - */ -"use strict"; - -const { get_message_length } = require('./struct_frame_gen'); -const sf_types = require('./struct_frame_types'); - -function parse_default_format_validate(buffer, msg_id_len) { - return true; -} - -function parse_default_format_char_for_len_id(c, msg_id_len) { - msg_id_len.msg_id = c; - msg_id_len.len = get_message_length(c); - return true; -} - -const default_parser_functions = { - get_msg_id_len: parse_default_format_char_for_len_id, - validate_packet: parse_default_format_validate -}; - -function parse_char_for_start_byte(config, c) { - if (config.start_byte == c) { - return default_parser_functions; - } - return undefined; -} - -function parse_char(pb, c) { - let parse_func_ptr = undefined; - switch (pb.state) { - case sf_types.ParserState.LOOKING_FOR_START_BYTE: - parse_func_ptr = parse_char_for_start_byte(pb.config, c); - if (parse_func_ptr) { - pb.config.parser_funcs = parse_func_ptr; - pb.state = sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID; - } - break; - - case sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID: - if (pb.config.parser_funcs && pb.config.parser_funcs.get_msg_id_len(c, pb.msg_id_len)) { - pb.state = sf_types.ParserState.GETTING_PAYLOAD; - pb.size = 0; - } - break; - - case sf_types.ParserState.GETTING_PAYLOAD: - pb.data[pb.size] = c; - pb.size++; - if (pb.size >= pb.msg_id_len.len) { - pb.msg_data = Buffer.from(pb.data.slice(0, pb.size)); - pb.state = sf_types.ParserState.LOOKING_FOR_START_BYTE; - if (pb.config.parser_funcs) { - return pb.config.parser_funcs.validate_packet(pb.data, pb.msg_id_len); - } - return false; - } - break; - - default: - break; - } - - return false; -} -module.exports.parse_char = parse_char; - -function parse_buffer(buffer, size, parser_result) { - let state = sf_types.ParserState.LOOKING_FOR_START_BYTE; - let parse_func_ptr = undefined; - for (let i = parser_result.r_loc; i < size; i++) { - switch (state) { - case sf_types.ParserState.LOOKING_FOR_START_BYTE: - parse_func_ptr = parse_char_for_start_byte(parser_result.config, buffer[i]); - if (parse_func_ptr) { - state = sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID; - } - break; - - case sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID: - if (parse_func_ptr && parse_func_ptr.get_msg_id_len(buffer[i], parser_result.msg_id_len)) { - state = sf_types.ParserState.GETTING_PAYLOAD; - } - break; - - case sf_types.ParserState.GETTING_PAYLOAD: - parser_result.msg_data = Buffer.from(buffer.slice(i, i + parser_result.msg_id_len.len)); - parser_result.r_loc = i + parser_result.msg_id_len.len; - parser_result.found = true; - if (parse_func_ptr && parse_func_ptr.validate_packet(parser_result.msg_data, parser_result.msg_id_len)) { - parser_result.valid = true; - return true; - } - else { - parser_result.valid = false; - return true; - } - break; - - default: - break; - } - } - return false; -} -module.exports.parse_buffer = parse_buffer; diff --git a/src/struct_frame/boilerplate/py/struct_frame_parser.py b/src/struct_frame/boilerplate/py/struct_frame_parser.py deleted file mode 100644 index 3b4d92c0..00000000 --- a/src/struct_frame/boilerplate/py/struct_frame_parser.py +++ /dev/null @@ -1,189 +0,0 @@ - -from enum import Enum - - -def fletcher_checksum_calculation(buffer, start=0, end=None): - if end == 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] - - -class BasicFrame: - """ - BasicFrame - Simple frame format with CRC - - Format: [START1=0x90] [START2=0x91] [MSG_ID] [MSG...] [CRC1] [CRC2] - - This frame format requires a message ID to message length lookup function - since the length is not included in the packet. - """ - - START_BYTE1 = 0x90 - START_BYTE2 = 0x91 - HEADER_SIZE = 3 # start1 + start2 + msg_id - FOOTER_SIZE = 2 # crc1 + crc2 - - def __init__(self): - self.packet = [] - self.desired_packet_length = 0 - self.state = 0 # 0: looking for start1, 1: looking for start2, 2: getting msg_id, 3: getting payload - - def encode_msg(self, msg): - """Encode a message object into a framed byte list""" - return self.encode(msg.pack(), msg.msg_id) - - def encode(self, data, msg_id): - """Encode data with a message ID into a framed byte list""" - output = [] - output.append(self.START_BYTE1) - output.append(self.START_BYTE2) - output.append(msg_id) - if len(data): - for b in data: - output.append(b) - # Calculate checksum on msg_id + data - checksum_data = [msg_id] + list(data) - checksum = fletcher_checksum_calculation(checksum_data) - output.append(checksum[0]) - output.append(checksum[1]) - return output - - def validate_packet(self, buffer): - """Validate a complete packet in a buffer""" - if len(buffer) < self.HEADER_SIZE + self.FOOTER_SIZE: - return None - - # Check start bytes - if buffer[0] != self.START_BYTE1 or buffer[1] != self.START_BYTE2: - return None - - msg_length = len(buffer) - self.HEADER_SIZE - self.FOOTER_SIZE - - # Validate checksum over msg_id + msg data - checksum = fletcher_checksum_calculation(buffer, 2, len(buffer) - self.FOOTER_SIZE) - if checksum[0] != buffer[-2] or checksum[1] != buffer[-1]: - return None - - return { - 'valid': True, - 'msg_id': buffer[2], - 'msg_len': msg_length, - 'msg_data': buffer[self.HEADER_SIZE:len(buffer) - self.FOOTER_SIZE] - } - - def get_msg_buffer(self, buffer): - """Get the message data portion from a validated buffer""" - return buffer[self.HEADER_SIZE:len(buffer) - self.FOOTER_SIZE] - - -class BasicPacket: - start_byte = 0x90 - header_length = 0 - footer_length = 0 - - desired_packet_length = 0 - packet = [] - - def __init__(self, start_byte=0x90, header_length=2, footer_length=2): - self.start_byte = start_byte - self.header_length = header_length - self.footer_length = footer_length - - def add_header_byte(self, byte, clear=False): - if clear: - self.packet.clear() - self.packet.append(byte) - return len(self.packet) >= self.header_length - - def add_packet_byte(self, byte): - self.packet.append(byte) - return len(self.packet) == self.desired_packet_length - - def get_msg_id(self): - return self.packet[1] - - def get_full_packet_length(self, msg_length): - self.desired_packet_length = self.header_length + self.footer_length + msg_length - return self.desired_packet_length - - def validate_packet(self): - checksum = fletcher_checksum_calculation( - self.packet, self.header_length - 1, self.desired_packet_length - self.footer_length) - return checksum[0] == self.packet[-2] and checksum[1] == self.packet[-1] - - def get_msg_buffer(self): - return self.packet[self.header_length:self.desired_packet_length - self.footer_length] - - def encode_msg(self, msg): - return self.encode(msg.pack(), msg.msg_id) - - def encode(self, data, msg_id): - output = [] - output.append(self.start_byte) - output.append(msg_id) - if (len(data)): - for b in data: - output.append(b) - # Calculate checksum on msg_id + data (consistent with validate_packet) - checksum_data = [msg_id] + list(data) - checksum = fletcher_checksum_calculation(checksum_data) - - output.append(checksum[0]) - output.append(checksum[1]) - return output - - -class ParserState(Enum): - LOOKING_FOR_START_BYTE = 0 - GETTING_HEADER = 1 - GETTING_PACKET = 2 - - -class FrameParser: - state = ParserState.LOOKING_FOR_START_BYTE - buffer = [] - packetFormat = None - msg_definitions = None - msg_id_loc = None - msg_type = None - - def __init__(self, packetFormats, msg_definitions): - self.packetFormats = packetFormats - self.msg_definitions = msg_definitions - - def parse_char(self, c): - if self.state == ParserState.LOOKING_FOR_START_BYTE: - if c in self.packetFormats: - self.packetFormat = self.packetFormats[c] - if self.packetFormat.add_header_byte(c, True): - self.state = ParserState.GETTING_PACKET - else: - self.state = ParserState.GETTING_HEADER - - elif self.state == ParserState.GETTING_HEADER: - if self.packetFormat.add_header_byte(c): - msg_id = self.packetFormat.get_msg_id() - if msg_id in self.msg_definitions: - self.msg_type = self.msg_definitions[msg_id] - if self.msg_type: - self.packetFormat.get_full_packet_length( - self.msg_type.msg_size) - self.state = ParserState.GETTING_PACKET - else: - self.state = ParserState.LOOKING_FOR_START_BYTE - - elif self.state == ParserState.GETTING_PACKET: - if self.packetFormat.add_packet_byte(c): - self.state = ParserState.LOOKING_FOR_START_BYTE - if self.packetFormat.validate_packet(): - return self.msg_type.create_unpack(bytes(self.packetFormat.get_msg_buffer())) - - return False diff --git a/src/struct_frame/boilerplate/ts/struct_frame_gen.ts b/src/struct_frame/boilerplate/ts/struct_frame_gen.ts deleted file mode 100644 index 6cffbcef..00000000 --- a/src/struct_frame/boilerplate/ts/struct_frame_gen.ts +++ /dev/null @@ -1,16 +0,0 @@ - -// This file should be updated to import and aggregate all generated .sf files -// For now, it returns 0 for unknown message IDs, which allows the parser to handle unknown messages gracefully -// In a production setup, you should import all your .sf files and call their get_message_length functions - -export function get_message_length(msg_id: number) { - // TODO: Import and aggregate all .sf files - // Example: - // import * as module1 from './module1.sf'; - // import * as module2 from './module2.sf'; - // const length = module1.get_message_length(msg_id) || module2.get_message_length(msg_id); - // return length; - - // Returning 0 for unknown message IDs allows graceful handling of unsupported messages - return 0; -} diff --git a/src/struct_frame/boilerplate/ts/struct_frame_parser.ts b/src/struct_frame/boilerplate/ts/struct_frame_parser.ts deleted file mode 100644 index 1e39b022..00000000 --- a/src/struct_frame/boilerplate/ts/struct_frame_parser.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { get_message_length } from './struct_frame_gen'; -import * as sf_types from './struct_frame_types'; - -function parse_default_format_validate(buffer: Uint8Array, msg_id_len: sf_types.msg_id_len_t): boolean { - return true; -} - -function parse_default_format_char_for_len_id(c: number, msg_id_len: sf_types.msg_id_len_t): boolean { - msg_id_len.msg_id = c; - msg_id_len.len = get_message_length(c); - return true; -} - -const default_parser_functions: sf_types.parser_functions_t = { get_msg_id_len: parse_default_format_char_for_len_id, validate_packet: parse_default_format_validate }; - -function parse_char_for_start_byte(config: sf_types.struct_frame_config, c: number): sf_types.parser_functions_t | undefined { - if (config.start_byte == c) { - return default_parser_functions; - } - return; -} - -export function parse_char(pb: sf_types.struct_frame_buffer, c: number): boolean { - let parse_func_ptr: sf_types.parser_functions_t | undefined = undefined; - switch (pb.state) { - case sf_types.ParserState.LOOKING_FOR_START_BYTE: - parse_func_ptr = parse_char_for_start_byte(pb.config, c); - if (parse_func_ptr) { - pb.config.parser_funcs = parse_func_ptr; - pb.state = sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID; - } - break; - - case sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID: - if (pb.config.parser_funcs && pb.config.parser_funcs.get_msg_id_len(c, pb.msg_id_len)) { - pb.state = sf_types.ParserState.GETTING_PAYLOAD; - pb.size = 0; - } - break; - - case sf_types.ParserState.GETTING_PAYLOAD: - pb.data[pb.size] = c; - pb.size++; - if (pb.size >= pb.msg_id_len.len) { - pb.msg_data = Buffer.from(pb.data.slice(0, pb.size)) - pb.state = sf_types.ParserState.LOOKING_FOR_START_BYTE; - if (pb.config.parser_funcs) { - return pb.config.parser_funcs.validate_packet(pb.data, pb.msg_id_len); - } - return false; - } - break; - - default: - break; - } - - return false; -} - -export function parse_buffer(buffer: Uint8Array, size: number, parser_result: sf_types.buffer_parser_result_t): boolean { - let state: sf_types.ParserState = sf_types.ParserState.LOOKING_FOR_START_BYTE; - let parse_func_ptr: sf_types.parser_functions_t | undefined; - for (let i = parser_result.r_loc; i < size; i++) { - switch (state) { - case sf_types.ParserState.LOOKING_FOR_START_BYTE: - parse_func_ptr = parse_char_for_start_byte(parser_result.config, buffer[i]); - if (parse_func_ptr) { - state = sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID; - } - break; - - case sf_types.ParserState.GETTING_LENGTH_MSG_AND_ID: - if (parse_func_ptr && parse_func_ptr.get_msg_id_len(buffer[i], parser_result.msg_id_len)) { - state = sf_types.ParserState.GETTING_PAYLOAD; - } - break; - - case sf_types.ParserState.GETTING_PAYLOAD: - parser_result.msg_data = Buffer.from(buffer.slice(i, i + parser_result.msg_id_len.len)); - parser_result.r_loc = i + parser_result.msg_id_len.len; - parser_result.found = true; - if (parse_func_ptr && parse_func_ptr.validate_packet(parser_result.msg_data, parser_result.msg_id_len)) { - parser_result.valid = true; - return true; - } - else { - parser_result.valid = false; - return true; - } - break; - - default: - break; - } - } - return false; -} diff --git a/src/struct_frame/c_gen.py b/src/struct_frame/c_gen.py index 188331ba..91ec57bd 100644 --- a/src/struct_frame/c_gen.py +++ b/src/struct_frame/c_gen.py @@ -185,11 +185,6 @@ def generate(msg): if msg.id: result += '#define %s_MSG_ID %d\n' % (defineName, msg.id) - funcName = defineName.lower() - if msg.id: - result += 'MESSAGE_HELPER(%s, %s, %d, %d);\n\n' % (funcName, structName, - size, msg.id) - return result + '\n' @staticmethod @@ -211,8 +206,9 @@ def generate(package): yield '#pragma once\n' yield '#pragma pack(1)\n' - - yield '#include "struct_frame.h"\n' + yield '#include \n' + yield '#include \n' + yield '#include \n\n' # include additional header files if available in the future @@ -241,12 +237,15 @@ def generate(package): # yield '\n' if package.messages: - yield 'bool get_message_length(size_t msg_id, size_t* size){\n switch (msg_id)\n {\n' + yield 'static inline bool get_message_length(size_t msg_id, size_t* size) {\n' + yield ' switch (msg_id) {\n' for key, msg in package.sortedMessages().items(): name = '%s_%s' % (CamelToSnakeCase( msg.package).upper(), CamelToSnakeCase(msg.name).upper()) if msg.id: - yield ' case %s_MSG_ID: *size = %s_MAX_SIZE; return true;\n' % (name, name) + yield ' case %s_MSG_ID: *size = %s_MAX_SIZE; return true;\n' % (name, name) - yield ' default: break;\n } return false;\n}' - yield '\n' + yield ' default: break;\n' + yield ' }\n' + yield ' return false;\n' + yield '}\n' diff --git a/src/struct_frame/cpp_gen.py b/src/struct_frame/cpp_gen.py index 3d4f24e7..b94bbc19 100644 --- a/src/struct_frame/cpp_gen.py +++ b/src/struct_frame/cpp_gen.py @@ -189,8 +189,7 @@ def generate(package): yield '#pragma once\n' yield '#include \n' - yield '#include \n' - yield '#include "struct_frame.hpp"\n\n' + yield '#include \n\n' # include additional header files if available in the future @@ -209,7 +208,7 @@ def generate(package): # Generate get_message_length function if package.messages: - yield 'namespace StructFrame {\n\n' + yield 'namespace FrameParsers {\n\n' yield 'inline bool get_message_length(size_t msg_id, size_t* size) {\n' yield ' switch (msg_id) {\n' for key, msg in package.sortedMessages().items(): @@ -222,4 +221,4 @@ def generate(package): yield ' }\n' yield ' return false;\n' yield '}\n\n' - yield '} // namespace StructFrame\n' + yield '} // namespace FrameParsers\n' diff --git a/src/struct_frame/generate.py b/src/struct_frame/generate.py index 30f66368..3991e47c 100644 --- a/src/struct_frame/generate.py +++ b/src/struct_frame/generate.py @@ -729,73 +729,90 @@ 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 all boilerplate files including hand-coded frame parsers. - if args.frame_formats: - # Frame parser files to exclude when generating frame parsers - frame_parser_files = { - 'c': ['basic_frame.h', 'basic_frame_with_len.h', 'struct_frame_parser.h'], - 'cpp': ['basic_frame.hpp', 'basic_frame_with_len.hpp', 'struct_frame_parser.hpp'], - 'ts': ['struct_frame_parser.ts'], - 'js': ['struct_frame_parser.js'], - 'py': ['struct_frame_parser.py'] - } - - def copy_boilerplate_selective(src_dir, dst_dir, exclude_files): - """Copy boilerplate files excluding frame parser files""" - if not os.path.exists(dst_dir): - os.makedirs(dst_dir) - for item in os.listdir(src_dir): - if item not in exclude_files: - 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) + # 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'] + } + + # Utility files that should be copied even when generating custom frame parsers + 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'] + } + + def copy_files_list(src_dir, dst_dir, files_to_copy): + """Copy specified files from src_dir to dst_dir""" + if not os.path.exists(dst_dir): + os.makedirs(dst_dir) + for item in files_to_copy: + 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) if args.build_c: - copy_boilerplate_selective( + copy_files_list( os.path.join(dir_path, "boilerplate/c"), - args.c_path[0], frame_parser_files['c']) + args.c_path[0], utility_files['c']) if args.build_ts: - copy_boilerplate_selective( + copy_files_list( os.path.join(dir_path, "boilerplate/ts"), - args.ts_path[0], frame_parser_files['ts']) + args.ts_path[0], utility_files['ts']) if args.build_js: - copy_boilerplate_selective( + copy_files_list( os.path.join(dir_path, "boilerplate/js"), - args.js_path[0], frame_parser_files['js']) + args.js_path[0], utility_files['js']) if args.build_py: - copy_boilerplate_selective( + copy_files_list( os.path.join(dir_path, "boilerplate/py"), - args.py_path[0], frame_parser_files['py']) + args.py_path[0], utility_files['py']) if args.build_cpp: - copy_boilerplate_selective( + copy_files_list( os.path.join(dir_path, "boilerplate/cpp"), - args.cpp_path[0], frame_parser_files['cpp']) + args.cpp_path[0], utility_files['cpp']) else: - # Copy all boilerplate files (default behavior) + # Copy essential boilerplate files (default behavior) if (args.build_c): - shutil.copytree(os.path.join(dir_path, "boilerplate/c"), - args.c_path[0], dirs_exist_ok=True) + copy_files_list( + os.path.join(dir_path, "boilerplate/c"), + args.c_path[0], essential_files['c']) if (args.build_ts): - shutil.copytree(os.path.join(dir_path, "boilerplate/ts"), - args.ts_path[0], dirs_exist_ok=True) + copy_files_list( + os.path.join(dir_path, "boilerplate/ts"), + args.ts_path[0], essential_files['ts']) if (args.build_js): - shutil.copytree(os.path.join(dir_path, "boilerplate/js"), - args.js_path[0], dirs_exist_ok=True) + copy_files_list( + os.path.join(dir_path, "boilerplate/js"), + args.js_path[0], essential_files['js']) if (args.build_py): - shutil.copytree(os.path.join(dir_path, "boilerplate/py"), - args.py_path[0], dirs_exist_ok=True) + copy_files_list( + os.path.join(dir_path, "boilerplate/py"), + args.py_path[0], essential_files['py']) if (args.build_cpp): - shutil.copytree(os.path.join(dir_path, "boilerplate/cpp"), - args.cpp_path[0], dirs_exist_ok=True) + copy_files_list( + os.path.join(dir_path, "boilerplate/cpp"), + args.cpp_path[0], essential_files['cpp']) # No boilerplate for GraphQL currently diff --git a/tests/c/test_arrays.c b/tests/c/test_arrays.c index 8cd4b13b..308a3e10 100644 --- a/tests/c/test_arrays.c +++ b/tests/c/test_arrays.c @@ -3,7 +3,7 @@ #include #include "comprehensive_arrays.sf.h" -#include "basic_frame.h" +#include "frame_parsers_gen.h" void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { printf("\n"); @@ -74,21 +74,19 @@ int test_array_operations() { // Encode message into BasicFrame format uint8_t encode_buffer[1024]; - basic_frame_encode_buffer_t buffer; - basic_frame_encode_init(&buffer, encode_buffer, sizeof(encode_buffer)); + size_t encoded_size = basic_frame_encode(encode_buffer, sizeof(encode_buffer), + COMPREHENSIVE_ARRAYS_COMPREHENSIVE_ARRAY_MESSAGE_MSG_ID, + (const uint8_t*)&msg, COMPREHENSIVE_ARRAYS_COMPREHENSIVE_ARRAY_MESSAGE_MAX_SIZE); - bool encoded = basic_frame_encode_msg(&buffer, COMPREHENSIVE_ARRAYS_COMPREHENSIVE_ARRAY_MESSAGE_MSG_ID, - &msg, COMPREHENSIVE_ARRAYS_COMPREHENSIVE_ARRAY_MESSAGE_MAX_SIZE); - - if (!encoded) { + if (encoded_size == 0) { print_failure_details("Encoding failed", NULL, 0); return 0; } // Validate and decode the BasicFrame - basic_frame_msg_info_t decode_result = basic_frame_validate_packet(encode_buffer, buffer.size); + frame_msg_info_t decode_result = basic_frame_validate_packet(encode_buffer, encoded_size); if (!decode_result.valid) { - print_failure_details("Validation failed", encode_buffer, buffer.size); + print_failure_details("Validation failed", encode_buffer, encoded_size); return 0; } @@ -97,22 +95,22 @@ int test_array_operations() { // Compare original and decoded messages if (decoded_msg->fixed_ints[0] != msg.fixed_ints[0]) { - print_failure_details("Value mismatch: fixed_ints[0]", encode_buffer, buffer.size); + print_failure_details("Value mismatch: fixed_ints[0]", encode_buffer, encoded_size); return 0; } if (decoded_msg->bounded_uints.count != msg.bounded_uints.count) { - print_failure_details("Value mismatch: bounded_uints.count", encode_buffer, buffer.size); + print_failure_details("Value mismatch: bounded_uints.count", encode_buffer, encoded_size); return 0; } if (decoded_msg->bounded_uints.data[0] != msg.bounded_uints.data[0]) { - print_failure_details("Value mismatch: bounded_uints.data[0]", encode_buffer, buffer.size); + print_failure_details("Value mismatch: bounded_uints.data[0]", encode_buffer, encoded_size); return 0; } if (decoded_msg->fixed_sensors[0].id != msg.fixed_sensors[0].id) { - print_failure_details("Value mismatch: fixed_sensors[0].id", encode_buffer, buffer.size); + print_failure_details("Value mismatch: fixed_sensors[0].id", encode_buffer, encoded_size); return 0; } diff --git a/tests/c/test_basic_types.c b/tests/c/test_basic_types.c index 1b2c01c5..4a8f00c8 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 "basic_frame.h" +#include "frame_parsers_gen.h" void print_failure_details(const char* label, const BasicTypesBasicTypesMessage* expected, const BasicTypesBasicTypesMessage* actual, @@ -61,21 +61,19 @@ int test_basic_types() { // Encode message into BasicFrame format uint8_t encode_buffer[1024]; - basic_frame_encode_buffer_t buffer; - basic_frame_encode_init(&buffer, encode_buffer, sizeof(encode_buffer)); + size_t encoded_size = basic_frame_encode(encode_buffer, sizeof(encode_buffer), + BASIC_TYPES_BASIC_TYPES_MESSAGE_MSG_ID, + (const uint8_t*)&msg, BASIC_TYPES_BASIC_TYPES_MESSAGE_MAX_SIZE); - bool encoded = basic_frame_encode_msg(&buffer, BASIC_TYPES_BASIC_TYPES_MESSAGE_MSG_ID, - &msg, BASIC_TYPES_BASIC_TYPES_MESSAGE_MAX_SIZE); - - if (!encoded) { + if (encoded_size == 0) { print_failure_details("Encoding failed", &msg, NULL, NULL, 0); return 0; } // Validate and decode the BasicFrame - basic_frame_msg_info_t decode_result = basic_frame_validate_packet(encode_buffer, buffer.size); + frame_msg_info_t decode_result = basic_frame_validate_packet(encode_buffer, encoded_size); if (!decode_result.valid) { - print_failure_details("Validation failed", &msg, NULL, encode_buffer, buffer.size); + print_failure_details("Validation failed", &msg, NULL, encode_buffer, encoded_size); return 0; } @@ -83,22 +81,22 @@ int test_basic_types() { // Compare original and decoded messages if (decoded_msg->small_int != msg.small_int) { - print_failure_details("Value mismatch: small_int", &msg, decoded_msg, encode_buffer, buffer.size); + print_failure_details("Value mismatch: small_int", &msg, decoded_msg, encode_buffer, encoded_size); return 0; } if (decoded_msg->medium_int != msg.medium_int) { - print_failure_details("Value mismatch: medium_int", &msg, decoded_msg, encode_buffer, buffer.size); + print_failure_details("Value mismatch: medium_int", &msg, decoded_msg, encode_buffer, encoded_size); return 0; } if (decoded_msg->flag != msg.flag) { - print_failure_details("Value mismatch: flag", &msg, decoded_msg, encode_buffer, buffer.size); + print_failure_details("Value mismatch: flag", &msg, decoded_msg, encode_buffer, encoded_size); return 0; } if (decoded_msg->single_precision != msg.single_precision) { - print_failure_details("Value mismatch: single_precision", &msg, decoded_msg, encode_buffer, buffer.size); + print_failure_details("Value mismatch: single_precision", &msg, decoded_msg, encode_buffer, encoded_size); return 0; } diff --git a/tests/c/test_cross_platform_deserialization.c b/tests/c/test_cross_platform_deserialization.c index b196aa3f..0add2ff4 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 "basic_frame.h" +#include "frame_parsers_gen.h" void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { printf("\n"); @@ -83,7 +83,7 @@ int read_and_validate_test_data(const char* filename) { return 0; } - basic_frame_msg_info_t decode_result = basic_frame_validate_packet(buffer, size); + frame_msg_info_t decode_result = basic_frame_validate_packet(buffer, size); if (!decode_result.valid) { print_failure_details("Failed to decode data", buffer, size); diff --git a/tests/c/test_cross_platform_serialization.c b/tests/c/test_cross_platform_serialization.c index c70ff61f..2dd26e76 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 "basic_frame.h" +#include "frame_parsers_gen.h" void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { printf("\n"); @@ -38,13 +38,11 @@ int create_test_data() { msg.test_array.data[2] = 300; uint8_t encode_buffer[512]; - basic_frame_encode_buffer_t buffer; - basic_frame_encode_init(&buffer, encode_buffer, sizeof(encode_buffer)); + size_t encoded_size = basic_frame_encode(encode_buffer, sizeof(encode_buffer), + SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, + (const uint8_t*)&msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE); - bool encoded = basic_frame_encode_msg(&buffer, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, - &msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE); - - if (!encoded) { + if (encoded_size == 0) { print_failure_details("Encoding failed", NULL, 0); return 0; } @@ -55,13 +53,13 @@ int create_test_data() { return 0; } - fwrite(encode_buffer, 1, buffer.size, file); + fwrite(encode_buffer, 1, encoded_size, file); fclose(file); // Self-validate - basic_frame_msg_info_t decode_result = basic_frame_validate_packet(encode_buffer, buffer.size); + frame_msg_info_t decode_result = basic_frame_validate_packet(encode_buffer, encoded_size); if (!decode_result.valid) { - print_failure_details("Self-validation failed", encode_buffer, buffer.size); + print_failure_details("Self-validation failed", encode_buffer, encoded_size); return 0; } @@ -69,7 +67,7 @@ int create_test_data() { (SerializationTestSerializationTestMessage*)decode_result.msg_data; if (decoded_msg->magic_number != 3735928559 || decoded_msg->test_array.count != 3) { - print_failure_details("Self-verification failed", encode_buffer, buffer.size); + print_failure_details("Self-verification failed", encode_buffer, encoded_size); return 0; } diff --git a/tests/cpp/test_arrays.cpp b/tests/cpp/test_arrays.cpp index 93b6b270..6d45e091 100644 --- a/tests/cpp/test_arrays.cpp +++ b/tests/cpp/test_arrays.cpp @@ -1,5 +1,5 @@ #include "comprehensive_arrays.sf.hpp" -#include "basic_frame.hpp" +#include "frame_parsers_gen.hpp" #include #include @@ -27,7 +27,7 @@ int main() { // Encode message into BasicFrame format uint8_t buffer[1024]; - StructFrame::BasicFrameEncodeBuffer encoder(buffer, sizeof(buffer)); + FrameParsers::BasicFrameEncodeBuffer encoder(buffer, sizeof(buffer)); if (!encoder.encode(COMPREHENSIVE_ARRAYS_COMPREHENSIVE_ARRAY_MESSAGE_MSG_ID, &msg, COMPREHENSIVE_ARRAYS_COMPREHENSIVE_ARRAY_MESSAGE_MAX_SIZE)) { diff --git a/tests/cpp/test_basic_types.cpp b/tests/cpp/test_basic_types.cpp index 2d0e9d71..338c5ca7 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 "basic_frame.hpp" +#include "frame_parsers_gen.hpp" #include #include @@ -44,7 +44,7 @@ int main() { // Encode message into BasicFrame format uint8_t buffer[512]; - StructFrame::BasicFrameEncodeBuffer encoder(buffer, sizeof(buffer)); + FrameParsers::BasicFrameEncodeBuffer encoder(buffer, sizeof(buffer)); if (!encoder.encode(BASIC_TYPES_BASIC_TYPES_MESSAGE_MSG_ID, &msg, BASIC_TYPES_BASIC_TYPES_MESSAGE_MAX_SIZE)) { diff --git a/tests/cpp/test_cross_platform_deserialization.cpp b/tests/cpp/test_cross_platform_deserialization.cpp index 02188229..98b18874 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 "basic_frame.hpp" +#include "frame_parsers_gen.hpp" void print_failure_details(const char* label) { std::cout << "\n============================================================\n"; @@ -77,7 +77,7 @@ bool read_and_validate_test_data(const char* filename) { return false; } - StructFrame::BasicFrameMsgInfo decode_result = StructFrame::basic_frame_validate_packet(buffer, size); + FrameParsers::FrameMsgInfo decode_result = FrameParsers::basic_frame_validate_packet(buffer, size); if (!decode_result.valid) { print_failure_details("Failed to decode data"); diff --git a/tests/cpp/test_cross_platform_serialization.cpp b/tests/cpp/test_cross_platform_serialization.cpp index 592dc2dd..fa407aed 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 "basic_frame.hpp" +#include "frame_parsers_gen.hpp" #include #include #include @@ -27,7 +27,7 @@ int main() { msg.test_array.data[2] = 300; uint8_t buffer[512]; - StructFrame::BasicFrameEncodeBuffer encoder(buffer, sizeof(buffer)); + FrameParsers::BasicFrameEncodeBuffer encoder(buffer, sizeof(buffer)); if (!encoder.encode(SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, &msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE)) { diff --git a/tests/py/test_cross_platform_deserialization.py b/tests/py/test_cross_platform_deserialization.py index d5f4c94e..daf20847 100644 --- a/tests/py/test_cross_platform_deserialization.py +++ b/tests/py/test_cross_platform_deserialization.py @@ -116,13 +116,12 @@ def read_and_validate_test_data(filename): sys.path.insert(0, '../generated/py') from serialization_test_sf import SerializationTestSerializationTestMessage - from struct_frame_parser import BasicFrame + from frame_parsers_gen import BasicFrame # Validate and decode using BasicFrame - basic_frame = BasicFrame() - result = basic_frame.validate_packet(list(binary_data)) + result = BasicFrame.validate_packet(list(binary_data)) - if not result or not result['valid']: + if not result.valid: print_failure_details( "Failed to decode data", expected_values={"decoded_message": "valid"}, @@ -132,7 +131,7 @@ def read_and_validate_test_data(filename): return False # Decode the message data - msg_data = bytes(result['msg_data']) + msg_data = bytes(result.msg_data) decoded_msg = SerializationTestSerializationTestMessage.create_unpack(msg_data) # Load expected values and validate