109 lines
6.6 KiB
C
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 */
|