Files
templates/c/protocan-transport/include/pcan_id.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

96 lines
2.9 KiB
C

/**
* @file pcan_id.h
* @brief Упаковка и разбор 29-битного идентификатора ProtoCAN.
*
* Раскладка (соответствует ProtoCanId_t из SETCAN/Inc/protocan.h):
*
* биты 28 Priority
* 27 Route
* 26:24 DeviceType
* 23:20 DeviceID
* 19:16 MsgType
* 15:0 MsgBody
*
* Здесь намеренно не используются битовые поля: их раскладка в C
* определяется реализацией, и один и тот же заголовок на другом
* компиляторе может дать другой порядок. Сдвиги переносимы всегда.
*/
#ifndef PCAN_ID_H
#define PCAN_ID_H
#include <stdint.h>
#include "pcan_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PCAN_ID_MASK 0x1FFFFFFFUL
/* --- Приоритет и маршрут --------------------------------------------------- */
#define PCAN_PRIORITY_CRITICAL 0U
#define PCAN_PRIORITY_STANDARD 1U
#define PCAN_ROUTE_FROM_PM 0U
#define PCAN_ROUTE_FROM_DEVICE 1U
/* --- Типы сообщений -------------------------------------------------------- */
typedef enum {
PCAN_MSG_BROADCAST = 0x0U,
PCAN_MSG_DISCRETE = 0x1U,
PCAN_MSG_ANALOG = 0x2U,
PCAN_MSG_GAS = 0x3U, /**< общее адресное пространство */
PCAN_MSG_MODBUS_COIL = 0x4U,
PCAN_MSG_MODBUS_DISCR = 0x5U,
PCAN_MSG_MODBUS_HOLDING = 0x6U,
PCAN_MSG_MODBUS_INPUT = 0x7U,
PCAN_MSG_ERROR = 0x8U,
PCAN_MSG_PULSE = 0xFU
} pcan_msgtype_t;
/** Разобранный идентификатор. */
typedef struct {
uint16_t msg_body;
uint8_t msg_type; /**< pcan_msgtype_t */
uint8_t device_id; /**< 0..15 */
uint8_t device_type; /**< 0..7 */
uint8_t route;
uint8_t priority;
} pcan_id_t;
uint32_t pcan_id_pack(const pcan_id_t *id);
void pcan_id_unpack(uint32_t raw, pcan_id_t *id);
/* --- Раскладки MsgBody ----------------------------------------------------- */
/** BROADCAST: Type[15:4], Body[3:0]. */
static inline uint16_t pcan_body_broadcast(uint16_t type, uint8_t body)
{
return (uint16_t)(((type & 0x0FFFU) << 4) | (body & 0x0FU));
}
/** DISCRETE / ANALOG: Type[15:12], Body[11:0]. */
static inline uint16_t pcan_body_typed(uint8_t type, uint16_t body)
{
return (uint16_t)(((uint16_t)(type & 0x0FU) << 12) | (body & 0x0FFFU));
}
/** MODBUS: StrAdr[15:4], RegCount[3:0]. */
static inline uint16_t pcan_body_modbus(uint16_t addr, uint8_t count)
{
return (uint16_t)(((addr & 0x0FFFU) << 4) | (count & 0x0FU));
}
/** ERROR: Info[15:8], Code[7:0]. */
static inline uint16_t pcan_body_error(uint8_t info, uint8_t code)
{
return (uint16_t)(((uint16_t)info << 8) | code);
}
#ifdef __cplusplus
}
#endif
#endif /* PCAN_ID_H */