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 проходят.
This commit is contained in:
113
c/protocan-transport/include/pcan_frame.h
Normal file
113
c/protocan-transport/include/pcan_frame.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @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 */
|
||||
Reference in New Issue
Block a user