84 lines
4.3 KiB
C
84 lines
4.3 KiB
C
/* 信息对象与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 */
|
||
|