/** * @file pcan_frame.h * @brief Транспортный кадр и потоковый разборщик. * * AA 55 | LEN | SEQ | FLAGS | ID0 ID1 ID2 ID3 | DATA[0..8] | CRC_L CRC_H * * LEN = 6 + DLC (длина участка SEQ..DATA), диапазон 6..14 * CRC = CRC-16/CCITT-FALSE по байтам LEN..DATA, little-endian * * Кадр самосинхронизирующийся: при мусоре в линии разборщик сдвигается * на байт и продолжает искать сигнатуру, теряя не больше одного кадра. * * Формат не зависит ни от платформы, ни от физического уровня: он одинаково * ложится на RS485, RS232, USB CDC и любой байтовый поток. */ #ifndef PCAN_FRAME_H #define PCAN_FRAME_H #include #include #include #include "pcan_config.h" #ifdef __cplusplus extern "C" { #endif #define PCAN_SOF0 0xAAU #define PCAN_SOF1 0x55U /** Расширенный (29-битный) идентификатор. */ #define PCAN_FLAG_IDE 0x01U /** Remote frame. */ #define PCAN_FLAG_RTR 0x02U /** 0: кадр пришёл из CAN; 1: кадр надо передать в CAN. */ #define PCAN_FLAG_DIR 0x04U /** Служебный кадр моста (диагностика), не относится к трафику CAN. */ #define PCAN_FLAG_ERR 0x08U #define PCAN_LEN_MIN 6U #define PCAN_LEN_MAX (PCAN_LEN_MIN + PCAN_DATA_MAX) /** SOF(2) + LEN(1) + LEN_MAX + CRC(2). */ #define PCAN_FRAME_MAX (PCAN_LEN_MAX + 5U) /** Разобранный кадр. */ typedef struct { uint8_t seq; uint8_t flags; uint32_t id; /**< 29-битный идентификатор */ uint8_t dlc; uint8_t data[PCAN_DATA_MAX]; } pcan_frame_t; /** * @brief Сериализует кадр. * @param out буфер приёмника; * @param out_size его размер, нужно не меньше PCAN_FRAME_MAX; * @return число записанных байт либо 0, если буфер мал. */ size_t pcan_frame_encode(const pcan_frame_t *frame, uint8_t *out, size_t out_size); /* --- Потоковый разборщик -------------------------------------------------- */ typedef enum { PCAN_ST_SOF0 = 0, PCAN_ST_SOF1, PCAN_ST_LEN, PCAN_ST_BODY, PCAN_ST_CRC_L, PCAN_ST_CRC_H } pcan_parse_state_t; /** Счётчики разборщика: полезны для диагностики линии. */ typedef struct { uint32_t frames; /**< успешно разобрано кадров */ uint32_t crc_errors; /**< кадров отброшено по CRC */ uint32_t bad_len; /**< LEN вне допустимого диапазона */ uint32_t stray_bytes; /**< байт отброшено вне кадров */ } pcan_parse_stats_t; typedef struct { pcan_parse_state_t state; uint8_t len; uint8_t idx; uint8_t body[PCAN_LEN_MAX + 1U]; /**< LEN + участок SEQ..DATA */ uint16_t crc_rx; pcan_parse_stats_t stats; } pcan_parser_t; void pcan_parser_init(pcan_parser_t *p); /** * @brief Скармливает разборщику один байт. * @return true, если кадр собран целиком и записан в out. */ bool pcan_parser_push(pcan_parser_t *p, uint8_t byte, pcan_frame_t *out); /** Колбэк на готовый кадр. */ typedef void (*pcan_frame_cb_t)(const pcan_frame_t *frame, void *user); /** * @brief Скармливает разборщику блок байт, вызывая cb на каждый кадр. * @return число разобранных кадров. */ size_t pcan_parser_feed(pcan_parser_t *p, const uint8_t *data, size_t len, pcan_frame_cb_t cb, void *user); #ifdef __cplusplus } #endif #endif /* PCAN_FRAME_H */