Files
templates/c/protocan-transport/include/pcan_frame.h
Andrey Kruchinkin 3dc636e012 feat(protocan-transport): транспортный уровень ProtoCAN и каталог GUI
Перенесён из репозитория protocan-transport, который подключался
сабмодулем в CAN_to_RS485.

Кадрирование AA 55 с CRC16 поверх любого байтового потока (RS485, RS232,
USB CDC), разбор 29-битного идентификатора, общее адресное пространство
регистров и каталог с подпиской на поток значений для SETGUI. Состояние
живёт в структурах вызывающего, поэтому в одной прошивке поднимается
сколько угодно независимых каналов. Порт STM32F4 (USART + DMA) в комплекте.

Хостовые тесты test_transport и test_gui проходят.
2026-08-23 01:15:35 +03:00

114 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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 */