Files
templates/c/set-protocol/include/pcan_id.h
T

109 lines
6.6 KiB
C

/*
* Явная упаковка полей в 29-битный идентификатор ProtoCAN и их извлечение. Маски и сдвиги
* задают переносимый wire-формат без зависимости от расположения битовых полей компилятора.
*/
/**
* @file pcan_id.h
* @brief Упаковка и разбор 29-битного идентификатора ProtoCAN.
*
* Раскладка (ProtoCanId_t из ports/stm32-bxcan/protocan.h, бывший SETCAN):
*
* биты 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_GAS_SLOT = 0x4U, /**< Слотный GAS с маской слов; код 0x4 освобождён от Modbus Coil. */
PCAN_MSG_MODBUS = 0x5U, /**< Единый Modbus; банк выбирается функцией 1…4 в MsgBody, коды 0x6/0x7 свободны. */
PCAN_MSG_ERROR = 0x8U,
PCAN_MSG_PULSE = 0xFU
} pcan_msgtype_t;
/** Разобранный идентификатор. */
typedef struct {
uint16_t msg_body;
uint_least8_t msg_type; /**< pcan_msgtype_t */ /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
uint_least8_t device_id; /**< 0..15 */ /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
uint_least8_t device_type; /**< 0..7 */ /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
uint_least8_t route; /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
uint_least8_t priority; /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
} 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, uint_least8_t body) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
{
return (uint16_t)(((type & 0x0FFFU) << 4) | (body & 0x0FU));
}
/** DISCRETE / ANALOG: Type[15:12], Body[11:0]. */
static inline uint16_t pcan_body_typed(uint_least8_t type, uint16_t body) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
{
return (uint16_t)(((uint16_t)(type & 0x0FU) << 12) | (body & 0x0FFFU));
}
/** MODBUS: StrAdr[15:4], Function-1[3:2], RegCount-1[1:0]; вызывающий проверяет адрес 0…4095 и значения 1…4. */
static inline uint16_t pcan_body_modbus(uint16_t addr, uint_least8_t count, uint_least8_t function) /* Два двухбитных поля кодируют четыре функции и четыре количества без потери 12-битного адреса. */
{ /* Упаковка применяется после проверки диапазонов параметров на стороне клиента. */
return (uint16_t)(((addr & 0x0FFFU) << 4) | (((function - 1U) & 3U) << 2) | ((count - 1U) & 3U)); /* 0xFFF ограничивает адрес 12 битами; смещение на единицу переводит значения 1…4 в wire-коды 0…3. */
} /* Конец упаковки единого Modbus типа 0x5. */
static inline uint_least8_t pcan_modbus_count(uint16_t body) /* Возвращает физическое количество регистров или битов из двух младших битов Body. */
{ /* Каждый двухбитный wire-код имеет допустимое значение. */
return (uint_least8_t)((body & 3U) + 1U); /* Маска 3 выделяет биты 1:0; прибавление единицы восстанавливает диапазон 1…4. */
} /* Конец извлечения количества. */
static inline uint_least8_t pcan_modbus_function(uint16_t body) /* Возвращает номер функции: Coil=1, Discrete=2, Holding=3, Input=4. */
{ /* Функция занимает два бита между адресом и количеством. */
return (uint_least8_t)(((body >> 2) & 3U) + 1U); /* Сдвиг выделяет биты 3:2; wire-коды 0…3 соответствуют функциям 1…4. */
} /* Конец извлечения функции. */
/** ERROR: Info[15:8], Code[7:0]. */
static inline uint16_t pcan_body_error(uint_least8_t info, uint_least8_t code) /* На C28x хранит октет в доступном 16-битном типе; допустимые значения поля и host ABI остаются прежними. */
{
return (uint16_t)(((uint16_t)info << 8) | code);
}
#ifdef __cplusplus
}
#endif
#endif /* PCAN_ID_H */