Перенесён из репозитория protocan-transport, который подключался сабмодулем в CAN_to_RS485. Кадрирование AA 55 с CRC16 поверх любого байтового потока (RS485, RS232, USB CDC), разбор 29-битного идентификатора, общее адресное пространство регистров и каталог с подпиской на поток значений для SETGUI. Состояние живёт в структурах вызывающего, поэтому в одной прошивке поднимается сколько угодно независимых каналов. Порт STM32F4 (USART + DMA) в комплекте. Хостовые тесты test_transport и test_gui проходят.
96 lines
2.9 KiB
C
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 */
|