Files
STM32F4-Base/IEC60870-Slave/common/IEC60870_InformationObjects_Internal.h
T
STF 4c55544f05
CI / L0 静态门禁 (pre-commit) (push) Failing after 45s
CI / L0.5 主机侧单测 (MSVC) (push) Failing after 42s
通信协议代码
2026-10-26 08:31:48 -04:00

84 lines
4.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 信息对象与ASDU的内部协作,不作为业务API。
* ASDU使用类型描述计算布局;具体对象通过只读函数表编码;解码按Type ID另行分派。
* 字节辅助函数不读写连接状态,也不依赖结构体对齐或主机字节序。 */
#ifndef IEC60870_INFORMATION_OBJECTS_INTERNAL_H
#define IEC60870_INFORMATION_OBJECTS_INTERNAL_H
#include "IEC60870_InformationObjects.h"
/* 单个文件段LOS最多255字节,另有4字节文件段头和最多3字节IOA。
* 即使对象可表示更长载荷,ASDU容器仍按配置的总长上限返回FULL。 */
#define IEC60870_OBJECT_MAX_PAYLOAD 259U
#define IEC60870_OBJECT_MAX_ENCODED (IEC60870_OBJECT_MAX_PAYLOAD + 3U)
/* 每个类型独立的只读编码函数表;解码仍由Type ID选择具体类型的解析函数。
* encode仅写临时载荷,公共入口验证后原子提交;变长类型提供两个长度回调。 */
typedef struct IEC60870_InformationObjectVTable {
uint8_t type_id; /* 线上类型标识;同时用于核对对象基类身份。 */
uint16_t payload_size; /* 固定类型的精确长度;变长类型的最低长度,不含IOA。 */
uint8_t single_object; /* 1表示仅允许一个对象;SQ约束由supports_sequence独立决定。 */
size_t object_size; /* 具体C结构的sizeof,用于输出存储检查,与线上长度无关。 */
int (*encode)(const IEC60870_InformationObject_t *object, uint8_t *payload); /* 写临时载荷,1成功/0字段非法。 */
uint8_t supports_sequence; /* 1允许SQ=1;参数类型允许多个对象但仅支持SQ=0。 */
uint16_t (*get_payload_size)(const IEC60870_InformationObject_t *object); /* NULL为固定长度。 */
uint16_t (*get_payload_size_from_buffer)(const uint8_t *payload, uint16_t length); /* 变长载荷精确长度;0非法。 */
} IEC60870_InformationObjectVTable;
/* 未支持的Type ID返回NULL;地址和长度校验由使用方在读报文前完成。 */
const IEC60870_InformationObjectVTable *IEC60870_InformationObject_Get_Descriptor(uint8_t type_id);
/* 按Type ID调用具体Get_From_Buffer;object==NULL时仅验证,不输出。
* object_size是调用方实际提供的容量,必须至少为所选具体类型的sizeof;
* 非空object必须对应该具体结构,尺寸足够不能替代类型匹配。失败不修改输出。 */
IEC60870_AsduResult_t IEC60870_InformationObject_Decode(uint8_t type_id, uint32_t ioa,
const uint8_t *payload, uint16_t length, void *object, size_t object_size);
/**
* 功能:从低字节在前的字节序列读取无符号值。
* 输入参数:data——至少length字节的有效输入,调用方先完成边界检查。
* length——1..4,用于1/2/3字节地址或2/4字节数值。
* 输出参数:无。
* 返回值:按位拼接的uint32_t,未使用高位为0。
* 说明:逐字节读,允许未对齐输入;不检查指针或范围。
*/
static inline uint32_t IEC60870_Object_Read_LE(const uint8_t *data, unsigned int length)
{
uint32_t value = 0;
unsigned int i;
for (i = 0; i < length; ++i) {
value |= (uint32_t)data[i] << (8U * i);
}
return value;
}
/**
* 功能:将数值低length字节按低字节在前写入报文。
* 输入参数:value——待写数值;需要保留的高位是否越界由调用方预先检查。
* length——1..4;只写指定字节数,不写尾部填充。
* 输出参数:data——至少length字节的可写区域。
* 返回值:无。
* 说明:逐字节写,不要求对齐;IOA必须先按所选宽度校验,防止被静默截断。
*/
static inline void IEC60870_Object_Write_LE(uint8_t *data, uint32_t value, unsigned int length)
{
unsigned int i;
for (i = 0; i < length; ++i) {
data[i] = (uint8_t)(value >> (8U * i));
}
}
/**
* 功能:计算所选IOA字段宽度能够表示的最大地址。
* 输入参数:parameters——非空且已通过AppLayerParameters_Valid校验,sizeOfIOA为1..3。
* 输出参数:无。
* 返回值:分别为0xFF、0xFFFF或0xFFFFFF。
* 说明:位移最多24位;本函数不检查参数,非法宽度不得传入。
*/
static inline uint32_t IEC60870_Object_Max_IOA(const IEC60870_AppLayerParameters_t *parameters)
{
return (UINT32_C(1) << (8U * (unsigned int)parameters->sizeOfIOA)) - 1U;
}
#endif /* IEC60870_INFORMATION_OBJECTS_INTERNAL_H */