7353 lines
366 KiB
C
7353 lines
366 KiB
C
/*
|
||
* 信息对象的具体实现。每个类型分别定义值编解码、只读编码函数表及公开构造/解析入口。
|
||
* 带CP24/CP56的普通监视和控制对象复用基础值处理;保护事件另处理CP16和QDP。
|
||
* 公共入口先在局部对象/字节数组中完成验证,成功后才写回调用方存储。
|
||
*/
|
||
#include "IEC60870_InformationObjects_Internal.h"
|
||
#include "IEC60870_Codec.h"
|
||
|
||
#include <float.h>
|
||
#include <limits.h>
|
||
#include <string.h>
|
||
|
||
_Static_assert(CHAR_BIT == 8, "IEC60870 requires 8-bit bytes");
|
||
_Static_assert(sizeof(float) == 4 && FLT_RADIX == 2 && FLT_MANT_DIG == 24 &&
|
||
FLT_MAX_EXP == 128, "IEC60870 short float requires IEEE 754 binary32");
|
||
|
||
/**
|
||
* 功能:按低字节在前读取16位补码值,用于归一化和标度值。
|
||
* 输入参数:data——至少2字节的有效输入;调用方已验证长度。
|
||
* 输出参数:无。
|
||
* 返回值:-32768..32767范围内的int16_t值。
|
||
* 说明:先扩展到int32_t再减65536恢复负值,避免越界无符号到有符号转换。
|
||
*/
|
||
static int16_t Read_I16(const uint8_t *data)
|
||
{
|
||
uint32_t raw = IEC60870_Object_Read_LE(data, 2);
|
||
return (int16_t)(raw < 0x8000U ? (int32_t)raw : (int32_t)raw - 65536);
|
||
}
|
||
|
||
/**
|
||
* 功能:按低字节在前读取32位补码累计值。
|
||
* 输入参数:data——至少4字节的有效输入;调用方已验证长度。
|
||
* 输出参数:无。
|
||
* 返回值:完整int32_t范围内的计数值,包括INT32_MIN。
|
||
* 说明:负数通过低31位减去2^31恢复,每一步运算均在int32_t范围内。
|
||
*/
|
||
static int32_t Read_I32(const uint8_t *data)
|
||
{
|
||
uint32_t raw = IEC60870_Object_Read_LE(data, 4);
|
||
return raw <= INT32_MAX ? (int32_t)raw :
|
||
(int32_t)(raw & UINT32_C(0x7FFFFFFF)) - INT32_MAX - 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将4字节报文恢复为float位模式。
|
||
* 输入参数:data——至少4字节的有效输入,低字节在前。
|
||
* 输出参数:value——非空float对象,保存解码后的IEEE 754 binary32位模式。
|
||
* 返回值:无。
|
||
* 说明:memcpy避免未对齐访问和指针别名问题,不进行浮点运算或NaN/Inf过滤。
|
||
*/
|
||
static void Read_Float(const uint8_t *data, float *value)
|
||
{
|
||
uint32_t bits = IEC60870_Object_Read_LE(data, 4);
|
||
memcpy(value, &bits, sizeof(bits));
|
||
}
|
||
|
||
/**
|
||
* 功能:将float位模式编码为低字节在前的4字节载荷。
|
||
* 输入参数:value——非空float指针,按位复制,不作浮点到整数的数值转换。
|
||
* 输出参数:data——至少4字节的可写空间。
|
||
* 返回值:无。
|
||
* 说明:先用memcpy取得uint32_t位表示,再按协议字节序写入。
|
||
*/
|
||
static void Write_Float(uint8_t *data, const float *value)
|
||
{
|
||
uint32_t bits;
|
||
memcpy(&bits, value, sizeof(bits));
|
||
IEC60870_Object_Write_LE(data, bits, 4);
|
||
}
|
||
|
||
/**
|
||
* 功能:初始化具体对象中的公共基类身份。
|
||
* 输入参数:ioa——已验证为0..0xFFFFFF的信息对象地址。
|
||
* vtable——与具体结构匹配的非空静态只读函数表。
|
||
* 输出参数:object——非空公共基类首成员;此函数只填写地址、类型和函数表。
|
||
* 返回值:无。
|
||
* 说明:对象仅借用永久有效的函数表;不分配内存,不保留请求或连接状态。
|
||
*/
|
||
static void Initialize_Object(IEC60870_InformationObject_t *object, uint32_t ioa,
|
||
const IEC60870_InformationObjectVTable *vtable)
|
||
{
|
||
object->ioa = ioa;
|
||
object->type_id = vtable->type_id;
|
||
object->virtual_function_table = vtable;
|
||
}
|
||
|
||
/* ---- Type 1:单点信息 ---- */
|
||
/**
|
||
* 功能:编码Type 1(单点信息)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SIQ(1):bit0为单点状态,bit1..3为保留位,高4位为品质。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SinglePointInformation_Encode_Value(const IEC60870_SinglePointInformation_t *self, uint8_t *payload)
|
||
{
|
||
/* SIQ/DIQ仅允许高4位品质,点状态分别占1/2位。 */
|
||
if (self->value > 1U || (self->quality & 0x0FU) != 0U) { return 0; }
|
||
payload[0] = (uint8_t)(self->value | self->quality);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 1(单点信息)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SIQ(1):bit0为单点状态,bit1..3为保留位,高4位为品质。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SinglePointInformation_Decode_Value(const uint8_t *payload, IEC60870_SinglePointInformation_t *self)
|
||
{
|
||
if ((payload[0] & 0x0EU) != 0U) { return 0; }
|
||
self->value = payload[0] & 1U;
|
||
self->quality = payload[0] & 0xF0U;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 1编码函数表的适配入口,将公共基类还原为SinglePointInformation对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SinglePointInformation_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SinglePointInformation_Encode_Value((const IEC60870_SinglePointInformation_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SinglePointInformation_VTable = {
|
||
1, 1, 0, sizeof(IEC60870_SinglePointInformation_t), SinglePointInformation_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 1(单点信息)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——单点状态,0或1。
|
||
* quality——品质仅允许BL/SB/NT/IV(0xF0范围内的位),不得夹带状态或保留位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SinglePointInformation_Create(IEC60870_SinglePointInformation_t *self,
|
||
uint32_t ioa, int value, int quality)
|
||
{
|
||
IEC60870_SinglePointInformation_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
value < 0 || value > 1 ||
|
||
quality < 0 || quality > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = (uint8_t)value;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &SinglePointInformation_VTable);
|
||
if (!SinglePointInformation_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 1(单点信息)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SinglePointInformation_Get_From_Buffer(IEC60870_SinglePointInformation_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SinglePointInformation_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SinglePointInformation_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &SinglePointInformation_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 3:双点信息 ---- */
|
||
/**
|
||
* 功能:编码Type 3(双点信息)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:DIQ(1):低2位为双点状态,bit2..3为保留位,高4位为品质。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int DoublePointInformation_Encode_Value(const IEC60870_DoublePointInformation_t *self, uint8_t *payload)
|
||
{
|
||
/* SIQ/DIQ仅允许高4位品质,点状态分别占1/2位。 */
|
||
if (self->value > 3U || (self->quality & 0x0FU) != 0U) { return 0; }
|
||
payload[0] = (uint8_t)(self->value | self->quality);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 3(双点信息)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:DIQ(1):低2位为双点状态,bit2..3为保留位,高4位为品质。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int DoublePointInformation_Decode_Value(const uint8_t *payload, IEC60870_DoublePointInformation_t *self)
|
||
{
|
||
if ((payload[0] & 0x0CU) != 0U) { return 0; }
|
||
self->value = payload[0] & 3U;
|
||
self->quality = payload[0] & 0xF0U;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 3编码函数表的适配入口,将公共基类还原为DoublePointInformation对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int DoublePointInformation_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return DoublePointInformation_Encode_Value((const IEC60870_DoublePointInformation_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable DoublePointInformation_VTable = {
|
||
3, 1, 0, sizeof(IEC60870_DoublePointInformation_t), DoublePointInformation_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 3(双点信息)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——双点状态,0..3,包含中间状态和不确定状态。
|
||
* quality——品质仅允许BL/SB/NT/IV(0xF0范围内的位),不得夹带状态或保留位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoublePointInformation_Create(IEC60870_DoublePointInformation_t *self,
|
||
uint32_t ioa, int value, int quality)
|
||
{
|
||
IEC60870_DoublePointInformation_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
value < 0 || value > 3 ||
|
||
quality < 0 || quality > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = (uint8_t)value;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &DoublePointInformation_VTable);
|
||
if (!DoublePointInformation_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 3(双点信息)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoublePointInformation_Get_From_Buffer(IEC60870_DoublePointInformation_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_DoublePointInformation_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!DoublePointInformation_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &DoublePointInformation_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 9:归一化测量值(原始16位定点值) ---- */
|
||
/**
|
||
* 功能:编码Type 9(归一化测量值(原始16位定点值))的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少3字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:NVA(2)+QDS(1):有符号16位归一化原始定点值,随后为品质。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int MeasuredValueNormalized_Encode_Value(const IEC60870_MeasuredValueNormalized_t *self, uint8_t *payload)
|
||
{
|
||
/* QDS的bit1..3为保留位;bit0为溢出,高4位为品质。 */
|
||
if ((self->quality & 0x0EU) != 0U) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
payload[2] = self->quality;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 9(归一化测量值(原始16位定点值))的值字段。
|
||
* 输入参数:payload——已确认有3字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:NVA(2)+QDS(1):有符号16位归一化原始定点值,随后为品质。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int MeasuredValueNormalized_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueNormalized_t *self)
|
||
{
|
||
if ((payload[2] & 0x0EU) != 0U) { return 0; }
|
||
self->value = Read_I16(payload);
|
||
self->quality = payload[2];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 9编码函数表的适配入口,将公共基类还原为MeasuredValueNormalized对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少3字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int MeasuredValueNormalized_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueNormalized_Encode_Value((const IEC60870_MeasuredValueNormalized_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable MeasuredValueNormalized_VTable = {
|
||
9, 3, 0, sizeof(IEC60870_MeasuredValueNormalized_t), MeasuredValueNormalized_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 9(归一化测量值(原始16位定点值))。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——归一化原始int16_t定点值,实际数值为value/32768.0。
|
||
* quality——QDS品质仅允许OV/BL/SB/NT/IV(0xF1范围内的位),bit1..3必须为0。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalized_Create(IEC60870_MeasuredValueNormalized_t *self,
|
||
uint32_t ioa, int16_t value, int quality)
|
||
{
|
||
IEC60870_MeasuredValueNormalized_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
quality < 0 || quality > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueNormalized_VTable);
|
||
if (!MeasuredValueNormalized_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 9(归一化测量值(原始16位定点值))。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的3字节载荷,必须非空。
|
||
* length——必须恰好为3;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalized_Get_From_Buffer(IEC60870_MeasuredValueNormalized_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueNormalized_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 3U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueNormalized_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueNormalized_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 11:标度化测量值 ---- */
|
||
/**
|
||
* 功能:编码Type 11(标度化测量值)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少3字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SVA(2)+QDS(1):有符号16位标度值,随后为品质。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int MeasuredValueScaled_Encode_Value(const IEC60870_MeasuredValueScaled_t *self, uint8_t *payload)
|
||
{
|
||
/* QDS的bit1..3为保留位;bit0为溢出,高4位为品质。 */
|
||
if ((self->quality & 0x0EU) != 0U) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
payload[2] = self->quality;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 11(标度化测量值)的值字段。
|
||
* 输入参数:payload——已确认有3字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SVA(2)+QDS(1):有符号16位标度值,随后为品质。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int MeasuredValueScaled_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueScaled_t *self)
|
||
{
|
||
if ((payload[2] & 0x0EU) != 0U) { return 0; }
|
||
self->value = Read_I16(payload);
|
||
self->quality = payload[2];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 11编码函数表的适配入口,将公共基类还原为MeasuredValueScaled对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少3字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int MeasuredValueScaled_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueScaled_Encode_Value((const IEC60870_MeasuredValueScaled_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable MeasuredValueScaled_VTable = {
|
||
11, 3, 0, sizeof(IEC60870_MeasuredValueScaled_t), MeasuredValueScaled_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 11(标度化测量值)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——有符号16位标度值,范围-32768..32767。
|
||
* quality——QDS品质仅允许OV/BL/SB/NT/IV(0xF1范围内的位),bit1..3必须为0。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueScaled_Create(IEC60870_MeasuredValueScaled_t *self,
|
||
uint32_t ioa, int16_t value, int quality)
|
||
{
|
||
IEC60870_MeasuredValueScaled_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
quality < 0 || quality > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueScaled_VTable);
|
||
if (!MeasuredValueScaled_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 11(标度化测量值)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的3字节载荷,必须非空。
|
||
* length——必须恰好为3;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueScaled_Get_From_Buffer(IEC60870_MeasuredValueScaled_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueScaled_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 3U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueScaled_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueScaled_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 13:短浮点测量值 ---- */
|
||
/**
|
||
* 功能:编码Type 13(短浮点测量值)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:短浮点(4)+QDS(1):IEEE 754 binary32位模式,随后为品质。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int MeasuredValueShort_Encode_Value(const IEC60870_MeasuredValueShort_t *self, uint8_t *payload)
|
||
{
|
||
/* QDS的bit1..3为保留位;bit0为溢出,高4位为品质。 */
|
||
if ((self->quality & 0x0EU) != 0U) { return 0; }
|
||
Write_Float(payload, &self->value);
|
||
payload[4] = self->quality;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 13(短浮点测量值)的值字段。
|
||
* 输入参数:payload——已确认有5字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:短浮点(4)+QDS(1):IEEE 754 binary32位模式,随后为品质。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int MeasuredValueShort_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueShort_t *self)
|
||
{
|
||
if ((payload[4] & 0x0EU) != 0U) { return 0; }
|
||
Read_Float(payload, &self->value);
|
||
self->quality = payload[4];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 13编码函数表的适配入口,将公共基类还原为MeasuredValueShort对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少5字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int MeasuredValueShort_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueShort_Encode_Value((const IEC60870_MeasuredValueShort_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable MeasuredValueShort_VTable = {
|
||
13, 5, 0, sizeof(IEC60870_MeasuredValueShort_t), MeasuredValueShort_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 13(短浮点测量值)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——短浮点值,采用IEEE 754 binary32,不进行NaN/Inf业务过滤。
|
||
* quality——QDS品质仅允许OV/BL/SB/NT/IV(0xF1范围内的位),bit1..3必须为0。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueShort_Create(IEC60870_MeasuredValueShort_t *self,
|
||
uint32_t ioa, float value, int quality)
|
||
{
|
||
IEC60870_MeasuredValueShort_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
quality < 0 || quality > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueShort_VTable);
|
||
if (!MeasuredValueShort_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 13(短浮点测量值)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的5字节载荷,必须非空。
|
||
* length——必须恰好为5;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueShort_Get_From_Buffer(IEC60870_MeasuredValueShort_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueShort_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 5U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueShort_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueShort_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 15:累计量 ---- */
|
||
/**
|
||
* 功能:编码Type 15(累计量)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:BCR(5):前4字节为有符号累计值,末字节为5位序号及CY/CA/IV。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int IntegratedTotals_Encode_Value(const IEC60870_IntegratedTotals_t *self, uint8_t *payload)
|
||
{
|
||
const IEC60870_BinaryCounterReading_t *value = &self->value;
|
||
if (value->sequence_number > 31U || value->has_carry > 1U ||
|
||
value->is_adjusted > 1U || value->is_invalid > 1U) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, (uint32_t)value->value, 4);
|
||
/* BCR末字节:低5位序号、bit5进位、bit6调整、bit7无效。 */
|
||
payload[4] = (uint8_t)(value->sequence_number | (value->has_carry << 5) |
|
||
(value->is_adjusted << 6) | (value->is_invalid << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 15(累计量)的值字段。
|
||
* 输入参数:payload——已确认有5字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:BCR(5):前4字节为有符号累计值,末字节为5位序号及CY/CA/IV。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int IntegratedTotals_Decode_Value(const uint8_t *payload, IEC60870_IntegratedTotals_t *self)
|
||
{
|
||
self->value.value = Read_I32(payload);
|
||
self->value.sequence_number = payload[4] & 31U;
|
||
self->value.has_carry = (payload[4] >> 5) & 1U;
|
||
self->value.is_adjusted = (payload[4] >> 6) & 1U;
|
||
self->value.is_invalid = payload[4] >> 7;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 15编码函数表的适配入口,将公共基类还原为IntegratedTotals对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少5字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int IntegratedTotals_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return IntegratedTotals_Encode_Value((const IEC60870_IntegratedTotals_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable IntegratedTotals_VTable = {
|
||
15, 5, 0, sizeof(IEC60870_IntegratedTotals_t), IntegratedTotals_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 15(累计量)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——非空BCR指针;计数为int32_t,序号0..31,CY/CA/IV均为0/1。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_IntegratedTotals_Create(IEC60870_IntegratedTotals_t *self,
|
||
uint32_t ioa, const IEC60870_BinaryCounterReading_t *value)
|
||
{
|
||
IEC60870_IntegratedTotals_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
value == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = *value;
|
||
Initialize_Object(&result.object, ioa, &IntegratedTotals_VTable);
|
||
if (!IntegratedTotals_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 15(累计量)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的5字节载荷,必须非空。
|
||
* length——必须恰好为5;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_IntegratedTotals_Get_From_Buffer(IEC60870_IntegratedTotals_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_IntegratedTotals_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 5U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!IntegratedTotals_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &IntegratedTotals_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 30:带时标单点信息 ---- */
|
||
/**
|
||
* 功能:编码Type 30(带时标单点信息)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SIQ(1):bit0为单点状态,bit1..3为保留位,高4位为品质,之后追加CP56Time2a(7)。
|
||
* 值部分调用SinglePointInformation_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SinglePointWithCP56Time2a_Encode_Value(const IEC60870_SinglePointWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return SinglePointInformation_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 1, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 30(带时标单点信息)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有8字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SIQ(1):bit0为单点状态,bit1..3为保留位,高4位为品质,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SinglePointWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_SinglePointWithCP56Time2a_t *self)
|
||
{
|
||
return SinglePointInformation_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 1, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 30编码函数表的适配入口,将公共基类还原为SinglePointWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少8字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SinglePointWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SinglePointWithCP56Time2a_Encode_Value((const IEC60870_SinglePointWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SinglePointWithCP56Time2a_VTable = {
|
||
30, 8, 0, sizeof(IEC60870_SinglePointWithCP56Time2a_t), SinglePointWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 30(带时标单点信息)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——单点状态,0或1。
|
||
* quality——品质仅允许BL/SB/NT/IV(0xF0范围内的位),不得夹带状态或保留位。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SinglePointWithCP56Time2a_Create(IEC60870_SinglePointWithCP56Time2a_t *self,
|
||
uint32_t ioa, int value, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_SinglePointWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
value < 0 || value > 1 ||
|
||
quality < 0 || quality > 255 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = (uint8_t)value;
|
||
result.base.quality = (uint8_t)quality;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &SinglePointWithCP56Time2a_VTable);
|
||
if (!SinglePointWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 30(带时标单点信息)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的8字节载荷,必须非空。
|
||
* length——必须恰好为8;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SinglePointWithCP56Time2a_Get_From_Buffer(IEC60870_SinglePointWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SinglePointWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 8U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SinglePointWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &SinglePointWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 31:带时标双点信息 ---- */
|
||
/**
|
||
* 功能:编码Type 31(带时标双点信息)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:DIQ(1):低2位为双点状态,bit2..3为保留位,高4位为品质,之后追加CP56Time2a(7)。
|
||
* 值部分调用DoublePointInformation_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int DoublePointWithCP56Time2a_Encode_Value(const IEC60870_DoublePointWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return DoublePointInformation_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 1, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 31(带时标双点信息)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有8字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:DIQ(1):低2位为双点状态,bit2..3为保留位,高4位为品质,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int DoublePointWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_DoublePointWithCP56Time2a_t *self)
|
||
{
|
||
return DoublePointInformation_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 1, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 31编码函数表的适配入口,将公共基类还原为DoublePointWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少8字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int DoublePointWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return DoublePointWithCP56Time2a_Encode_Value((const IEC60870_DoublePointWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable DoublePointWithCP56Time2a_VTable = {
|
||
31, 8, 0, sizeof(IEC60870_DoublePointWithCP56Time2a_t), DoublePointWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 31(带时标双点信息)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——双点状态,0..3,包含中间状态和不确定状态。
|
||
* quality——品质仅允许BL/SB/NT/IV(0xF0范围内的位),不得夹带状态或保留位。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoublePointWithCP56Time2a_Create(IEC60870_DoublePointWithCP56Time2a_t *self,
|
||
uint32_t ioa, int value, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_DoublePointWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
value < 0 || value > 3 ||
|
||
quality < 0 || quality > 255 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = (uint8_t)value;
|
||
result.base.quality = (uint8_t)quality;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &DoublePointWithCP56Time2a_VTable);
|
||
if (!DoublePointWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 31(带时标双点信息)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的8字节载荷,必须非空。
|
||
* length——必须恰好为8;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoublePointWithCP56Time2a_Get_From_Buffer(IEC60870_DoublePointWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_DoublePointWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 8U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!DoublePointWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &DoublePointWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 34:带时标归一化测量值 ---- */
|
||
/**
|
||
* 功能:编码Type 34(带时标归一化测量值)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少10字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:NVA(2)+QDS(1):有符号16位归一化原始定点值,随后为品质,之后追加CP56Time2a(7)。
|
||
* 值部分调用MeasuredValueNormalized_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int MeasuredValueNormalizedWithCP56Time2a_Encode_Value(const IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return MeasuredValueNormalized_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 3, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 34(带时标归一化测量值)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有10字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:NVA(2)+QDS(1):有符号16位归一化原始定点值,随后为品质,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int MeasuredValueNormalizedWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *self)
|
||
{
|
||
return MeasuredValueNormalized_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 3, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 34编码函数表的适配入口,将公共基类还原为MeasuredValueNormalizedWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少10字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int MeasuredValueNormalizedWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueNormalizedWithCP56Time2a_Encode_Value((const IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable MeasuredValueNormalizedWithCP56Time2a_VTable = {
|
||
34, 10, 0, sizeof(IEC60870_MeasuredValueNormalizedWithCP56Time2a_t), MeasuredValueNormalizedWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 34(带时标归一化测量值)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——归一化原始int16_t定点值,实际数值为value/32768.0。
|
||
* quality——QDS品质仅允许OV/BL/SB/NT/IV(0xF1范围内的位),bit1..3必须为0。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP56Time2a_Create(IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *self,
|
||
uint32_t ioa, int16_t value, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_MeasuredValueNormalizedWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
quality < 0 || quality > 255 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = value;
|
||
result.base.quality = (uint8_t)quality;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueNormalizedWithCP56Time2a_VTable);
|
||
if (!MeasuredValueNormalizedWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 34(带时标归一化测量值)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的10字节载荷,必须非空。
|
||
* length——必须恰好为10;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP56Time2a_Get_From_Buffer(IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueNormalizedWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 10U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueNormalizedWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueNormalizedWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 35:带时标标度化测量值 ---- */
|
||
/**
|
||
* 功能:编码Type 35(带时标标度化测量值)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少10字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SVA(2)+QDS(1):有符号16位标度值,随后为品质,之后追加CP56Time2a(7)。
|
||
* 值部分调用MeasuredValueScaled_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int MeasuredValueScaledWithCP56Time2a_Encode_Value(const IEC60870_MeasuredValueScaledWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return MeasuredValueScaled_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 3, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 35(带时标标度化测量值)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有10字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SVA(2)+QDS(1):有符号16位标度值,随后为品质,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int MeasuredValueScaledWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueScaledWithCP56Time2a_t *self)
|
||
{
|
||
return MeasuredValueScaled_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 3, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 35编码函数表的适配入口,将公共基类还原为MeasuredValueScaledWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少10字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int MeasuredValueScaledWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueScaledWithCP56Time2a_Encode_Value((const IEC60870_MeasuredValueScaledWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable MeasuredValueScaledWithCP56Time2a_VTable = {
|
||
35, 10, 0, sizeof(IEC60870_MeasuredValueScaledWithCP56Time2a_t), MeasuredValueScaledWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 35(带时标标度化测量值)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——有符号16位标度值,范围-32768..32767。
|
||
* quality——QDS品质仅允许OV/BL/SB/NT/IV(0xF1范围内的位),bit1..3必须为0。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP56Time2a_Create(IEC60870_MeasuredValueScaledWithCP56Time2a_t *self,
|
||
uint32_t ioa, int16_t value, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_MeasuredValueScaledWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
quality < 0 || quality > 255 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = value;
|
||
result.base.quality = (uint8_t)quality;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueScaledWithCP56Time2a_VTable);
|
||
if (!MeasuredValueScaledWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 35(带时标标度化测量值)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的10字节载荷,必须非空。
|
||
* length——必须恰好为10;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP56Time2a_Get_From_Buffer(IEC60870_MeasuredValueScaledWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueScaledWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 10U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueScaledWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueScaledWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 36:带时标短浮点测量值 ---- */
|
||
/**
|
||
* 功能:编码Type 36(带时标短浮点测量值)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少12字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:短浮点(4)+QDS(1):IEEE 754 binary32位模式,随后为品质,之后追加CP56Time2a(7)。
|
||
* 值部分调用MeasuredValueShort_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int MeasuredValueShortWithCP56Time2a_Encode_Value(const IEC60870_MeasuredValueShortWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return MeasuredValueShort_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 5, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 36(带时标短浮点测量值)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有12字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:短浮点(4)+QDS(1):IEEE 754 binary32位模式,随后为品质,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int MeasuredValueShortWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueShortWithCP56Time2a_t *self)
|
||
{
|
||
return MeasuredValueShort_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 5, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 36编码函数表的适配入口,将公共基类还原为MeasuredValueShortWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少12字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int MeasuredValueShortWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueShortWithCP56Time2a_Encode_Value((const IEC60870_MeasuredValueShortWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable MeasuredValueShortWithCP56Time2a_VTable = {
|
||
36, 12, 0, sizeof(IEC60870_MeasuredValueShortWithCP56Time2a_t), MeasuredValueShortWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 36(带时标短浮点测量值)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——短浮点值,采用IEEE 754 binary32,不进行NaN/Inf业务过滤。
|
||
* quality——QDS品质仅允许OV/BL/SB/NT/IV(0xF1范围内的位),bit1..3必须为0。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP56Time2a_Create(IEC60870_MeasuredValueShortWithCP56Time2a_t *self,
|
||
uint32_t ioa, float value, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_MeasuredValueShortWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
quality < 0 || quality > 255 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = value;
|
||
result.base.quality = (uint8_t)quality;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueShortWithCP56Time2a_VTable);
|
||
if (!MeasuredValueShortWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 36(带时标短浮点测量值)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的12字节载荷,必须非空。
|
||
* length——必须恰好为12;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP56Time2a_Get_From_Buffer(IEC60870_MeasuredValueShortWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueShortWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 12U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueShortWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueShortWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 37:带时标累计量 ---- */
|
||
/**
|
||
* 功能:编码Type 37(带时标累计量)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少12字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:BCR(5):前4字节为有符号累计值,末字节为5位序号及CY/CA/IV,之后追加CP56Time2a(7)。
|
||
* 值部分调用IntegratedTotals_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int IntegratedTotalsWithCP56Time2a_Encode_Value(const IEC60870_IntegratedTotalsWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return IntegratedTotals_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 5, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 37(带时标累计量)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有12字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:BCR(5):前4字节为有符号累计值,末字节为5位序号及CY/CA/IV,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int IntegratedTotalsWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_IntegratedTotalsWithCP56Time2a_t *self)
|
||
{
|
||
return IntegratedTotals_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 5, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 37编码函数表的适配入口,将公共基类还原为IntegratedTotalsWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少12字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int IntegratedTotalsWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return IntegratedTotalsWithCP56Time2a_Encode_Value((const IEC60870_IntegratedTotalsWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable IntegratedTotalsWithCP56Time2a_VTable = {
|
||
37, 12, 0, sizeof(IEC60870_IntegratedTotalsWithCP56Time2a_t), IntegratedTotalsWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 37(带时标累计量)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——非空BCR指针;计数为int32_t,序号0..31,CY/CA/IV均为0/1。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP56Time2a_Create(IEC60870_IntegratedTotalsWithCP56Time2a_t *self,
|
||
uint32_t ioa, const IEC60870_BinaryCounterReading_t *value, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_IntegratedTotalsWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
value == NULL ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = *value;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &IntegratedTotalsWithCP56Time2a_VTable);
|
||
if (!IntegratedTotalsWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 37(带时标累计量)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的12字节载荷,必须非空。
|
||
* length——必须恰好为12;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP56Time2a_Get_From_Buffer(IEC60870_IntegratedTotalsWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_IntegratedTotalsWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 12U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!IntegratedTotalsWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &IntegratedTotalsWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 45:单命令 ---- */
|
||
/**
|
||
* 功能:编码Type 45(单命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SCO(1):bit0为状态,bit1保留,bit2..6为QU,bit7为S/E。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SingleCommand_Encode_Value(const IEC60870_SingleCommand_t *self, uint8_t *payload)
|
||
{
|
||
/* SCO的bit1必须为0;单命令状态为0/1;QU占bit2..6,S/E占bit7。 */
|
||
if (self->state > 1U ||
|
||
self->is_select > 1U || self->qualifier > 31U) { return 0; }
|
||
payload[0] = (uint8_t)(self->state | (self->qualifier << 2) | (self->is_select << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 45(单命令)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SCO(1):bit0为状态,bit1保留,bit2..6为QU,bit7为S/E。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SingleCommand_Decode_Value(const uint8_t *payload, IEC60870_SingleCommand_t *self)
|
||
{
|
||
if ((payload[0] & 2U) != 0U) { return 0; }
|
||
self->state = payload[0] & 1U;
|
||
self->is_select = payload[0] >> 7;
|
||
self->qualifier = (payload[0] >> 2) & 31U;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 45编码函数表的适配入口,将公共基类还原为SingleCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SingleCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SingleCommand_Encode_Value((const IEC60870_SingleCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SingleCommand_VTable = {
|
||
45, 1, 1, sizeof(IEC60870_SingleCommand_t), SingleCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 45(单命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* state——单命令状态,0或1;SCO保留位由编码器保持为0。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——命令限定词QU,0..31;具体业务含义由应用判断。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SingleCommand_Create(IEC60870_SingleCommand_t *self,
|
||
uint32_t ioa, int state, int is_select, int qualifier)
|
||
{
|
||
IEC60870_SingleCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
state < 0 || state > 1 ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 31) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.state = (uint8_t)state;
|
||
result.is_select = (uint8_t)is_select;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &SingleCommand_VTable);
|
||
if (!SingleCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 45(单命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SingleCommand_Get_From_Buffer(IEC60870_SingleCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SingleCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SingleCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &SingleCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 46:双命令 ---- */
|
||
/**
|
||
* 功能:编码Type 46(双命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:DCO(1):低2位为状态(仅1/2),bit2..6为QU,bit7为S/E。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int DoubleCommand_Encode_Value(const IEC60870_DoubleCommand_t *self, uint8_t *payload)
|
||
{
|
||
/* DCO/RCO仅接收状态1/2;QU占bit2..6,S/E占bit7。 */
|
||
if ((self->state != 1U && self->state != 2U) ||
|
||
self->is_select > 1U || self->qualifier > 31U) { return 0; }
|
||
payload[0] = (uint8_t)(self->state | (self->qualifier << 2) | (self->is_select << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 46(双命令)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:DCO(1):低2位为状态(仅1/2),bit2..6为QU,bit7为S/E。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int DoubleCommand_Decode_Value(const uint8_t *payload, IEC60870_DoubleCommand_t *self)
|
||
{
|
||
self->state = payload[0] & 3U;
|
||
if (self->state != 1U && self->state != 2U) { return 0; }
|
||
self->is_select = payload[0] >> 7;
|
||
self->qualifier = (payload[0] >> 2) & 31U;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 46编码函数表的适配入口,将公共基类还原为DoubleCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int DoubleCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return DoubleCommand_Encode_Value((const IEC60870_DoubleCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable DoubleCommand_VTable = {
|
||
46, 1, 1, sizeof(IEC60870_DoubleCommand_t), DoubleCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 46(双命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* state——双命令/步调节状态,仅允许1或2。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——命令限定词QU,0..31;具体业务含义由应用判断。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoubleCommand_Create(IEC60870_DoubleCommand_t *self,
|
||
uint32_t ioa, int state, int is_select, int qualifier)
|
||
{
|
||
IEC60870_DoubleCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
state < 1 || state > 2 ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 31) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.state = (uint8_t)state;
|
||
result.is_select = (uint8_t)is_select;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &DoubleCommand_VTable);
|
||
if (!DoubleCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 46(双命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoubleCommand_Get_From_Buffer(IEC60870_DoubleCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_DoubleCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!DoubleCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &DoubleCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 47:步调节命令 ---- */
|
||
/**
|
||
* 功能:编码Type 47(步调节命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:RCO(1):低2位为调节状态(仅1/2),bit2..6为QU,bit7为S/E。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int StepCommand_Encode_Value(const IEC60870_StepCommand_t *self, uint8_t *payload)
|
||
{
|
||
/* DCO/RCO仅接收状态1/2;QU占bit2..6,S/E占bit7。 */
|
||
if ((self->state != 1U && self->state != 2U) ||
|
||
self->is_select > 1U || self->qualifier > 31U) { return 0; }
|
||
payload[0] = (uint8_t)(self->state | (self->qualifier << 2) | (self->is_select << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 47(步调节命令)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:RCO(1):低2位为调节状态(仅1/2),bit2..6为QU,bit7为S/E。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int StepCommand_Decode_Value(const uint8_t *payload, IEC60870_StepCommand_t *self)
|
||
{
|
||
self->state = payload[0] & 3U;
|
||
if (self->state != 1U && self->state != 2U) { return 0; }
|
||
self->is_select = payload[0] >> 7;
|
||
self->qualifier = (payload[0] >> 2) & 31U;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 47编码函数表的适配入口,将公共基类还原为StepCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int StepCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return StepCommand_Encode_Value((const IEC60870_StepCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable StepCommand_VTable = {
|
||
47, 1, 1, sizeof(IEC60870_StepCommand_t), StepCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 47(步调节命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* state——双命令/步调节状态,仅允许1或2。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——命令限定词QU,0..31;具体业务含义由应用判断。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepCommand_Create(IEC60870_StepCommand_t *self,
|
||
uint32_t ioa, int state, int is_select, int qualifier)
|
||
{
|
||
IEC60870_StepCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
state < 1 || state > 2 ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 31) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.state = (uint8_t)state;
|
||
result.is_select = (uint8_t)is_select;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &StepCommand_VTable);
|
||
if (!StepCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 47(步调节命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepCommand_Get_From_Buffer(IEC60870_StepCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_StepCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!StepCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &StepCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 48:归一化设定值命令(原始16位定点值) ---- */
|
||
/**
|
||
* 功能:编码Type 48(归一化设定值命令(原始16位定点值))的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少3字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:NVA(2)+QOS(1):归一化原始定点值;QOS低7位为QL,bit7为S/E。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SetpointCommandNormalized_Encode_Value(const IEC60870_SetpointCommandNormalized_t *self, uint8_t *payload)
|
||
{
|
||
if (self->is_select > 1U || self->qualifier > 127U) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
/* 数值后接QOS:低7位QL,高位S/E。 */
|
||
payload[2] = (uint8_t)(self->qualifier | (self->is_select << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 48(归一化设定值命令(原始16位定点值))的值字段。
|
||
* 输入参数:payload——已确认有3字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:NVA(2)+QOS(1):归一化原始定点值;QOS低7位为QL,bit7为S/E。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SetpointCommandNormalized_Decode_Value(const uint8_t *payload, IEC60870_SetpointCommandNormalized_t *self)
|
||
{
|
||
self->value = Read_I16(payload);
|
||
self->qualifier = payload[2] & 127U;
|
||
self->is_select = payload[2] >> 7;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 48编码函数表的适配入口,将公共基类还原为SetpointCommandNormalized对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少3字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SetpointCommandNormalized_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SetpointCommandNormalized_Encode_Value((const IEC60870_SetpointCommandNormalized_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SetpointCommandNormalized_VTable = {
|
||
48, 3, 1, sizeof(IEC60870_SetpointCommandNormalized_t), SetpointCommandNormalized_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 48(归一化设定值命令(原始16位定点值))。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——归一化原始int16_t定点值,实际数值为value/32768.0。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——设定值限定词QL,0..127;编码到QOS低7位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalized_Create(IEC60870_SetpointCommandNormalized_t *self,
|
||
uint32_t ioa, int16_t value, int is_select, int qualifier)
|
||
{
|
||
IEC60870_SetpointCommandNormalized_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 127) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.is_select = (uint8_t)is_select;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &SetpointCommandNormalized_VTable);
|
||
if (!SetpointCommandNormalized_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 48(归一化设定值命令(原始16位定点值))。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的3字节载荷,必须非空。
|
||
* length——必须恰好为3;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalized_Get_From_Buffer(IEC60870_SetpointCommandNormalized_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SetpointCommandNormalized_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 3U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SetpointCommandNormalized_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &SetpointCommandNormalized_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 49:标度化设定值命令 ---- */
|
||
/**
|
||
* 功能:编码Type 49(标度化设定值命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少3字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SVA(2)+QOS(1):标度值;QOS低7位为QL,bit7为S/E。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SetpointCommandScaled_Encode_Value(const IEC60870_SetpointCommandScaled_t *self, uint8_t *payload)
|
||
{
|
||
if (self->is_select > 1U || self->qualifier > 127U) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
/* 数值后接QOS:低7位QL,高位S/E。 */
|
||
payload[2] = (uint8_t)(self->qualifier | (self->is_select << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 49(标度化设定值命令)的值字段。
|
||
* 输入参数:payload——已确认有3字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SVA(2)+QOS(1):标度值;QOS低7位为QL,bit7为S/E。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SetpointCommandScaled_Decode_Value(const uint8_t *payload, IEC60870_SetpointCommandScaled_t *self)
|
||
{
|
||
self->value = Read_I16(payload);
|
||
self->qualifier = payload[2] & 127U;
|
||
self->is_select = payload[2] >> 7;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 49编码函数表的适配入口,将公共基类还原为SetpointCommandScaled对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少3字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SetpointCommandScaled_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SetpointCommandScaled_Encode_Value((const IEC60870_SetpointCommandScaled_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SetpointCommandScaled_VTable = {
|
||
49, 3, 1, sizeof(IEC60870_SetpointCommandScaled_t), SetpointCommandScaled_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 49(标度化设定值命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——有符号16位标度值,范围-32768..32767。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——设定值限定词QL,0..127;编码到QOS低7位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandScaled_Create(IEC60870_SetpointCommandScaled_t *self,
|
||
uint32_t ioa, int16_t value, int is_select, int qualifier)
|
||
{
|
||
IEC60870_SetpointCommandScaled_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 127) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.is_select = (uint8_t)is_select;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &SetpointCommandScaled_VTable);
|
||
if (!SetpointCommandScaled_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 49(标度化设定值命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的3字节载荷,必须非空。
|
||
* length——必须恰好为3;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandScaled_Get_From_Buffer(IEC60870_SetpointCommandScaled_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SetpointCommandScaled_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 3U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SetpointCommandScaled_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &SetpointCommandScaled_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 50:短浮点设定值命令 ---- */
|
||
/**
|
||
* 功能:编码Type 50(短浮点设定值命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:短浮点(4)+QOS(1):浮点位模式;QOS低7位为QL,bit7为S/E。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SetpointCommandShort_Encode_Value(const IEC60870_SetpointCommandShort_t *self, uint8_t *payload)
|
||
{
|
||
if (self->is_select > 1U || self->qualifier > 127U) { return 0; }
|
||
Write_Float(payload, &self->value);
|
||
/* 数值后接QOS:低7位QL,高位S/E。 */
|
||
payload[4] = (uint8_t)(self->qualifier | (self->is_select << 7));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 50(短浮点设定值命令)的值字段。
|
||
* 输入参数:payload——已确认有5字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:短浮点(4)+QOS(1):浮点位模式;QOS低7位为QL,bit7为S/E。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SetpointCommandShort_Decode_Value(const uint8_t *payload, IEC60870_SetpointCommandShort_t *self)
|
||
{
|
||
Read_Float(payload, &self->value);
|
||
self->qualifier = payload[4] & 127U;
|
||
self->is_select = payload[4] >> 7;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 50编码函数表的适配入口,将公共基类还原为SetpointCommandShort对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少5字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SetpointCommandShort_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SetpointCommandShort_Encode_Value((const IEC60870_SetpointCommandShort_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SetpointCommandShort_VTable = {
|
||
50, 5, 1, sizeof(IEC60870_SetpointCommandShort_t), SetpointCommandShort_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 50(短浮点设定值命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——短浮点值,采用IEEE 754 binary32,不进行NaN/Inf业务过滤。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——设定值限定词QL,0..127;编码到QOS低7位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandShort_Create(IEC60870_SetpointCommandShort_t *self,
|
||
uint32_t ioa, float value, int is_select, int qualifier)
|
||
{
|
||
IEC60870_SetpointCommandShort_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 127) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.is_select = (uint8_t)is_select;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &SetpointCommandShort_VTable);
|
||
if (!SetpointCommandShort_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 50(短浮点设定值命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的5字节载荷,必须非空。
|
||
* length——必须恰好为5;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandShort_Get_From_Buffer(IEC60870_SetpointCommandShort_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SetpointCommandShort_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 5U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SetpointCommandShort_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &SetpointCommandShort_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 58:带时标单命令 ---- */
|
||
/**
|
||
* 功能:编码Type 58(带时标单命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SCO(1):bit0为状态,bit1保留,bit2..6为QU,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 值部分调用SingleCommand_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SingleCommandWithCP56Time2a_Encode_Value(const IEC60870_SingleCommandWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return SingleCommand_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 1, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 58(带时标单命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有8字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SCO(1):bit0为状态,bit1保留,bit2..6为QU,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SingleCommandWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_SingleCommandWithCP56Time2a_t *self)
|
||
{
|
||
return SingleCommand_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 1, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 58编码函数表的适配入口,将公共基类还原为SingleCommandWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少8字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SingleCommandWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SingleCommandWithCP56Time2a_Encode_Value((const IEC60870_SingleCommandWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SingleCommandWithCP56Time2a_VTable = {
|
||
58, 8, 1, sizeof(IEC60870_SingleCommandWithCP56Time2a_t), SingleCommandWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 58(带时标单命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* state——单命令状态,0或1;SCO保留位由编码器保持为0。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——命令限定词QU,0..31;具体业务含义由应用判断。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SingleCommandWithCP56Time2a_Create(IEC60870_SingleCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, int state, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_SingleCommandWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
state < 0 || state > 1 ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 31 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.state = (uint8_t)state;
|
||
result.base.is_select = (uint8_t)is_select;
|
||
result.base.qualifier = (uint8_t)qualifier;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &SingleCommandWithCP56Time2a_VTable);
|
||
if (!SingleCommandWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 58(带时标单命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的8字节载荷,必须非空。
|
||
* length——必须恰好为8;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SingleCommandWithCP56Time2a_Get_From_Buffer(IEC60870_SingleCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SingleCommandWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 8U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SingleCommandWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &SingleCommandWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 59:带时标双命令 ---- */
|
||
/**
|
||
* 功能:编码Type 59(带时标双命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:DCO(1):低2位为状态(仅1/2),bit2..6为QU,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 值部分调用DoubleCommand_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int DoubleCommandWithCP56Time2a_Encode_Value(const IEC60870_DoubleCommandWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return DoubleCommand_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 1, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 59(带时标双命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有8字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:DCO(1):低2位为状态(仅1/2),bit2..6为QU,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int DoubleCommandWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_DoubleCommandWithCP56Time2a_t *self)
|
||
{
|
||
return DoubleCommand_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 1, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 59编码函数表的适配入口,将公共基类还原为DoubleCommandWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少8字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int DoubleCommandWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return DoubleCommandWithCP56Time2a_Encode_Value((const IEC60870_DoubleCommandWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable DoubleCommandWithCP56Time2a_VTable = {
|
||
59, 8, 1, sizeof(IEC60870_DoubleCommandWithCP56Time2a_t), DoubleCommandWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 59(带时标双命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* state——双命令/步调节状态,仅允许1或2。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——命令限定词QU,0..31;具体业务含义由应用判断。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoubleCommandWithCP56Time2a_Create(IEC60870_DoubleCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, int state, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_DoubleCommandWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
state < 1 || state > 2 ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 31 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.state = (uint8_t)state;
|
||
result.base.is_select = (uint8_t)is_select;
|
||
result.base.qualifier = (uint8_t)qualifier;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &DoubleCommandWithCP56Time2a_VTable);
|
||
if (!DoubleCommandWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 59(带时标双命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的8字节载荷,必须非空。
|
||
* length——必须恰好为8;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoubleCommandWithCP56Time2a_Get_From_Buffer(IEC60870_DoubleCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_DoubleCommandWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 8U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!DoubleCommandWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &DoubleCommandWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 60:带时标步调节命令 ---- */
|
||
/**
|
||
* 功能:编码Type 60(带时标步调节命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:RCO(1):低2位为调节状态(仅1/2),bit2..6为QU,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 值部分调用StepCommand_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int StepCommandWithCP56Time2a_Encode_Value(const IEC60870_StepCommandWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return StepCommand_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 1, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 60(带时标步调节命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有8字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:RCO(1):低2位为调节状态(仅1/2),bit2..6为QU,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int StepCommandWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_StepCommandWithCP56Time2a_t *self)
|
||
{
|
||
return StepCommand_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 1, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 60编码函数表的适配入口,将公共基类还原为StepCommandWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少8字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int StepCommandWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return StepCommandWithCP56Time2a_Encode_Value((const IEC60870_StepCommandWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable StepCommandWithCP56Time2a_VTable = {
|
||
60, 8, 1, sizeof(IEC60870_StepCommandWithCP56Time2a_t), StepCommandWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 60(带时标步调节命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* state——双命令/步调节状态,仅允许1或2。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——命令限定词QU,0..31;具体业务含义由应用判断。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepCommandWithCP56Time2a_Create(IEC60870_StepCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, int state, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_StepCommandWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
state < 1 || state > 2 ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 31 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.state = (uint8_t)state;
|
||
result.base.is_select = (uint8_t)is_select;
|
||
result.base.qualifier = (uint8_t)qualifier;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &StepCommandWithCP56Time2a_VTable);
|
||
if (!StepCommandWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 60(带时标步调节命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的8字节载荷,必须非空。
|
||
* length——必须恰好为8;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepCommandWithCP56Time2a_Get_From_Buffer(IEC60870_StepCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_StepCommandWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 8U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!StepCommandWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &StepCommandWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 61:带时标归一化设定值命令 ---- */
|
||
/**
|
||
* 功能:编码Type 61(带时标归一化设定值命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少10字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:NVA(2)+QOS(1):归一化原始定点值;QOS低7位为QL,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 值部分调用SetpointCommandNormalized_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SetpointCommandNormalizedWithCP56Time2a_Encode_Value(const IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return SetpointCommandNormalized_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 3, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 61(带时标归一化设定值命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有10字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:NVA(2)+QOS(1):归一化原始定点值;QOS低7位为QL,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SetpointCommandNormalizedWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *self)
|
||
{
|
||
return SetpointCommandNormalized_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 3, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 61编码函数表的适配入口,将公共基类还原为SetpointCommandNormalizedWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少10字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SetpointCommandNormalizedWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SetpointCommandNormalizedWithCP56Time2a_Encode_Value((const IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SetpointCommandNormalizedWithCP56Time2a_VTable = {
|
||
61, 10, 1, sizeof(IEC60870_SetpointCommandNormalizedWithCP56Time2a_t), SetpointCommandNormalizedWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 61(带时标归一化设定值命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——归一化原始int16_t定点值,实际数值为value/32768.0。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——设定值限定词QL,0..127;编码到QOS低7位。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalizedWithCP56Time2a_Create(IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *self,
|
||
uint32_t ioa, int16_t value, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_SetpointCommandNormalizedWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 127 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = value;
|
||
result.base.is_select = (uint8_t)is_select;
|
||
result.base.qualifier = (uint8_t)qualifier;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &SetpointCommandNormalizedWithCP56Time2a_VTable);
|
||
if (!SetpointCommandNormalizedWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 61(带时标归一化设定值命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的10字节载荷,必须非空。
|
||
* length——必须恰好为10;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalizedWithCP56Time2a_Get_From_Buffer(IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SetpointCommandNormalizedWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 10U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SetpointCommandNormalizedWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &SetpointCommandNormalizedWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 62:带时标标度化设定值命令 ---- */
|
||
/**
|
||
* 功能:编码Type 62(带时标标度化设定值命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少10字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:SVA(2)+QOS(1):标度值;QOS低7位为QL,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 值部分调用SetpointCommandScaled_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SetpointCommandScaledWithCP56Time2a_Encode_Value(const IEC60870_SetpointCommandScaledWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return SetpointCommandScaled_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 3, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 62(带时标标度化设定值命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有10字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:SVA(2)+QOS(1):标度值;QOS低7位为QL,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SetpointCommandScaledWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_SetpointCommandScaledWithCP56Time2a_t *self)
|
||
{
|
||
return SetpointCommandScaled_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 3, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 62编码函数表的适配入口,将公共基类还原为SetpointCommandScaledWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少10字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SetpointCommandScaledWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SetpointCommandScaledWithCP56Time2a_Encode_Value((const IEC60870_SetpointCommandScaledWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SetpointCommandScaledWithCP56Time2a_VTable = {
|
||
62, 10, 1, sizeof(IEC60870_SetpointCommandScaledWithCP56Time2a_t), SetpointCommandScaledWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 62(带时标标度化设定值命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——有符号16位标度值,范围-32768..32767。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——设定值限定词QL,0..127;编码到QOS低7位。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandScaledWithCP56Time2a_Create(IEC60870_SetpointCommandScaledWithCP56Time2a_t *self,
|
||
uint32_t ioa, int16_t value, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_SetpointCommandScaledWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 127 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = value;
|
||
result.base.is_select = (uint8_t)is_select;
|
||
result.base.qualifier = (uint8_t)qualifier;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &SetpointCommandScaledWithCP56Time2a_VTable);
|
||
if (!SetpointCommandScaledWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 62(带时标标度化设定值命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的10字节载荷,必须非空。
|
||
* length——必须恰好为10;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandScaledWithCP56Time2a_Get_From_Buffer(IEC60870_SetpointCommandScaledWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SetpointCommandScaledWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 10U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SetpointCommandScaledWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &SetpointCommandScaledWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 63:带时标短浮点设定值命令 ---- */
|
||
/**
|
||
* 功能:编码Type 63(带时标短浮点设定值命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少12字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:短浮点(4)+QOS(1):浮点位模式;QOS低7位为QL,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 值部分调用SetpointCommandShort_Encode_Value,成功后追加7字节CP56。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int SetpointCommandShortWithCP56Time2a_Encode_Value(const IEC60870_SetpointCommandShortWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return SetpointCommandShort_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 5, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 63(带时标短浮点设定值命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有12字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:短浮点(4)+QOS(1):浮点位模式;QOS低7位为QL,bit7为S/E,之后追加CP56Time2a(7)。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int SetpointCommandShortWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_SetpointCommandShortWithCP56Time2a_t *self)
|
||
{
|
||
return SetpointCommandShort_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 5, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 63编码函数表的适配入口,将公共基类还原为SetpointCommandShortWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少12字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int SetpointCommandShortWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SetpointCommandShortWithCP56Time2a_Encode_Value((const IEC60870_SetpointCommandShortWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable SetpointCommandShortWithCP56Time2a_VTable = {
|
||
63, 12, 1, sizeof(IEC60870_SetpointCommandShortWithCP56Time2a_t), SetpointCommandShortWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 63(带时标短浮点设定值命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* value——短浮点值,采用IEEE 754 binary32,不进行NaN/Inf业务过滤。
|
||
* is_select——选择/执行标志S/E,1为选择、0为执行;本函数不执行命令。
|
||
* qualifier——设定值限定词QL,0..127;编码到QOS低7位。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandShortWithCP56Time2a_Create(IEC60870_SetpointCommandShortWithCP56Time2a_t *self,
|
||
uint32_t ioa, float value, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_SetpointCommandShortWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
is_select < 0 || is_select > 1 ||
|
||
qualifier < 0 || qualifier > 127 ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.base.value = value;
|
||
result.base.is_select = (uint8_t)is_select;
|
||
result.base.qualifier = (uint8_t)qualifier;
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &SetpointCommandShortWithCP56Time2a_VTable);
|
||
if (!SetpointCommandShortWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 63(带时标短浮点设定值命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的12字节载荷,必须非空。
|
||
* length——必须恰好为12;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SetpointCommandShortWithCP56Time2a_Get_From_Buffer(IEC60870_SetpointCommandShortWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SetpointCommandShortWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 12U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SetpointCommandShortWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.base.object, ioa, &SetpointCommandShortWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 100:总召唤命令 ---- */
|
||
/**
|
||
* 功能:编码Type 100(总召唤命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:QOI(1):总召唤限定词,整字节保存,业务层判断召唤范围。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int InterrogationCommand_Encode_Value(const IEC60870_InterrogationCommand_t *self, uint8_t *payload)
|
||
{
|
||
payload[0] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 100(总召唤命令)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:QOI(1):总召唤限定词,整字节保存,业务层判断召唤范围。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int InterrogationCommand_Decode_Value(const uint8_t *payload, IEC60870_InterrogationCommand_t *self)
|
||
{
|
||
self->qualifier = payload[0];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 100编码函数表的适配入口,将公共基类还原为InterrogationCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int InterrogationCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return InterrogationCommand_Encode_Value((const IEC60870_InterrogationCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable InterrogationCommand_VTable = {
|
||
100, 1, 1, sizeof(IEC60870_InterrogationCommand_t), InterrogationCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 100(总召唤命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* qualifier——总召唤限定词QOI,0..255;本层保留全部编码值。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_InterrogationCommand_Create(IEC60870_InterrogationCommand_t *self,
|
||
uint32_t ioa, int qualifier)
|
||
{
|
||
IEC60870_InterrogationCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
qualifier < 0 || qualifier > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &InterrogationCommand_VTable);
|
||
if (!InterrogationCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 100(总召唤命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_InterrogationCommand_Get_From_Buffer(IEC60870_InterrogationCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_InterrogationCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!InterrogationCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &InterrogationCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 101:电能脉冲召唤命令 ---- */
|
||
/**
|
||
* 功能:编码Type 101(电能脉冲召唤命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:QCC(1):低6位为请求限定词RQT,高2位为冻结限定词FR。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int CounterInterrogationCommand_Encode_Value(const IEC60870_CounterInterrogationCommand_t *self, uint8_t *payload)
|
||
{
|
||
if (self->qualifier > 63U || self->freeze > 3U) { return 0; }
|
||
/* QCC:低6位RQT,高2位FR。 */
|
||
payload[0] = (uint8_t)(self->qualifier | (self->freeze << 6));
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 101(电能脉冲召唤命令)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:QCC(1):低6位为请求限定词RQT,高2位为冻结限定词FR。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int CounterInterrogationCommand_Decode_Value(const uint8_t *payload, IEC60870_CounterInterrogationCommand_t *self)
|
||
{
|
||
self->qualifier = payload[0] & 63U;
|
||
self->freeze = payload[0] >> 6;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 101编码函数表的适配入口,将公共基类还原为CounterInterrogationCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int CounterInterrogationCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return CounterInterrogationCommand_Encode_Value((const IEC60870_CounterInterrogationCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable CounterInterrogationCommand_VTable = {
|
||
101, 1, 1, sizeof(IEC60870_CounterInterrogationCommand_t), CounterInterrogationCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 101(电能脉冲召唤命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* qualifier——电能脉冲请求限定词RQT,0..63。
|
||
* freeze——冻结限定词FR,0..3,编码到QCC高2位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_CounterInterrogationCommand_Create(IEC60870_CounterInterrogationCommand_t *self,
|
||
uint32_t ioa, int qualifier, int freeze)
|
||
{
|
||
IEC60870_CounterInterrogationCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
qualifier < 0 || qualifier > 63 ||
|
||
freeze < 0 || freeze > 3) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.qualifier = (uint8_t)qualifier;
|
||
result.freeze = (uint8_t)freeze;
|
||
Initialize_Object(&result.object, ioa, &CounterInterrogationCommand_VTable);
|
||
if (!CounterInterrogationCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 101(电能脉冲召唤命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_CounterInterrogationCommand_Get_From_Buffer(IEC60870_CounterInterrogationCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_CounterInterrogationCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!CounterInterrogationCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &CounterInterrogationCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 102:读命令 ---- */
|
||
/**
|
||
* 功能:编码Type 102(读命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少0字节的临时区;本类型不访问该区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:无值载荷:报文只包含由ASDU层处理的IOA。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int ReadCommand_Encode_Value(const IEC60870_ReadCommand_t *self, uint8_t *payload)
|
||
{
|
||
/* 读命令仅含IOA,无值载荷;不解引用payload。 */
|
||
(void)self;
|
||
(void)payload;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 102(读命令)的值字段。
|
||
* 输入参数:payload——已确认有0字节的载荷;允许NULL,函数不解引用。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:无值载荷:报文只包含由ASDU层处理的IOA。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int ReadCommand_Decode_Value(const uint8_t *payload, IEC60870_ReadCommand_t *self)
|
||
{
|
||
/* 读命令仅含IOA,无值载荷;不解引用payload。 */
|
||
(void)self;
|
||
(void)payload;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 102编码函数表的适配入口,将公共基类还原为ReadCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少0字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int ReadCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ReadCommand_Encode_Value((const IEC60870_ReadCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable ReadCommand_VTable = {
|
||
102, 0, 1, sizeof(IEC60870_ReadCommand_t), ReadCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 102(读命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ReadCommand_Create(IEC60870_ReadCommand_t *self,
|
||
uint32_t ioa)
|
||
{
|
||
IEC60870_ReadCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
Initialize_Object(&result.object, ioa, &ReadCommand_VTable);
|
||
if (!ReadCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 102(读命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的0字节载荷,允许NULL。
|
||
* length——必须恰好为0;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ReadCommand_Get_From_Buffer(IEC60870_ReadCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ReadCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 0U) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ReadCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &ReadCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 103:时钟同步命令 ---- */
|
||
/**
|
||
* 功能:编码Type 103(时钟同步命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少7字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:CP56Time2a(7):源时间及IV/SU,不执行系统校时。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int ClockSynchronizationCommand_Encode_Value(const IEC60870_ClockSynchronizationCommand_t *self, uint8_t *payload)
|
||
{
|
||
return IEC60870_Time_To_CP56(&self->time, payload, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 103(时钟同步命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有7字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:CP56Time2a(7):源时间及IV/SU,不执行系统校时。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int ClockSynchronizationCommand_Decode_Value(const uint8_t *payload, IEC60870_ClockSynchronizationCommand_t *self)
|
||
{
|
||
return IEC60870_Time_From_CP56(payload, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 103编码函数表的适配入口,将公共基类还原为ClockSynchronizationCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少7字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int ClockSynchronizationCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ClockSynchronizationCommand_Encode_Value((const IEC60870_ClockSynchronizationCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable ClockSynchronizationCommand_VTable = {
|
||
103, 7, 1, sizeof(IEC60870_ClockSynchronizationCommand_t), ClockSynchronizationCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 103(时钟同步命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ClockSynchronizationCommand_Create(IEC60870_ClockSynchronizationCommand_t *self,
|
||
uint32_t ioa, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_ClockSynchronizationCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &ClockSynchronizationCommand_VTable);
|
||
if (!ClockSynchronizationCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 103(时钟同步命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的7字节载荷,必须非空。
|
||
* length——必须恰好为7;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ClockSynchronizationCommand_Get_From_Buffer(IEC60870_ClockSynchronizationCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ClockSynchronizationCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 7U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ClockSynchronizationCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &ClockSynchronizationCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 105:复位进程命令 ---- */
|
||
/**
|
||
* 功能:编码Type 105(复位进程命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:QRP(1):复位进程限定词,整字节保存,业务层判断操作含义。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int ResetProcessCommand_Encode_Value(const IEC60870_ResetProcessCommand_t *self, uint8_t *payload)
|
||
{
|
||
payload[0] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 105(复位进程命令)的值字段。
|
||
* 输入参数:payload——已确认有1字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:QRP(1):复位进程限定词,整字节保存,业务层判断操作含义。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int ResetProcessCommand_Decode_Value(const uint8_t *payload, IEC60870_ResetProcessCommand_t *self)
|
||
{
|
||
self->qualifier = payload[0];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 105编码函数表的适配入口,将公共基类还原为ResetProcessCommand对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少1字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int ResetProcessCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ResetProcessCommand_Encode_Value((const IEC60870_ResetProcessCommand_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable ResetProcessCommand_VTable = {
|
||
105, 1, 1, sizeof(IEC60870_ResetProcessCommand_t), ResetProcessCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 105(复位进程命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* qualifier——复位进程限定词QRP,0..255;本层不执行复位。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* 仅创建内存对象;加入ASDU时才按应用层参数编码IOA并检查报文容量。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ResetProcessCommand_Create(IEC60870_ResetProcessCommand_t *self,
|
||
uint32_t ioa, int qualifier)
|
||
{
|
||
IEC60870_ResetProcessCommand_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
qualifier < 0 || qualifier > 255) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &ResetProcessCommand_VTable);
|
||
if (!ResetProcessCommand_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 105(复位进程命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的1字节载荷,必须非空。
|
||
* length——必须恰好为1;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ResetProcessCommand_Get_From_Buffer(IEC60870_ResetProcessCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ResetProcessCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 1U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ResetProcessCommand_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &ResetProcessCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 107:带时标测试命令 ---- */
|
||
/**
|
||
* 功能:编码Type 107(带时标测试命令)的值载荷,不处理IOA或ASDU头。
|
||
* 输入参数:self——非空具体对象;只检查本类型的值字段,不核对公共基类身份。
|
||
* 输出参数:payload——至少9字节的临时区。
|
||
* 返回值:1表示字段合法且编码完成;0表示字段或时标非法。
|
||
* 说明:布局:测试序号(2)+CP56Time2a(7):测试序号与链路发送序号无关。
|
||
* 多字节整数和浮点字节均低字节在前,结构体不直接映射报文。
|
||
* 失败可以留下部分临时字节;公开入口只在全部验证成功后写入用户缓冲区。
|
||
*/
|
||
static int TestCommandWithCP56Time2a_Encode_Value(const IEC60870_TestCommandWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, self->sequence, 2);
|
||
return IEC60870_Time_To_CP56(&self->time, payload + 2, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码Type 107(带时标测试命令)的值字段和CP56时标。
|
||
* 输入参数:payload——已确认有9字节的载荷。
|
||
* 输出参数:self——调用方已清零的临时具体对象;不填写IOA、Type ID或函数表。
|
||
* 返回值:1表示解码成功;0表示保留位、状态或时标不合法。
|
||
* 说明:布局:测试序号(2)+CP56Time2a(7):测试序号与链路发送序号无关。
|
||
* 本内部函数不重复检查指针/长度,失败可留下部分字段,由公开解析器丢弃临时结果。
|
||
*/
|
||
static int TestCommandWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_TestCommandWithCP56Time2a_t *self)
|
||
{
|
||
self->sequence = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
return IEC60870_Time_From_CP56(payload + 2, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:Type 107编码函数表的适配入口,将公共基类还原为TestCommandWithCP56Time2a对象。
|
||
* 输入参数:object——来自该具体类型的公共首成员指针;调用前已核对Type ID和函数表。
|
||
* 输出参数:payload——至少9字节的临时载荷区,不包含IOA。
|
||
* 返回值:1表示值编码成功;0表示字段或时标非法。
|
||
* 说明:类型转换依赖结构体首成员地址相同的约定,不能向此入口传入伪造基类。
|
||
*/
|
||
static int TestCommandWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return TestCommandWithCP56Time2a_Encode_Value((const IEC60870_TestCommandWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
/* 表项依次为Type ID、线上载荷字节数、单对象标志、内存结构尺寸、编码入口。
|
||
* sizeof仅用于检查解码输出存储,不能作为报文载荷长度。 */
|
||
static const IEC60870_InformationObjectVTable TestCommandWithCP56Time2a_VTable = {
|
||
107, 9, 1, sizeof(IEC60870_TestCommandWithCP56Time2a_t), TestCommandWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 107(带时标测试命令)。
|
||
* 输入参数:ioa——信息对象地址,0..0xFFFFFF;编码时再按配置的IOA宽度检查上限。
|
||
* sequence——16位测试序号,0..65535,与APCI的N(S)/N(R)无关。
|
||
* time——非空CP56日历指针,采用2000..2099年约定;保留IV/SU,成功后按值复制。
|
||
* 输出参数:self——非空具体对象存储;成功时写入值、IOA、类型和只读编码函数表。
|
||
* 返回值:IEC60870_ASDU_OK表示构造完成;IEC60870_ASDU_ERROR表示参数、字段或时标非法。
|
||
* 说明:不分配堆内存。先在局部对象中试编码校验,再整体写回self;失败保持原对象不变。
|
||
* BCR/CP56输入按值复制,返回后调用方可以复用输入;构造成功不表示命令已执行。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_TestCommandWithCP56Time2a_Create(IEC60870_TestCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, uint16_t sequence, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_TestCommandWithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL ||
|
||
ioa > IEC60870_ASDU_MAX_IOA ||
|
||
time == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
result.sequence = sequence;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &TestCommandWithCP56Time2a_VTable);
|
||
if (!TestCommandWithCP56Time2a_Encode_Value(&result, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:从精确长度载荷中解析Type 107(带时标测试命令)。
|
||
* 输入参数:ioa——已从对象区提取的地址,0..0xFFFFFF;SQ隐含地址由ASDU层还原。
|
||
* payload——不包含IOA或ASDU头的9字节载荷,必须非空。
|
||
* length——必须恰好为9;截短和多余尾字节均拒绝。
|
||
* 输出参数:self——非空具体对象存储;成功结果按值保存,不借用输入。
|
||
* 返回值:IEC60870_ASDU_OK表示解析完成;IEC60870_ASDU_ERROR表示地址、长度或字段非法。
|
||
* 说明:仅在值与可选时标全部通过校验后绑定基类并写回self,任何失败保持原对象不变。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_TestCommandWithCP56Time2a_Get_From_Buffer(IEC60870_TestCommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_TestCommandWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || length != 9U || payload == NULL) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
memset(&result, 0, sizeof(result));
|
||
if (!TestCommandWithCP56Time2a_Decode_Value(payload, &result)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
Initialize_Object(&result.object, ioa, &TestCommandWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 5:步位置信息 ---- */
|
||
/**
|
||
* 功能:编码步位置信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少2字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:VTI(1:低7位补码位置、bit7瞬态) + QDS(1);失败只影响临时区。
|
||
*/
|
||
static int StepPositionInformation_Encode_Value(const IEC60870_StepPositionInformation_t *self, uint8_t *payload)
|
||
{
|
||
if (self->value < -64 || self->value > 63 || self->is_transient > 1U || (self->quality & 0x0EU)) { return 0; }
|
||
payload[0] = (uint8_t)(((uint8_t)self->value & 0x7FU) | (self->is_transient << 7));
|
||
payload[1] = self->quality;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码步位置信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的2字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:VTI(1:低7位补码位置、bit7瞬态) + QDS(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int StepPositionInformation_Decode_Value(const uint8_t *payload, IEC60870_StepPositionInformation_t *self)
|
||
{
|
||
if (payload[1] & 0x0EU) { return 0; }
|
||
self->value = (int8_t)((payload[0] & 0x40U) ? (int)(payload[0] & 0x7FU) - 128 : (int)(payload[0] & 0x7FU));
|
||
self->is_transient = payload[0] >> 7;
|
||
self->quality = payload[1];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到StepPositionInformation编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int StepPositionInformation_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return StepPositionInformation_Encode_Value((const IEC60870_StepPositionInformation_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable StepPositionInformation_VTable = {
|
||
5, 2, 0, sizeof(IEC60870_StepPositionInformation_t), StepPositionInformation_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 5(步位置信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepPositionInformation_Create(IEC60870_StepPositionInformation_t *self,
|
||
uint32_t ioa, int value, int is_transient, int quality)
|
||
{
|
||
IEC60870_StepPositionInformation_t result;
|
||
uint8_t payload[2];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(value < -64 || value > 63) ||
|
||
(is_transient < 0 || is_transient > 1) ||
|
||
(quality < 0 || quality > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = (int8_t)value;
|
||
result.is_transient = (uint8_t)is_transient;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &StepPositionInformation_VTable);
|
||
if (!StepPositionInformation_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 5(步位置信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepPositionInformation_Get_From_Buffer(IEC60870_StepPositionInformation_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_StepPositionInformation_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 2U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!StepPositionInformation_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &StepPositionInformation_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 7:32位比特串监视 ---- */
|
||
/**
|
||
* 功能:编码32位比特串监视的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:BSI(4) + QDS(1);失败只影响临时区。
|
||
*/
|
||
static int BitString32_Encode_Value(const IEC60870_BitString32_t *self, uint8_t *payload)
|
||
{
|
||
if (self->quality & 0x0EU) { return 0; }
|
||
IEC60870_Object_Write_LE(payload + 0, self->value, 4);
|
||
payload[4] = self->quality;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码32位比特串监视的值字段。
|
||
* 输入参数:payload——已校验完整长度的5字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:BSI(4) + QDS(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int BitString32_Decode_Value(const uint8_t *payload, IEC60870_BitString32_t *self)
|
||
{
|
||
if (payload[4] & 0x0EU) { return 0; }
|
||
self->value = (uint32_t)IEC60870_Object_Read_LE(payload + 0, 4);
|
||
self->quality = payload[4];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到BitString32编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int BitString32_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return BitString32_Encode_Value((const IEC60870_BitString32_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable BitString32_VTable = {
|
||
7, 5, 0, sizeof(IEC60870_BitString32_t), BitString32_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 7(32位比特串监视)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_BitString32_Create(IEC60870_BitString32_t *self,
|
||
uint32_t ioa, uint32_t value, int quality)
|
||
{
|
||
IEC60870_BitString32_t result;
|
||
uint8_t payload[5];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(quality < 0 || quality > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &BitString32_VTable);
|
||
if (!BitString32_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 7(32位比特串监视)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_BitString32_Get_From_Buffer(IEC60870_BitString32_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_BitString32_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 5U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!BitString32_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &BitString32_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 2:带CP24单点信息 ---- */
|
||
/**
|
||
* 功能:编码带CP24单点信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少4字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(1) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int SinglePointWithCP24Time2a_Encode_Value(const IEC60870_SinglePointWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return SinglePointInformation_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 1, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24单点信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的4字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(1) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int SinglePointWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_SinglePointWithCP24Time2a_t *self)
|
||
{
|
||
return SinglePointInformation_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 1, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到SinglePointWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int SinglePointWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SinglePointWithCP24Time2a_Encode_Value((const IEC60870_SinglePointWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable SinglePointWithCP24Time2a_VTable = {
|
||
2, 4, 0, sizeof(IEC60870_SinglePointWithCP24Time2a_t), SinglePointWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 2(带CP24单点信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SinglePointWithCP24Time2a_Create(IEC60870_SinglePointWithCP24Time2a_t *self,
|
||
uint32_t ioa, int value, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_SinglePointWithCP24Time2a_t result;
|
||
uint8_t payload[4];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_SinglePointInformation_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &SinglePointWithCP24Time2a_VTable);
|
||
if (!SinglePointWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 2(带CP24单点信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SinglePointWithCP24Time2a_Get_From_Buffer(IEC60870_SinglePointWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SinglePointWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 4U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SinglePointWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &SinglePointWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 4:带CP24双点信息 ---- */
|
||
/**
|
||
* 功能:编码带CP24双点信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少4字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(1) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int DoublePointWithCP24Time2a_Encode_Value(const IEC60870_DoublePointWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return DoublePointInformation_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 1, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24双点信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的4字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(1) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int DoublePointWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_DoublePointWithCP24Time2a_t *self)
|
||
{
|
||
return DoublePointInformation_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 1, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到DoublePointWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int DoublePointWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return DoublePointWithCP24Time2a_Encode_Value((const IEC60870_DoublePointWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable DoublePointWithCP24Time2a_VTable = {
|
||
4, 4, 0, sizeof(IEC60870_DoublePointWithCP24Time2a_t), DoublePointWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 4(带CP24双点信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoublePointWithCP24Time2a_Create(IEC60870_DoublePointWithCP24Time2a_t *self,
|
||
uint32_t ioa, int value, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_DoublePointWithCP24Time2a_t result;
|
||
uint8_t payload[4];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_DoublePointInformation_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &DoublePointWithCP24Time2a_VTable);
|
||
if (!DoublePointWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 4(带CP24双点信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DoublePointWithCP24Time2a_Get_From_Buffer(IEC60870_DoublePointWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_DoublePointWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 4U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!DoublePointWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &DoublePointWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 6:带CP24步位置信息 ---- */
|
||
/**
|
||
* 功能:编码带CP24步位置信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(2) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int StepPositionWithCP24Time2a_Encode_Value(const IEC60870_StepPositionWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return StepPositionInformation_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 2, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24步位置信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的5字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(2) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int StepPositionWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_StepPositionWithCP24Time2a_t *self)
|
||
{
|
||
return StepPositionInformation_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 2, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到StepPositionWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int StepPositionWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return StepPositionWithCP24Time2a_Encode_Value((const IEC60870_StepPositionWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable StepPositionWithCP24Time2a_VTable = {
|
||
6, 5, 0, sizeof(IEC60870_StepPositionWithCP24Time2a_t), StepPositionWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 6(带CP24步位置信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepPositionWithCP24Time2a_Create(IEC60870_StepPositionWithCP24Time2a_t *self,
|
||
uint32_t ioa, int value, int is_transient, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_StepPositionWithCP24Time2a_t result;
|
||
uint8_t payload[5];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_StepPositionInformation_Create(&result.base, ioa, value, is_transient, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &StepPositionWithCP24Time2a_VTable);
|
||
if (!StepPositionWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 6(带CP24步位置信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepPositionWithCP24Time2a_Get_From_Buffer(IEC60870_StepPositionWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_StepPositionWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 5U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!StepPositionWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &StepPositionWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 8:带CP24比特串监视 ---- */
|
||
/**
|
||
* 功能:编码带CP24比特串监视的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(5) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int Bitstring32WithCP24Time2a_Encode_Value(const IEC60870_Bitstring32WithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return BitString32_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 5, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24比特串监视的值字段。
|
||
* 输入参数:payload——已校验完整长度的8字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(5) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int Bitstring32WithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_Bitstring32WithCP24Time2a_t *self)
|
||
{
|
||
return BitString32_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 5, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到Bitstring32WithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int Bitstring32WithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return Bitstring32WithCP24Time2a_Encode_Value((const IEC60870_Bitstring32WithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable Bitstring32WithCP24Time2a_VTable = {
|
||
8, 8, 0, sizeof(IEC60870_Bitstring32WithCP24Time2a_t), Bitstring32WithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 8(带CP24比特串监视)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP24Time2a_Create(IEC60870_Bitstring32WithCP24Time2a_t *self,
|
||
uint32_t ioa, uint32_t value, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_Bitstring32WithCP24Time2a_t result;
|
||
uint8_t payload[8];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_BitString32_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &Bitstring32WithCP24Time2a_VTable);
|
||
if (!Bitstring32WithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 8(带CP24比特串监视)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP24Time2a_Get_From_Buffer(IEC60870_Bitstring32WithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_Bitstring32WithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 8U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!Bitstring32WithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &Bitstring32WithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 10:带CP24归一化测量值 ---- */
|
||
/**
|
||
* 功能:编码带CP24归一化测量值的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少6字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(3) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int MeasuredValueNormalizedWithCP24Time2a_Encode_Value(const IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return MeasuredValueNormalized_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 3, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24归一化测量值的值字段。
|
||
* 输入参数:payload——已校验完整长度的6字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(3) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int MeasuredValueNormalizedWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *self)
|
||
{
|
||
return MeasuredValueNormalized_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 3, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到MeasuredValueNormalizedWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int MeasuredValueNormalizedWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueNormalizedWithCP24Time2a_Encode_Value((const IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable MeasuredValueNormalizedWithCP24Time2a_VTable = {
|
||
10, 6, 0, sizeof(IEC60870_MeasuredValueNormalizedWithCP24Time2a_t), MeasuredValueNormalizedWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 10(带CP24归一化测量值)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP24Time2a_Create(IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *self,
|
||
uint32_t ioa, int16_t value, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_MeasuredValueNormalizedWithCP24Time2a_t result;
|
||
uint8_t payload[6];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_MeasuredValueNormalized_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueNormalizedWithCP24Time2a_VTable);
|
||
if (!MeasuredValueNormalizedWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 10(带CP24归一化测量值)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP24Time2a_Get_From_Buffer(IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueNormalizedWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 6U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueNormalizedWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueNormalizedWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 12:带CP24标度化测量值 ---- */
|
||
/**
|
||
* 功能:编码带CP24标度化测量值的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少6字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(3) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int MeasuredValueScaledWithCP24Time2a_Encode_Value(const IEC60870_MeasuredValueScaledWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return MeasuredValueScaled_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 3, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24标度化测量值的值字段。
|
||
* 输入参数:payload——已校验完整长度的6字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(3) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int MeasuredValueScaledWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueScaledWithCP24Time2a_t *self)
|
||
{
|
||
return MeasuredValueScaled_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 3, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到MeasuredValueScaledWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int MeasuredValueScaledWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueScaledWithCP24Time2a_Encode_Value((const IEC60870_MeasuredValueScaledWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable MeasuredValueScaledWithCP24Time2a_VTable = {
|
||
12, 6, 0, sizeof(IEC60870_MeasuredValueScaledWithCP24Time2a_t), MeasuredValueScaledWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 12(带CP24标度化测量值)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP24Time2a_Create(IEC60870_MeasuredValueScaledWithCP24Time2a_t *self,
|
||
uint32_t ioa, int16_t value, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_MeasuredValueScaledWithCP24Time2a_t result;
|
||
uint8_t payload[6];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_MeasuredValueScaled_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueScaledWithCP24Time2a_VTable);
|
||
if (!MeasuredValueScaledWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 12(带CP24标度化测量值)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP24Time2a_Get_From_Buffer(IEC60870_MeasuredValueScaledWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueScaledWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 6U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueScaledWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueScaledWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 14:带CP24短浮点测量值 ---- */
|
||
/**
|
||
* 功能:编码带CP24短浮点测量值的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(5) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int MeasuredValueShortWithCP24Time2a_Encode_Value(const IEC60870_MeasuredValueShortWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return MeasuredValueShort_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 5, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24短浮点测量值的值字段。
|
||
* 输入参数:payload——已校验完整长度的8字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(5) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int MeasuredValueShortWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueShortWithCP24Time2a_t *self)
|
||
{
|
||
return MeasuredValueShort_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 5, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到MeasuredValueShortWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int MeasuredValueShortWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueShortWithCP24Time2a_Encode_Value((const IEC60870_MeasuredValueShortWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable MeasuredValueShortWithCP24Time2a_VTable = {
|
||
14, 8, 0, sizeof(IEC60870_MeasuredValueShortWithCP24Time2a_t), MeasuredValueShortWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 14(带CP24短浮点测量值)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP24Time2a_Create(IEC60870_MeasuredValueShortWithCP24Time2a_t *self,
|
||
uint32_t ioa, float value, int quality, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_MeasuredValueShortWithCP24Time2a_t result;
|
||
uint8_t payload[8];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_MeasuredValueShort_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueShortWithCP24Time2a_VTable);
|
||
if (!MeasuredValueShortWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 14(带CP24短浮点测量值)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP24Time2a_Get_From_Buffer(IEC60870_MeasuredValueShortWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueShortWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 8U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueShortWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &MeasuredValueShortWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 16:带CP24累计量 ---- */
|
||
/**
|
||
* 功能:编码带CP24累计量的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少8字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(5) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int IntegratedTotalsWithCP24Time2a_Encode_Value(const IEC60870_IntegratedTotalsWithCP24Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return IntegratedTotals_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 5, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24累计量的值字段。
|
||
* 输入参数:payload——已校验完整长度的8字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(5) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int IntegratedTotalsWithCP24Time2a_Decode_Value(const uint8_t *payload, IEC60870_IntegratedTotalsWithCP24Time2a_t *self)
|
||
{
|
||
return IntegratedTotals_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP24(payload + 5, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到IntegratedTotalsWithCP24Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int IntegratedTotalsWithCP24Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return IntegratedTotalsWithCP24Time2a_Encode_Value((const IEC60870_IntegratedTotalsWithCP24Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable IntegratedTotalsWithCP24Time2a_VTable = {
|
||
16, 8, 0, sizeof(IEC60870_IntegratedTotalsWithCP24Time2a_t), IntegratedTotalsWithCP24Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 16(带CP24累计量)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP24Time2a_Create(IEC60870_IntegratedTotalsWithCP24Time2a_t *self,
|
||
uint32_t ioa, const IEC60870_BinaryCounterReading_t *value, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_IntegratedTotalsWithCP24Time2a_t result;
|
||
uint8_t payload[8];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_IntegratedTotals_Create(&result.base, ioa, value) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &IntegratedTotalsWithCP24Time2a_VTable);
|
||
if (!IntegratedTotalsWithCP24Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 16(带CP24累计量)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP24Time2a_Get_From_Buffer(IEC60870_IntegratedTotalsWithCP24Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_IntegratedTotalsWithCP24Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 8U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!IntegratedTotalsWithCP24Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &IntegratedTotalsWithCP24Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 32:带CP56步位置信息 ---- */
|
||
/**
|
||
* 功能:编码带CP56步位置信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少9字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(2) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int StepPositionWithCP56Time2a_Encode_Value(const IEC60870_StepPositionWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return StepPositionInformation_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 2, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP56步位置信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的9字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(2) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int StepPositionWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_StepPositionWithCP56Time2a_t *self)
|
||
{
|
||
return StepPositionInformation_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 2, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到StepPositionWithCP56Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int StepPositionWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return StepPositionWithCP56Time2a_Encode_Value((const IEC60870_StepPositionWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable StepPositionWithCP56Time2a_VTable = {
|
||
32, 9, 0, sizeof(IEC60870_StepPositionWithCP56Time2a_t), StepPositionWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 32(带CP56步位置信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepPositionWithCP56Time2a_Create(IEC60870_StepPositionWithCP56Time2a_t *self,
|
||
uint32_t ioa, int value, int is_transient, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_StepPositionWithCP56Time2a_t result;
|
||
uint8_t payload[9];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_StepPositionInformation_Create(&result.base, ioa, value, is_transient, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &StepPositionWithCP56Time2a_VTable);
|
||
if (!StepPositionWithCP56Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 32(带CP56步位置信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_StepPositionWithCP56Time2a_Get_From_Buffer(IEC60870_StepPositionWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_StepPositionWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 9U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!StepPositionWithCP56Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &StepPositionWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 33:带CP56比特串监视 ---- */
|
||
/**
|
||
* 功能:编码带CP56比特串监视的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少12字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(5) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int Bitstring32WithCP56Time2a_Encode_Value(const IEC60870_Bitstring32WithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return BitString32_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 5, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP56比特串监视的值字段。
|
||
* 输入参数:payload——已校验完整长度的12字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(5) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int Bitstring32WithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_Bitstring32WithCP56Time2a_t *self)
|
||
{
|
||
return BitString32_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 5, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到Bitstring32WithCP56Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int Bitstring32WithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return Bitstring32WithCP56Time2a_Encode_Value((const IEC60870_Bitstring32WithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable Bitstring32WithCP56Time2a_VTable = {
|
||
33, 12, 0, sizeof(IEC60870_Bitstring32WithCP56Time2a_t), Bitstring32WithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 33(带CP56比特串监视)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP56Time2a_Create(IEC60870_Bitstring32WithCP56Time2a_t *self,
|
||
uint32_t ioa, uint32_t value, int quality, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_Bitstring32WithCP56Time2a_t result;
|
||
uint8_t payload[12];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_BitString32_Create(&result.base, ioa, value, quality) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &Bitstring32WithCP56Time2a_VTable);
|
||
if (!Bitstring32WithCP56Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 33(带CP56比特串监视)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP56Time2a_Get_From_Buffer(IEC60870_Bitstring32WithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_Bitstring32WithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 12U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!Bitstring32WithCP56Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &Bitstring32WithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 17:带CP24保护事件 ---- */
|
||
/**
|
||
* 功能:编码带CP24保护事件的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少6字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:SEP(1:ES低2位,QDP高5位) + CP16(2) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int EventOfProtectionEquipment_Encode_Value(const IEC60870_EventOfProtectionEquipment_t *self, uint8_t *payload)
|
||
{
|
||
if (self->event > 3U || (self->quality & 0x07U)) { return 0; }
|
||
payload[0] = (uint8_t)(self->event | self->quality);
|
||
return IEC60870_Time_To_CP16(&self->elapsed_time, payload + 1, IEC60870_CP16_LEN) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 3, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24保护事件的值字段。
|
||
* 输入参数:payload——已校验完整长度的6字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:SEP(1:ES低2位,QDP高5位) + CP16(2) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int EventOfProtectionEquipment_Decode_Value(const uint8_t *payload, IEC60870_EventOfProtectionEquipment_t *self)
|
||
{
|
||
if (payload[0] & 0x04U) { return 0; }
|
||
self->event = payload[0] & 0x03U;
|
||
self->quality = payload[0] & 0xF8U;
|
||
return IEC60870_Time_From_CP16(payload + 1, IEC60870_CP16_LEN, &self->elapsed_time) &&
|
||
IEC60870_Time_From_CP24(payload + 3, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到EventOfProtectionEquipment编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int EventOfProtectionEquipment_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return EventOfProtectionEquipment_Encode_Value((const IEC60870_EventOfProtectionEquipment_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable EventOfProtectionEquipment_VTable = {
|
||
17, 6, 0, sizeof(IEC60870_EventOfProtectionEquipment_t), EventOfProtectionEquipment_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 17(带CP24保护事件)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipment_Create(IEC60870_EventOfProtectionEquipment_t *self,
|
||
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_EventOfProtectionEquipment_t result;
|
||
uint8_t payload[6];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(event < 0 || event > 3) ||
|
||
(quality < 0 || quality > 255) ||
|
||
(elapsed_time == NULL) ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.event = (uint8_t)event;
|
||
result.quality = (uint8_t)quality;
|
||
result.elapsed_time = *elapsed_time;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &EventOfProtectionEquipment_VTable);
|
||
if (!EventOfProtectionEquipment_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 17(带CP24保护事件)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipment_Get_From_Buffer(IEC60870_EventOfProtectionEquipment_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_EventOfProtectionEquipment_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 6U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!EventOfProtectionEquipment_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &EventOfProtectionEquipment_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 18:带CP24成组保护启动事件 ---- */
|
||
/**
|
||
* 功能:编码带CP24成组保护启动事件的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少7字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int PackedStartEventsOfProtectionEquipment_Encode_Value(const IEC60870_PackedStartEventsOfProtectionEquipment_t *self, uint8_t *payload)
|
||
{
|
||
if (self->event > 63U || (self->quality & 0x07U)) { return 0; }
|
||
payload[0] = self->event;
|
||
payload[1] = self->quality;
|
||
return IEC60870_Time_To_CP16(&self->elapsed_time, payload + 2, IEC60870_CP16_LEN) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 4, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24成组保护启动事件的值字段。
|
||
* 输入参数:payload——已校验完整长度的7字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int PackedStartEventsOfProtectionEquipment_Decode_Value(const uint8_t *payload, IEC60870_PackedStartEventsOfProtectionEquipment_t *self)
|
||
{
|
||
if (payload[0] > 63U || (payload[1] & 0x07U)) { return 0; }
|
||
self->event = payload[0];
|
||
self->quality = payload[1];
|
||
return IEC60870_Time_From_CP16(payload + 2, IEC60870_CP16_LEN, &self->elapsed_time) &&
|
||
IEC60870_Time_From_CP24(payload + 4, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到PackedStartEventsOfProtectionEquipment编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int PackedStartEventsOfProtectionEquipment_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return PackedStartEventsOfProtectionEquipment_Encode_Value((const IEC60870_PackedStartEventsOfProtectionEquipment_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable PackedStartEventsOfProtectionEquipment_VTable = {
|
||
18, 7, 0, sizeof(IEC60870_PackedStartEventsOfProtectionEquipment_t), PackedStartEventsOfProtectionEquipment_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 18(带CP24成组保护启动事件)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipment_Create(IEC60870_PackedStartEventsOfProtectionEquipment_t *self,
|
||
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_PackedStartEventsOfProtectionEquipment_t result;
|
||
uint8_t payload[7];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(event < 0 || event > 63) ||
|
||
(quality < 0 || quality > 255) ||
|
||
(elapsed_time == NULL) ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.event = (uint8_t)event;
|
||
result.quality = (uint8_t)quality;
|
||
result.elapsed_time = *elapsed_time;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &PackedStartEventsOfProtectionEquipment_VTable);
|
||
if (!PackedStartEventsOfProtectionEquipment_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 18(带CP24成组保护启动事件)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipment_Get_From_Buffer(IEC60870_PackedStartEventsOfProtectionEquipment_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_PackedStartEventsOfProtectionEquipment_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 7U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!PackedStartEventsOfProtectionEquipment_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &PackedStartEventsOfProtectionEquipment_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 19:带CP24保护输出电路信息 ---- */
|
||
/**
|
||
* 功能:编码带CP24保护输出电路信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少7字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP24(3);失败只影响临时区。
|
||
*/
|
||
static int PackedOutputCircuitInfo_Encode_Value(const IEC60870_PackedOutputCircuitInfo_t *self, uint8_t *payload)
|
||
{
|
||
if (self->event > 15U || (self->quality & 0x07U)) { return 0; }
|
||
payload[0] = self->event;
|
||
payload[1] = self->quality;
|
||
return IEC60870_Time_To_CP16(&self->elapsed_time, payload + 2, IEC60870_CP16_LEN) &&
|
||
IEC60870_Time_To_CP24(&self->time, payload + 4, IEC60870_CP24_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP24保护输出电路信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的7字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP24(3);公开入口在成功后统一提交。
|
||
*/
|
||
static int PackedOutputCircuitInfo_Decode_Value(const uint8_t *payload, IEC60870_PackedOutputCircuitInfo_t *self)
|
||
{
|
||
if (payload[0] > 15U || (payload[1] & 0x07U)) { return 0; }
|
||
self->event = payload[0];
|
||
self->quality = payload[1];
|
||
return IEC60870_Time_From_CP16(payload + 2, IEC60870_CP16_LEN, &self->elapsed_time) &&
|
||
IEC60870_Time_From_CP24(payload + 4, IEC60870_CP24_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到PackedOutputCircuitInfo编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int PackedOutputCircuitInfo_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return PackedOutputCircuitInfo_Encode_Value((const IEC60870_PackedOutputCircuitInfo_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable PackedOutputCircuitInfo_VTable = {
|
||
19, 7, 0, sizeof(IEC60870_PackedOutputCircuitInfo_t), PackedOutputCircuitInfo_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 19(带CP24保护输出电路信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfo_Create(IEC60870_PackedOutputCircuitInfo_t *self,
|
||
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP24Time2a_t *time)
|
||
{
|
||
IEC60870_PackedOutputCircuitInfo_t result;
|
||
uint8_t payload[7];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(event < 0 || event > 15) ||
|
||
(quality < 0 || quality > 255) ||
|
||
(elapsed_time == NULL) ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.event = (uint8_t)event;
|
||
result.quality = (uint8_t)quality;
|
||
result.elapsed_time = *elapsed_time;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &PackedOutputCircuitInfo_VTable);
|
||
if (!PackedOutputCircuitInfo_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 19(带CP24保护输出电路信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfo_Get_From_Buffer(IEC60870_PackedOutputCircuitInfo_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_PackedOutputCircuitInfo_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 7U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!PackedOutputCircuitInfo_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &PackedOutputCircuitInfo_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 38:带CP56保护事件 ---- */
|
||
/**
|
||
* 功能:编码带CP56保护事件的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少10字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:SEP(1:ES低2位,QDP高5位) + CP16(2) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int EventOfProtectionEquipmentWithCP56Time2a_Encode_Value(const IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
if (self->event > 3U || (self->quality & 0x07U)) { return 0; }
|
||
payload[0] = (uint8_t)(self->event | self->quality);
|
||
return IEC60870_Time_To_CP16(&self->elapsed_time, payload + 1, IEC60870_CP16_LEN) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 3, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP56保护事件的值字段。
|
||
* 输入参数:payload——已校验完整长度的10字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:SEP(1:ES低2位,QDP高5位) + CP16(2) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int EventOfProtectionEquipmentWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *self)
|
||
{
|
||
if (payload[0] & 0x04U) { return 0; }
|
||
self->event = payload[0] & 0x03U;
|
||
self->quality = payload[0] & 0xF8U;
|
||
return IEC60870_Time_From_CP16(payload + 1, IEC60870_CP16_LEN, &self->elapsed_time) &&
|
||
IEC60870_Time_From_CP56(payload + 3, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到EventOfProtectionEquipmentWithCP56Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int EventOfProtectionEquipmentWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return EventOfProtectionEquipmentWithCP56Time2a_Encode_Value((const IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable EventOfProtectionEquipmentWithCP56Time2a_VTable = {
|
||
38, 10, 0, sizeof(IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t), EventOfProtectionEquipmentWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 38(带CP56保护事件)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipmentWithCP56Time2a_Create(IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *self,
|
||
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t result;
|
||
uint8_t payload[10];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(event < 0 || event > 3) ||
|
||
(quality < 0 || quality > 255) ||
|
||
(elapsed_time == NULL) ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.event = (uint8_t)event;
|
||
result.quality = (uint8_t)quality;
|
||
result.elapsed_time = *elapsed_time;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &EventOfProtectionEquipmentWithCP56Time2a_VTable);
|
||
if (!EventOfProtectionEquipmentWithCP56Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 38(带CP56保护事件)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipmentWithCP56Time2a_Get_From_Buffer(IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 10U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!EventOfProtectionEquipmentWithCP56Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &EventOfProtectionEquipmentWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 39:带CP56成组保护启动事件 ---- */
|
||
/**
|
||
* 功能:编码带CP56成组保护启动事件的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少11字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Encode_Value(const IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
if (self->event > 63U || (self->quality & 0x07U)) { return 0; }
|
||
payload[0] = self->event;
|
||
payload[1] = self->quality;
|
||
return IEC60870_Time_To_CP16(&self->elapsed_time, payload + 2, IEC60870_CP16_LEN) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 4, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP56成组保护启动事件的值字段。
|
||
* 输入参数:payload——已校验完整长度的11字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *self)
|
||
{
|
||
if (payload[0] > 63U || (payload[1] & 0x07U)) { return 0; }
|
||
self->event = payload[0];
|
||
self->quality = payload[1];
|
||
return IEC60870_Time_From_CP16(payload + 2, IEC60870_CP16_LEN, &self->elapsed_time) &&
|
||
IEC60870_Time_From_CP56(payload + 4, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到PackedStartEventsOfProtectionEquipmentWithCP56Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Encode_Value((const IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable PackedStartEventsOfProtectionEquipmentWithCP56Time2a_VTable = {
|
||
39, 11, 0, sizeof(IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t), PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 39(带CP56成组保护启动事件)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Create(IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *self,
|
||
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t result;
|
||
uint8_t payload[11];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(event < 0 || event > 63) ||
|
||
(quality < 0 || quality > 255) ||
|
||
(elapsed_time == NULL) ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.event = (uint8_t)event;
|
||
result.quality = (uint8_t)quality;
|
||
result.elapsed_time = *elapsed_time;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &PackedStartEventsOfProtectionEquipmentWithCP56Time2a_VTable);
|
||
if (!PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 39(带CP56成组保护启动事件)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Get_From_Buffer(IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 11U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &PackedStartEventsOfProtectionEquipmentWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 40:带CP56保护输出电路信息 ---- */
|
||
/**
|
||
* 功能:编码带CP56保护输出电路信息的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少11字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int PackedOutputCircuitInfoWithCP56Time2a_Encode_Value(const IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
if (self->event > 15U || (self->quality & 0x07U)) { return 0; }
|
||
payload[0] = self->event;
|
||
payload[1] = self->quality;
|
||
return IEC60870_Time_To_CP16(&self->elapsed_time, payload + 2, IEC60870_CP16_LEN) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 4, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP56保护输出电路信息的值字段。
|
||
* 输入参数:payload——已校验完整长度的11字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:事件(1) + QDP(1) + CP16(2) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int PackedOutputCircuitInfoWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *self)
|
||
{
|
||
if (payload[0] > 15U || (payload[1] & 0x07U)) { return 0; }
|
||
self->event = payload[0];
|
||
self->quality = payload[1];
|
||
return IEC60870_Time_From_CP16(payload + 2, IEC60870_CP16_LEN, &self->elapsed_time) &&
|
||
IEC60870_Time_From_CP56(payload + 4, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到PackedOutputCircuitInfoWithCP56Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int PackedOutputCircuitInfoWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return PackedOutputCircuitInfoWithCP56Time2a_Encode_Value((const IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable PackedOutputCircuitInfoWithCP56Time2a_VTable = {
|
||
40, 11, 0, sizeof(IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t), PackedOutputCircuitInfoWithCP56Time2a_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 40(带CP56保护输出电路信息)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfoWithCP56Time2a_Create(IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *self,
|
||
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t result;
|
||
uint8_t payload[11];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(event < 0 || event > 15) ||
|
||
(quality < 0 || quality > 255) ||
|
||
(elapsed_time == NULL) ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.event = (uint8_t)event;
|
||
result.quality = (uint8_t)quality;
|
||
result.elapsed_time = *elapsed_time;
|
||
result.time = *time;
|
||
Initialize_Object(&result.object, ioa, &PackedOutputCircuitInfoWithCP56Time2a_VTable);
|
||
if (!PackedOutputCircuitInfoWithCP56Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 40(带CP56保护输出电路信息)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfoWithCP56Time2a_Get_From_Buffer(IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 11U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!PackedOutputCircuitInfoWithCP56Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &PackedOutputCircuitInfoWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 20:带变位检测的成组单点 ---- */
|
||
/**
|
||
* 功能:编码带变位检测的成组单点的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:SCD(4:状态16位 + 变位16位) + QDS(1);失败只影响临时区。
|
||
*/
|
||
static int PackedSinglePointWithSCD_Encode_Value(const IEC60870_PackedSinglePointWithSCD_t *self, uint8_t *payload)
|
||
{
|
||
if (self->quality & 0x0EU) { return 0; }
|
||
IEC60870_Object_Write_LE(payload + 0, self->status, 2);
|
||
IEC60870_Object_Write_LE(payload + 2, self->change, 2);
|
||
payload[4] = self->quality;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带变位检测的成组单点的值字段。
|
||
* 输入参数:payload——已校验完整长度的5字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:SCD(4:状态16位 + 变位16位) + QDS(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int PackedSinglePointWithSCD_Decode_Value(const uint8_t *payload, IEC60870_PackedSinglePointWithSCD_t *self)
|
||
{
|
||
if (payload[4] & 0x0EU) { return 0; }
|
||
self->status = (uint16_t)IEC60870_Object_Read_LE(payload + 0, 2);
|
||
self->change = (uint16_t)IEC60870_Object_Read_LE(payload + 2, 2);
|
||
self->quality = payload[4];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到PackedSinglePointWithSCD编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int PackedSinglePointWithSCD_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return PackedSinglePointWithSCD_Encode_Value((const IEC60870_PackedSinglePointWithSCD_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable PackedSinglePointWithSCD_VTable = {
|
||
20, 5, 0, sizeof(IEC60870_PackedSinglePointWithSCD_t), PackedSinglePointWithSCD_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 20(带变位检测的成组单点)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedSinglePointWithSCD_Create(IEC60870_PackedSinglePointWithSCD_t *self,
|
||
uint32_t ioa, uint16_t status, uint16_t change, int quality)
|
||
{
|
||
IEC60870_PackedSinglePointWithSCD_t result;
|
||
uint8_t payload[5];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(quality < 0 || quality > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.status = status;
|
||
result.change = change;
|
||
result.quality = (uint8_t)quality;
|
||
Initialize_Object(&result.object, ioa, &PackedSinglePointWithSCD_VTable);
|
||
if (!PackedSinglePointWithSCD_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 20(带变位检测的成组单点)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_PackedSinglePointWithSCD_Get_From_Buffer(IEC60870_PackedSinglePointWithSCD_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_PackedSinglePointWithSCD_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 5U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!PackedSinglePointWithSCD_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &PackedSinglePointWithSCD_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 21:无品质归一化测量值 ---- */
|
||
/**
|
||
* 功能:编码无品质归一化测量值的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少2字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NVA(2),不包含QDS;失败只影响临时区。
|
||
*/
|
||
static int MeasuredValueNormalizedWithoutQuality_Encode_Value(const IEC60870_MeasuredValueNormalizedWithoutQuality_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码无品质归一化测量值的值字段。
|
||
* 输入参数:payload——已校验完整长度的2字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NVA(2),不包含QDS;公开入口在成功后统一提交。
|
||
*/
|
||
static int MeasuredValueNormalizedWithoutQuality_Decode_Value(const uint8_t *payload, IEC60870_MeasuredValueNormalizedWithoutQuality_t *self)
|
||
{
|
||
self->value = Read_I16(payload);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到MeasuredValueNormalizedWithoutQuality编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int MeasuredValueNormalizedWithoutQuality_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return MeasuredValueNormalizedWithoutQuality_Encode_Value((const IEC60870_MeasuredValueNormalizedWithoutQuality_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable MeasuredValueNormalizedWithoutQuality_VTable = {
|
||
21, 2, 0, sizeof(IEC60870_MeasuredValueNormalizedWithoutQuality_t), MeasuredValueNormalizedWithoutQuality_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 21(无品质归一化测量值)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithoutQuality_Create(IEC60870_MeasuredValueNormalizedWithoutQuality_t *self,
|
||
uint32_t ioa, int16_t value)
|
||
{
|
||
IEC60870_MeasuredValueNormalizedWithoutQuality_t result;
|
||
uint8_t payload[2];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueNormalizedWithoutQuality_VTable);
|
||
if (!MeasuredValueNormalizedWithoutQuality_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 21(无品质归一化测量值)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithoutQuality_Get_From_Buffer(IEC60870_MeasuredValueNormalizedWithoutQuality_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_MeasuredValueNormalizedWithoutQuality_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 2U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!MeasuredValueNormalizedWithoutQuality_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &MeasuredValueNormalizedWithoutQuality_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 51:32位比特串命令 ---- */
|
||
/**
|
||
* 功能:编码32位比特串命令的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少4字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:BSI(4),不包含QDS;失败只影响临时区。
|
||
*/
|
||
static int Bitstring32Command_Encode_Value(const IEC60870_Bitstring32Command_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload + 0, self->value, 4);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码32位比特串命令的值字段。
|
||
* 输入参数:payload——已校验完整长度的4字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:BSI(4),不包含QDS;公开入口在成功后统一提交。
|
||
*/
|
||
static int Bitstring32Command_Decode_Value(const uint8_t *payload, IEC60870_Bitstring32Command_t *self)
|
||
{
|
||
self->value = (uint32_t)IEC60870_Object_Read_LE(payload + 0, 4);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到Bitstring32Command编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int Bitstring32Command_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return Bitstring32Command_Encode_Value((const IEC60870_Bitstring32Command_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable Bitstring32Command_VTable = {
|
||
51, 4, 1, sizeof(IEC60870_Bitstring32Command_t), Bitstring32Command_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 51(32位比特串命令)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32Command_Create(IEC60870_Bitstring32Command_t *self,
|
||
uint32_t ioa, uint32_t value)
|
||
{
|
||
IEC60870_Bitstring32Command_t result;
|
||
uint8_t payload[4];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
Initialize_Object(&result.object, ioa, &Bitstring32Command_VTable);
|
||
if (!Bitstring32Command_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 51(32位比特串命令)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32Command_Get_From_Buffer(IEC60870_Bitstring32Command_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_Bitstring32Command_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 4U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!Bitstring32Command_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &Bitstring32Command_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 64:带CP56比特串命令 ---- */
|
||
/**
|
||
* 功能:编码带CP56比特串命令的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少11字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:基础值(4) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int Bitstring32CommandWithCP56Time2a_Encode_Value(const IEC60870_Bitstring32CommandWithCP56Time2a_t *self, uint8_t *payload)
|
||
{
|
||
return Bitstring32Command_Encode_Value(&self->base, payload) &&
|
||
IEC60870_Time_To_CP56(&self->time, payload + 4, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码带CP56比特串命令的值字段。
|
||
* 输入参数:payload——已校验完整长度的11字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:基础值(4) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int Bitstring32CommandWithCP56Time2a_Decode_Value(const uint8_t *payload, IEC60870_Bitstring32CommandWithCP56Time2a_t *self)
|
||
{
|
||
return Bitstring32Command_Decode_Value(payload, &self->base) &&
|
||
IEC60870_Time_From_CP56(payload + 4, IEC60870_CP56_LEN, &self->time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到Bitstring32CommandWithCP56Time2a编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int Bitstring32CommandWithCP56Time2a_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return Bitstring32CommandWithCP56Time2a_Encode_Value((const IEC60870_Bitstring32CommandWithCP56Time2a_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable Bitstring32CommandWithCP56Time2a_VTable = {
|
||
64, 11, 1, sizeof(IEC60870_Bitstring32CommandWithCP56Time2a_t), Bitstring32CommandWithCP56Time2a_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 64(带CP56比特串命令)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32CommandWithCP56Time2a_Create(IEC60870_Bitstring32CommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, uint32_t value, const IEC60870_CP56Time2a_t *time)
|
||
{
|
||
IEC60870_Bitstring32CommandWithCP56Time2a_t result;
|
||
uint8_t payload[11];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (IEC60870_Bitstring32Command_Create(&result.base, ioa, value) != IEC60870_ASDU_OK) { return IEC60870_ASDU_ERROR; }
|
||
result.time = *time;
|
||
Initialize_Object(&result.base.object, ioa, &Bitstring32CommandWithCP56Time2a_VTable);
|
||
if (!Bitstring32CommandWithCP56Time2a_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 64(带CP56比特串命令)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_Bitstring32CommandWithCP56Time2a_Get_From_Buffer(IEC60870_Bitstring32CommandWithCP56Time2a_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_Bitstring32CommandWithCP56Time2a_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 11U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!Bitstring32CommandWithCP56Time2a_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.base.object, ioa, &Bitstring32CommandWithCP56Time2a_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 70:初始化结束 ---- */
|
||
/**
|
||
* 功能:编码初始化结束的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:COI(1),地址适用性由应用判断;失败只影响临时区。
|
||
*/
|
||
static int EndOfInitialization_Encode_Value(const IEC60870_EndOfInitialization_t *self, uint8_t *payload)
|
||
{
|
||
payload[0] = self->cause;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码初始化结束的值字段。
|
||
* 输入参数:payload——已校验完整长度的1字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:COI(1),地址适用性由应用判断;公开入口在成功后统一提交。
|
||
*/
|
||
static int EndOfInitialization_Decode_Value(const uint8_t *payload, IEC60870_EndOfInitialization_t *self)
|
||
{
|
||
self->cause = payload[0];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到EndOfInitialization编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int EndOfInitialization_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return EndOfInitialization_Encode_Value((const IEC60870_EndOfInitialization_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable EndOfInitialization_VTable = {
|
||
70, 1, 1, sizeof(IEC60870_EndOfInitialization_t), EndOfInitialization_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 70(初始化结束)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_EndOfInitialization_Create(IEC60870_EndOfInitialization_t *self,
|
||
uint32_t ioa, int cause)
|
||
{
|
||
IEC60870_EndOfInitialization_t result;
|
||
uint8_t payload[1];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(cause < 0 || cause > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.cause = (uint8_t)cause;
|
||
Initialize_Object(&result.object, ioa, &EndOfInitialization_VTable);
|
||
if (!EndOfInitialization_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 70(初始化结束)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_EndOfInitialization_Get_From_Buffer(IEC60870_EndOfInitialization_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_EndOfInitialization_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 1U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!EndOfInitialization_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &EndOfInitialization_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 104:无时标测试命令 ---- */
|
||
/**
|
||
* 功能:编码无时标测试命令的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少2字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:固定测试图样AA 55;失败只影响临时区。
|
||
*/
|
||
static int TestCommand_Encode_Value(const IEC60870_TestCommand_t *self, uint8_t *payload)
|
||
{
|
||
(void)self;
|
||
payload[0] = 0xAAU;
|
||
payload[1] = 0x55U;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码无时标测试命令的值字段。
|
||
* 输入参数:payload——已校验完整长度的2字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:固定测试图样AA 55;公开入口在成功后统一提交。
|
||
*/
|
||
static int TestCommand_Decode_Value(const uint8_t *payload, IEC60870_TestCommand_t *self)
|
||
{
|
||
(void)self;
|
||
return payload[0] == 0xAAU && payload[1] == 0x55U;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到TestCommand编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int TestCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return TestCommand_Encode_Value((const IEC60870_TestCommand_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable TestCommand_VTable = {
|
||
104, 2, 1, sizeof(IEC60870_TestCommand_t), TestCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 104(无时标测试命令)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_TestCommand_Create(IEC60870_TestCommand_t *self,
|
||
uint32_t ioa)
|
||
{
|
||
IEC60870_TestCommand_t result;
|
||
uint8_t payload[2];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
Initialize_Object(&result.object, ioa, &TestCommand_VTable);
|
||
if (!TestCommand_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 104(无时标测试命令)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_TestCommand_Get_From_Buffer(IEC60870_TestCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_TestCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 2U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!TestCommand_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &TestCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 106:延时获得命令 ---- */
|
||
/**
|
||
* 功能:编码延时获得命令的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少2字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:CP16(2);失败只影响临时区。
|
||
*/
|
||
static int DelayAcquisitionCommand_Encode_Value(const IEC60870_DelayAcquisitionCommand_t *self, uint8_t *payload)
|
||
{
|
||
return IEC60870_Time_To_CP16(&self->delay, payload, IEC60870_CP16_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码延时获得命令的值字段。
|
||
* 输入参数:payload——已校验完整长度的2字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:CP16(2);公开入口在成功后统一提交。
|
||
*/
|
||
static int DelayAcquisitionCommand_Decode_Value(const uint8_t *payload, IEC60870_DelayAcquisitionCommand_t *self)
|
||
{
|
||
return IEC60870_Time_From_CP16(payload, IEC60870_CP16_LEN, &self->delay);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到DelayAcquisitionCommand编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int DelayAcquisitionCommand_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return DelayAcquisitionCommand_Encode_Value((const IEC60870_DelayAcquisitionCommand_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable DelayAcquisitionCommand_VTable = {
|
||
106, 2, 1, sizeof(IEC60870_DelayAcquisitionCommand_t), DelayAcquisitionCommand_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 106(延时获得命令)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DelayAcquisitionCommand_Create(IEC60870_DelayAcquisitionCommand_t *self,
|
||
uint32_t ioa, const IEC60870_CP16Time2a_t *delay)
|
||
{
|
||
IEC60870_DelayAcquisitionCommand_t result;
|
||
uint8_t payload[2];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(delay == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.delay = *delay;
|
||
Initialize_Object(&result.object, ioa, &DelayAcquisitionCommand_VTable);
|
||
if (!DelayAcquisitionCommand_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 106(延时获得命令)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_DelayAcquisitionCommand_Get_From_Buffer(IEC60870_DelayAcquisitionCommand_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_DelayAcquisitionCommand_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 2U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!DelayAcquisitionCommand_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &DelayAcquisitionCommand_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 110:归一化测量值参数 ---- */
|
||
/**
|
||
* 功能:编码归一化测量值参数的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少3字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:参数值(2) + QPM(1),QPM不是QDS;失败只影响临时区。
|
||
*/
|
||
static int ParameterNormalizedValue_Encode_Value(const IEC60870_ParameterNormalizedValue_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
payload[2] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码归一化测量值参数的值字段。
|
||
* 输入参数:payload——已校验完整长度的3字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:参数值(2) + QPM(1),QPM不是QDS;公开入口在成功后统一提交。
|
||
*/
|
||
static int ParameterNormalizedValue_Decode_Value(const uint8_t *payload, IEC60870_ParameterNormalizedValue_t *self)
|
||
{
|
||
self->value = Read_I16(payload);
|
||
self->qualifier = payload[2];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到ParameterNormalizedValue编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int ParameterNormalizedValue_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ParameterNormalizedValue_Encode_Value((const IEC60870_ParameterNormalizedValue_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable ParameterNormalizedValue_VTable = {
|
||
110, 3, 0, sizeof(IEC60870_ParameterNormalizedValue_t), ParameterNormalizedValue_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 110(归一化测量值参数)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterNormalizedValue_Create(IEC60870_ParameterNormalizedValue_t *self,
|
||
uint32_t ioa, int16_t value, int qualifier)
|
||
{
|
||
IEC60870_ParameterNormalizedValue_t result;
|
||
uint8_t payload[3];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &ParameterNormalizedValue_VTable);
|
||
if (!ParameterNormalizedValue_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 110(归一化测量值参数)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterNormalizedValue_Get_From_Buffer(IEC60870_ParameterNormalizedValue_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ParameterNormalizedValue_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 3U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ParameterNormalizedValue_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &ParameterNormalizedValue_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 111:标度化测量值参数 ---- */
|
||
/**
|
||
* 功能:编码标度化测量值参数的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少3字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:参数值(2) + QPM(1),QPM不是QDS;失败只影响临时区。
|
||
*/
|
||
static int ParameterScaledValue_Encode_Value(const IEC60870_ParameterScaledValue_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, (uint16_t)self->value, 2);
|
||
payload[2] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码标度化测量值参数的值字段。
|
||
* 输入参数:payload——已校验完整长度的3字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:参数值(2) + QPM(1),QPM不是QDS;公开入口在成功后统一提交。
|
||
*/
|
||
static int ParameterScaledValue_Decode_Value(const uint8_t *payload, IEC60870_ParameterScaledValue_t *self)
|
||
{
|
||
self->value = Read_I16(payload);
|
||
self->qualifier = payload[2];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到ParameterScaledValue编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int ParameterScaledValue_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ParameterScaledValue_Encode_Value((const IEC60870_ParameterScaledValue_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable ParameterScaledValue_VTable = {
|
||
111, 3, 0, sizeof(IEC60870_ParameterScaledValue_t), ParameterScaledValue_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 111(标度化测量值参数)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterScaledValue_Create(IEC60870_ParameterScaledValue_t *self,
|
||
uint32_t ioa, int16_t value, int qualifier)
|
||
{
|
||
IEC60870_ParameterScaledValue_t result;
|
||
uint8_t payload[3];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &ParameterScaledValue_VTable);
|
||
if (!ParameterScaledValue_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 111(标度化测量值参数)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterScaledValue_Get_From_Buffer(IEC60870_ParameterScaledValue_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ParameterScaledValue_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 3U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ParameterScaledValue_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &ParameterScaledValue_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 112:短浮点测量值参数 ---- */
|
||
/**
|
||
* 功能:编码短浮点测量值参数的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:参数值(4) + QPM(1),QPM不是QDS;失败只影响临时区。
|
||
*/
|
||
static int ParameterFloatValue_Encode_Value(const IEC60870_ParameterFloatValue_t *self, uint8_t *payload)
|
||
{
|
||
Write_Float(payload, &self->value);
|
||
payload[4] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码短浮点测量值参数的值字段。
|
||
* 输入参数:payload——已校验完整长度的5字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:参数值(4) + QPM(1),QPM不是QDS;公开入口在成功后统一提交。
|
||
*/
|
||
static int ParameterFloatValue_Decode_Value(const uint8_t *payload, IEC60870_ParameterFloatValue_t *self)
|
||
{
|
||
Read_Float(payload, &self->value);
|
||
self->qualifier = payload[4];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到ParameterFloatValue编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int ParameterFloatValue_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ParameterFloatValue_Encode_Value((const IEC60870_ParameterFloatValue_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable ParameterFloatValue_VTable = {
|
||
112, 5, 0, sizeof(IEC60870_ParameterFloatValue_t), ParameterFloatValue_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 112(短浮点测量值参数)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterFloatValue_Create(IEC60870_ParameterFloatValue_t *self,
|
||
uint32_t ioa, float value, int qualifier)
|
||
{
|
||
IEC60870_ParameterFloatValue_t result;
|
||
uint8_t payload[5];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.value = value;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &ParameterFloatValue_VTable);
|
||
if (!ParameterFloatValue_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 112(短浮点测量值参数)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterFloatValue_Get_From_Buffer(IEC60870_ParameterFloatValue_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ParameterFloatValue_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 5U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ParameterFloatValue_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &ParameterFloatValue_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 113:参数激活 ---- */
|
||
/**
|
||
* 功能:编码参数激活的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少1字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:QPA(1);失败只影响临时区。
|
||
*/
|
||
static int ParameterActivation_Encode_Value(const IEC60870_ParameterActivation_t *self, uint8_t *payload)
|
||
{
|
||
payload[0] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码参数激活的值字段。
|
||
* 输入参数:payload——已校验完整长度的1字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:QPA(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int ParameterActivation_Decode_Value(const uint8_t *payload, IEC60870_ParameterActivation_t *self)
|
||
{
|
||
self->qualifier = payload[0];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到ParameterActivation编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int ParameterActivation_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return ParameterActivation_Encode_Value((const IEC60870_ParameterActivation_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable ParameterActivation_VTable = {
|
||
113, 1, 0, sizeof(IEC60870_ParameterActivation_t), ParameterActivation_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 113(参数激活)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterActivation_Create(IEC60870_ParameterActivation_t *self,
|
||
uint32_t ioa, int qualifier)
|
||
{
|
||
IEC60870_ParameterActivation_t result;
|
||
uint8_t payload[1];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &ParameterActivation_VTable);
|
||
if (!ParameterActivation_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 113(参数激活)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_ParameterActivation_Get_From_Buffer(IEC60870_ParameterActivation_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_ParameterActivation_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 1U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!ParameterActivation_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &ParameterActivation_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 120:文件准备就绪 ---- */
|
||
/**
|
||
* 功能:编码文件准备就绪的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少6字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + LOF(3) + FRQ(1);失败只影响临时区。
|
||
*/
|
||
static int FileReady_Encode_Value(const IEC60870_FileReady_t *self, uint8_t *payload)
|
||
{
|
||
if (self->file_length > UINT32_C(0xFFFFFF) || (self->qualifier & 0x7FU)) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
IEC60870_Object_Write_LE(payload + 2, self->file_length, 3);
|
||
payload[5] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码文件准备就绪的值字段。
|
||
* 输入参数:payload——已校验完整长度的6字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + LOF(3) + FRQ(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int FileReady_Decode_Value(const uint8_t *payload, IEC60870_FileReady_t *self)
|
||
{
|
||
if (payload[5] & 0x7FU) { return 0; }
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->file_length = IEC60870_Object_Read_LE(payload + 2, 3);
|
||
self->qualifier = payload[5];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到FileReady编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int FileReady_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return FileReady_Encode_Value((const IEC60870_FileReady_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable FileReady_VTable = {
|
||
120, 6, 1, sizeof(IEC60870_FileReady_t), FileReady_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 120(文件准备就绪)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileReady_Create(IEC60870_FileReady_t *self,
|
||
uint32_t ioa, uint16_t file_name, uint32_t file_length, int qualifier)
|
||
{
|
||
IEC60870_FileReady_t result;
|
||
uint8_t payload[6];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(file_length > UINT32_C(0xFFFFFF)) ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.file_length = file_length;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &FileReady_VTable);
|
||
if (!FileReady_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 120(文件准备就绪)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileReady_Get_From_Buffer(IEC60870_FileReady_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_FileReady_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 6U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!FileReady_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &FileReady_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 121:节准备就绪 ---- */
|
||
/**
|
||
* 功能:编码节准备就绪的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少7字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + LOS(3) + SRQ(1);失败只影响临时区。
|
||
*/
|
||
static int SectionReady_Encode_Value(const IEC60870_SectionReady_t *self, uint8_t *payload)
|
||
{
|
||
if (self->section_length > UINT32_C(0xFFFFFF) || (self->qualifier & 0x7FU)) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
payload[2] = self->section;
|
||
IEC60870_Object_Write_LE(payload + 3, self->section_length, 3);
|
||
payload[6] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码节准备就绪的值字段。
|
||
* 输入参数:payload——已校验完整长度的7字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + LOS(3) + SRQ(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int SectionReady_Decode_Value(const uint8_t *payload, IEC60870_SectionReady_t *self)
|
||
{
|
||
if (payload[6] & 0x7FU) { return 0; }
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->section = payload[2];
|
||
self->section_length = IEC60870_Object_Read_LE(payload + 3, 3);
|
||
self->qualifier = payload[6];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到SectionReady编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int SectionReady_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return SectionReady_Encode_Value((const IEC60870_SectionReady_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable SectionReady_VTable = {
|
||
121, 7, 1, sizeof(IEC60870_SectionReady_t), SectionReady_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 121(节准备就绪)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SectionReady_Create(IEC60870_SectionReady_t *self,
|
||
uint32_t ioa, uint16_t file_name, int section, uint32_t section_length, int qualifier)
|
||
{
|
||
IEC60870_SectionReady_t result;
|
||
uint8_t payload[7];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(section < 0 || section > 255) ||
|
||
(section_length > UINT32_C(0xFFFFFF)) ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.section = (uint8_t)section;
|
||
result.section_length = section_length;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &SectionReady_VTable);
|
||
if (!SectionReady_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 121(节准备就绪)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_SectionReady_Get_From_Buffer(IEC60870_SectionReady_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_SectionReady_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 7U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!SectionReady_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &SectionReady_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 122:文件/节召唤或选择 ---- */
|
||
/**
|
||
* 功能:编码文件/节召唤或选择的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少4字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + SCQ(1);失败只影响临时区。
|
||
*/
|
||
static int FileCallOrSelect_Encode_Value(const IEC60870_FileCallOrSelect_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
payload[2] = self->section;
|
||
payload[3] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码文件/节召唤或选择的值字段。
|
||
* 输入参数:payload——已校验完整长度的4字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + SCQ(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int FileCallOrSelect_Decode_Value(const uint8_t *payload, IEC60870_FileCallOrSelect_t *self)
|
||
{
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->section = payload[2];
|
||
self->qualifier = payload[3];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到FileCallOrSelect编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int FileCallOrSelect_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return FileCallOrSelect_Encode_Value((const IEC60870_FileCallOrSelect_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable FileCallOrSelect_VTable = {
|
||
122, 4, 1, sizeof(IEC60870_FileCallOrSelect_t), FileCallOrSelect_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 122(文件/节召唤或选择)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileCallOrSelect_Create(IEC60870_FileCallOrSelect_t *self,
|
||
uint32_t ioa, uint16_t file_name, int section, int qualifier)
|
||
{
|
||
IEC60870_FileCallOrSelect_t result;
|
||
uint8_t payload[4];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(section < 0 || section > 255) ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.section = (uint8_t)section;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &FileCallOrSelect_VTable);
|
||
if (!FileCallOrSelect_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 122(文件/节召唤或选择)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileCallOrSelect_Get_From_Buffer(IEC60870_FileCallOrSelect_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_FileCallOrSelect_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 4U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!FileCallOrSelect_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &FileCallOrSelect_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 124:文件/节确认 ---- */
|
||
/**
|
||
* 功能:编码文件/节确认的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少4字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + AFQ(1);失败只影响临时区。
|
||
*/
|
||
static int FileACK_Encode_Value(const IEC60870_FileACK_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
payload[2] = self->section;
|
||
payload[3] = self->qualifier;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码文件/节确认的值字段。
|
||
* 输入参数:payload——已校验完整长度的4字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + AFQ(1);公开入口在成功后统一提交。
|
||
*/
|
||
static int FileACK_Decode_Value(const uint8_t *payload, IEC60870_FileACK_t *self)
|
||
{
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->section = payload[2];
|
||
self->qualifier = payload[3];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到FileACK编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int FileACK_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return FileACK_Encode_Value((const IEC60870_FileACK_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable FileACK_VTable = {
|
||
124, 4, 1, sizeof(IEC60870_FileACK_t), FileACK_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 124(文件/节确认)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileACK_Create(IEC60870_FileACK_t *self,
|
||
uint32_t ioa, uint16_t file_name, int section, int qualifier)
|
||
{
|
||
IEC60870_FileACK_t result;
|
||
uint8_t payload[4];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(section < 0 || section > 255) ||
|
||
(qualifier < 0 || qualifier > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.section = (uint8_t)section;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
Initialize_Object(&result.object, ioa, &FileACK_VTable);
|
||
if (!FileACK_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 124(文件/节确认)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileACK_Get_From_Buffer(IEC60870_FileACK_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_FileACK_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 4U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!FileACK_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &FileACK_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 123:最后文件段或节 ---- */
|
||
/**
|
||
* 功能:编码最后文件段或节的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少5字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + LSQ(1) + CHS(1),这里只传递校验和;失败只影响临时区。
|
||
*/
|
||
static int FileLastSegmentOrSection_Encode_Value(const IEC60870_FileLastSegmentOrSection_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
payload[2] = self->section;
|
||
payload[3] = self->qualifier;
|
||
payload[4] = self->checksum;
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码最后文件段或节的值字段。
|
||
* 输入参数:payload——已校验完整长度的5字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + LSQ(1) + CHS(1),这里只传递校验和;公开入口在成功后统一提交。
|
||
*/
|
||
static int FileLastSegmentOrSection_Decode_Value(const uint8_t *payload, IEC60870_FileLastSegmentOrSection_t *self)
|
||
{
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->section = payload[2];
|
||
self->qualifier = payload[3];
|
||
self->checksum = payload[4];
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到FileLastSegmentOrSection编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int FileLastSegmentOrSection_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return FileLastSegmentOrSection_Encode_Value((const IEC60870_FileLastSegmentOrSection_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable FileLastSegmentOrSection_VTable = {
|
||
123, 5, 1, sizeof(IEC60870_FileLastSegmentOrSection_t), FileLastSegmentOrSection_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 123(最后文件段或节)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileLastSegmentOrSection_Create(IEC60870_FileLastSegmentOrSection_t *self,
|
||
uint32_t ioa, uint16_t file_name, int section, int qualifier, int checksum)
|
||
{
|
||
IEC60870_FileLastSegmentOrSection_t result;
|
||
uint8_t payload[5];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(section < 0 || section > 255) ||
|
||
(qualifier < 0 || qualifier > 255) ||
|
||
(checksum < 0 || checksum > 255)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.section = (uint8_t)section;
|
||
result.qualifier = (uint8_t)qualifier;
|
||
result.checksum = (uint8_t)checksum;
|
||
Initialize_Object(&result.object, ioa, &FileLastSegmentOrSection_VTable);
|
||
if (!FileLastSegmentOrSection_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 123(最后文件段或节)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileLastSegmentOrSection_Get_From_Buffer(IEC60870_FileLastSegmentOrSection_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_FileLastSegmentOrSection_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 5U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!FileLastSegmentOrSection_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &FileLastSegmentOrSection_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 125:文件段 ---- */
|
||
/**
|
||
* 功能:编码文件段的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少4+LOS字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + LOS(1) + 段数据(LOS),SQ=0且仅一个对象;失败只影响临时区。
|
||
*/
|
||
static int FileSegment_Encode_Value(const IEC60870_FileSegment_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
payload[2] = self->section;
|
||
payload[3] = self->length;
|
||
memcpy(payload + 4, self->data, self->length);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:解码文件段的值字段。
|
||
* 输入参数:payload——已校验完整长度的变长载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + NOS(1) + LOS(1) + 段数据(LOS),SQ=0且仅一个对象;公开入口在成功后统一提交。
|
||
*/
|
||
static int FileSegment_Decode_Value(const uint8_t *payload, IEC60870_FileSegment_t *self)
|
||
{
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->section = payload[2];
|
||
self->length = payload[3];
|
||
memcpy(self->data, payload + 4, self->length);
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到FileSegment编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int FileSegment_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return FileSegment_Encode_Value((const IEC60870_FileSegment_t *)object, payload);
|
||
}
|
||
|
||
/**
|
||
* 功能:取得文件段的实际值载荷长度。
|
||
* 输入参数:object——已核对身份的文件段基类。
|
||
* 输出参数:无。
|
||
* 返回值:4+LOS,最大259字节。
|
||
* 说明:只计算线上长度;不包含IOA或ASDU公共头。
|
||
*/
|
||
static uint16_t FileSegment_Payload_Size(const IEC60870_InformationObject_t *object)
|
||
{
|
||
const IEC60870_FileSegment_t *self = (const IEC60870_FileSegment_t *)object;
|
||
return (uint16_t)(4U + self->length);
|
||
}
|
||
|
||
/**
|
||
* 功能:从文件段原文安全取得载荷长度。
|
||
* 输入参数:payload——值载荷;length——实际可读字节数。
|
||
* 输出参数:无。
|
||
* 返回值:完整段返回4+LOS,截短或空指针返回0。
|
||
* 说明:读取LOS前要求至少4字节;精确尾长由ASDU层检查。
|
||
*/
|
||
static uint16_t FileSegment_Payload_Size_From_Buffer(const uint8_t *payload, uint16_t length)
|
||
{
|
||
uint16_t required;
|
||
if (payload == NULL || length < 4U) { return 0; }
|
||
required = (uint16_t)(4U + payload[3]);
|
||
return required <= length ? required : 0U;
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable FileSegment_VTable = {
|
||
125, 4, 1, sizeof(IEC60870_FileSegment_t), FileSegment_Encode,
|
||
0, FileSegment_Payload_Size, FileSegment_Payload_Size_From_Buffer
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 125(文件段)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileSegment_Create(IEC60870_FileSegment_t *self,
|
||
uint32_t ioa, uint16_t file_name, int section, const uint8_t *data, uint16_t data_length)
|
||
{
|
||
IEC60870_FileSegment_t result;
|
||
uint8_t payload[IEC60870_OBJECT_MAX_PAYLOAD];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(section < 0 || section > 255) ||
|
||
(data_length > 255U) ||
|
||
((data_length != 0U && data == NULL))) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.section = (uint8_t)section;
|
||
result.length = (uint8_t)data_length;
|
||
if (data_length != 0U) { memcpy(result.data, data, data_length); }
|
||
Initialize_Object(&result.object, ioa, &FileSegment_VTable);
|
||
if (!FileSegment_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 125(文件段)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:先验证LOS与载荷长度,再复制数据;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileSegment_Get_From_Buffer(IEC60870_FileSegment_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_FileSegment_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length < 4U || length != (uint16_t)(4U + payload[3])) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!FileSegment_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &FileSegment_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 126:文件目录 ---- */
|
||
/**
|
||
* 功能:编码文件目录的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少13字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + LOF(3) + SOF(1) + CP56(7);失败只影响临时区。
|
||
*/
|
||
static int FileDirectory_Encode_Value(const IEC60870_FileDirectory_t *self, uint8_t *payload)
|
||
{
|
||
if (self->file_length > UINT32_C(0xFFFFFF)) { return 0; }
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
IEC60870_Object_Write_LE(payload + 2, self->file_length, 3);
|
||
payload[5] = self->status;
|
||
return IEC60870_Time_To_CP56(&self->creation_time, payload + 6, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码文件目录的值字段。
|
||
* 输入参数:payload——已校验完整长度的13字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + LOF(3) + SOF(1) + CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int FileDirectory_Decode_Value(const uint8_t *payload, IEC60870_FileDirectory_t *self)
|
||
{
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
self->file_length = IEC60870_Object_Read_LE(payload + 2, 3);
|
||
self->status = payload[5];
|
||
return IEC60870_Time_From_CP56(payload + 6, IEC60870_CP56_LEN, &self->creation_time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到FileDirectory编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int FileDirectory_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return FileDirectory_Encode_Value((const IEC60870_FileDirectory_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable FileDirectory_VTable = {
|
||
126, 13, 0, sizeof(IEC60870_FileDirectory_t), FileDirectory_Encode,
|
||
1, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 126(文件目录)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileDirectory_Create(IEC60870_FileDirectory_t *self,
|
||
uint32_t ioa, uint16_t file_name, uint32_t file_length, int status, const IEC60870_CP56Time2a_t *creation_time)
|
||
{
|
||
IEC60870_FileDirectory_t result;
|
||
uint8_t payload[13];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(file_length > UINT32_C(0xFFFFFF)) ||
|
||
(status < 0 || status > 255) ||
|
||
(creation_time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.file_length = file_length;
|
||
result.status = (uint8_t)status;
|
||
result.creation_time = *creation_time;
|
||
Initialize_Object(&result.object, ioa, &FileDirectory_VTable);
|
||
if (!FileDirectory_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 126(文件目录)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_FileDirectory_Get_From_Buffer(IEC60870_FileDirectory_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_FileDirectory_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 13U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!FileDirectory_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &FileDirectory_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/* ---- Type 127:归档查询 ---- */
|
||
/**
|
||
* 功能:编码归档查询的值字段。
|
||
* 输入参数:self——具体对象,已核对存储类型。
|
||
* 输出参数:payload——至少16字节的临时区。
|
||
* 返回值:1合法;0字段或时间非法。
|
||
* 说明:NOF(2) + 查询起始CP56(7) + 查询结束CP56(7);失败只影响临时区。
|
||
*/
|
||
static int QueryLog_Encode_Value(const IEC60870_QueryLog_t *self, uint8_t *payload)
|
||
{
|
||
IEC60870_Object_Write_LE(payload, self->file_name, 2);
|
||
return IEC60870_Time_To_CP56(&self->start_time, payload + 2, IEC60870_CP56_LEN) &&
|
||
IEC60870_Time_To_CP56(&self->stop_time, payload + 9, IEC60870_CP56_LEN);
|
||
}
|
||
|
||
/**
|
||
* 功能:解码归档查询的值字段。
|
||
* 输入参数:payload——已校验完整长度的16字节载荷。
|
||
* 输出参数:self——已清零的局部对象,不填写基类身份。
|
||
* 返回值:1合法;0保留位或时间非法。
|
||
* 说明:NOF(2) + 查询起始CP56(7) + 查询结束CP56(7);公开入口在成功后统一提交。
|
||
*/
|
||
static int QueryLog_Decode_Value(const uint8_t *payload, IEC60870_QueryLog_t *self)
|
||
{
|
||
self->file_name = (uint16_t)IEC60870_Object_Read_LE(payload, 2);
|
||
return IEC60870_Time_From_CP56(payload + 2, IEC60870_CP56_LEN, &self->start_time) &&
|
||
IEC60870_Time_From_CP56(payload + 9, IEC60870_CP56_LEN, &self->stop_time);
|
||
}
|
||
|
||
/**
|
||
* 功能:将公共基类分派到QueryLog编码。
|
||
* 输入参数:object——已核对类型和函数表的具体对象首成员。
|
||
* 输出参数:payload——足够大的临时载荷区。
|
||
* 返回值:1成功;0字段非法。
|
||
* 说明:类型转换依赖首成员布局,禁止伪造公共基类。
|
||
*/
|
||
static int QueryLog_Encode(const IEC60870_InformationObject_t *object, uint8_t *payload)
|
||
{
|
||
return QueryLog_Encode_Value((const IEC60870_QueryLog_t *)object, payload);
|
||
}
|
||
|
||
static const IEC60870_InformationObjectVTable QueryLog_VTable = {
|
||
127, 16, 1, sizeof(IEC60870_QueryLog_t), QueryLog_Encode,
|
||
0, NULL, NULL
|
||
};
|
||
|
||
/**
|
||
* 功能:在调用方存储中构造Type 127(归档查询)。
|
||
* 输入参数:ioa——24位地址;其余值的范围见公开结构及声明注释。
|
||
* 输出参数:self——成功后整体保存对象,失败不变。
|
||
* 返回值:OK成功;ERROR参数、字段或时间非法。
|
||
* 说明:局部对象验证通过后提交,不分配内存;ASDU容量另行检查。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_QueryLog_Create(IEC60870_QueryLog_t *self,
|
||
uint32_t ioa, uint16_t file_name, const IEC60870_CP56Time2a_t *start_time, const IEC60870_CP56Time2a_t *stop_time)
|
||
{
|
||
IEC60870_QueryLog_t result;
|
||
uint8_t payload[16];
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA ||
|
||
(start_time == NULL) ||
|
||
(stop_time == NULL)) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
result.file_name = file_name;
|
||
result.start_time = *start_time;
|
||
result.stop_time = *stop_time;
|
||
Initialize_Object(&result.object, ioa, &QueryLog_VTable);
|
||
if (!QueryLog_Encode_Value(&result, payload)) { return IEC60870_ASDU_ERROR; }
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:解析Type 127(归档查询)。
|
||
* 输入参数:ioa——已还原地址;payload——值载荷;length——精确字节数。
|
||
* 输出参数:self——成功时整体写入,失败不变。
|
||
* 返回值:OK成功;ERROR参数、长度、保留位或时间非法。
|
||
* 说明:逐字段恢复数值并初始化基类;结果不借用输入。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_QueryLog_Get_From_Buffer(IEC60870_QueryLog_t *self,
|
||
uint32_t ioa, const uint8_t *payload, uint16_t length)
|
||
{
|
||
IEC60870_QueryLog_t result;
|
||
if (self == NULL || ioa > IEC60870_ASDU_MAX_IOA || payload == NULL ||
|
||
length != 16U) { return IEC60870_ASDU_ERROR; }
|
||
memset(&result, 0, sizeof(result));
|
||
if (!QueryLog_Decode_Value(payload, &result)) { return IEC60870_ASDU_ERROR; }
|
||
Initialize_Object(&result.object, ioa, &QueryLog_VTable);
|
||
*self = result;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:取得当前配置下一条ASDU能容纳的最大文件段数据长度。
|
||
* 输入参数:parameters——合法应用层参数,包含最大ASDU长度和字段宽度。
|
||
* 输出参数:无。
|
||
* 返回值:0..255为数据容量;-1表示参数非法或连空文件段也容纳不下。
|
||
* 说明:扣除公共头、IOA和4字节段头;104默认配置返回236。
|
||
*/
|
||
int IEC60870_FileSegment_Get_Max_Data_Size(const IEC60870_AppLayerParameters_t *parameters)
|
||
{
|
||
int size;
|
||
if (!IEC60870_AppLayerParameters_Valid(parameters)) { return -1; }
|
||
size = parameters->maxSizeOfASDU - (2 + parameters->sizeOfCOT + parameters->sizeOfCA) - parameters->sizeOfIOA - 4;
|
||
if (size < 0) { return -1; }
|
||
return size > 255 ? 255 : size;
|
||
}
|
||
|
||
|
||
/**
|
||
* 功能:根据Type ID取得内部只读类型描述。
|
||
* 输入参数:type_id——报文或已初始化对象中的类型标识。
|
||
* 输出参数:无。
|
||
* 返回值:支持时返回静态描述表指针,未知类型返回NULL。
|
||
* 说明:表中保存载荷长度、对象存储尺寸、单对象限制和编码函数;不解析值字段。
|
||
*/
|
||
const IEC60870_InformationObjectVTable *IEC60870_InformationObject_Get_Descriptor(uint8_t type_id)
|
||
{
|
||
switch (type_id) {
|
||
case 1: return &SinglePointInformation_VTable;
|
||
case 3: return &DoublePointInformation_VTable;
|
||
case 9: return &MeasuredValueNormalized_VTable;
|
||
case 11: return &MeasuredValueScaled_VTable;
|
||
case 13: return &MeasuredValueShort_VTable;
|
||
case 15: return &IntegratedTotals_VTable;
|
||
case 30: return &SinglePointWithCP56Time2a_VTable;
|
||
case 31: return &DoublePointWithCP56Time2a_VTable;
|
||
case 34: return &MeasuredValueNormalizedWithCP56Time2a_VTable;
|
||
case 35: return &MeasuredValueScaledWithCP56Time2a_VTable;
|
||
case 36: return &MeasuredValueShortWithCP56Time2a_VTable;
|
||
case 37: return &IntegratedTotalsWithCP56Time2a_VTable;
|
||
case 45: return &SingleCommand_VTable;
|
||
case 46: return &DoubleCommand_VTable;
|
||
case 47: return &StepCommand_VTable;
|
||
case 48: return &SetpointCommandNormalized_VTable;
|
||
case 49: return &SetpointCommandScaled_VTable;
|
||
case 50: return &SetpointCommandShort_VTable;
|
||
case 58: return &SingleCommandWithCP56Time2a_VTable;
|
||
case 59: return &DoubleCommandWithCP56Time2a_VTable;
|
||
case 60: return &StepCommandWithCP56Time2a_VTable;
|
||
case 61: return &SetpointCommandNormalizedWithCP56Time2a_VTable;
|
||
case 62: return &SetpointCommandScaledWithCP56Time2a_VTable;
|
||
case 63: return &SetpointCommandShortWithCP56Time2a_VTable;
|
||
case 100: return &InterrogationCommand_VTable;
|
||
case 101: return &CounterInterrogationCommand_VTable;
|
||
case 102: return &ReadCommand_VTable;
|
||
case 103: return &ClockSynchronizationCommand_VTable;
|
||
case 105: return &ResetProcessCommand_VTable;
|
||
case 107: return &TestCommandWithCP56Time2a_VTable;
|
||
case 5: return &StepPositionInformation_VTable;
|
||
case 7: return &BitString32_VTable;
|
||
case 2: return &SinglePointWithCP24Time2a_VTable;
|
||
case 4: return &DoublePointWithCP24Time2a_VTable;
|
||
case 6: return &StepPositionWithCP24Time2a_VTable;
|
||
case 8: return &Bitstring32WithCP24Time2a_VTable;
|
||
case 10: return &MeasuredValueNormalizedWithCP24Time2a_VTable;
|
||
case 12: return &MeasuredValueScaledWithCP24Time2a_VTable;
|
||
case 14: return &MeasuredValueShortWithCP24Time2a_VTable;
|
||
case 16: return &IntegratedTotalsWithCP24Time2a_VTable;
|
||
case 32: return &StepPositionWithCP56Time2a_VTable;
|
||
case 33: return &Bitstring32WithCP56Time2a_VTable;
|
||
case 17: return &EventOfProtectionEquipment_VTable;
|
||
case 18: return &PackedStartEventsOfProtectionEquipment_VTable;
|
||
case 19: return &PackedOutputCircuitInfo_VTable;
|
||
case 38: return &EventOfProtectionEquipmentWithCP56Time2a_VTable;
|
||
case 39: return &PackedStartEventsOfProtectionEquipmentWithCP56Time2a_VTable;
|
||
case 40: return &PackedOutputCircuitInfoWithCP56Time2a_VTable;
|
||
case 20: return &PackedSinglePointWithSCD_VTable;
|
||
case 21: return &MeasuredValueNormalizedWithoutQuality_VTable;
|
||
case 51: return &Bitstring32Command_VTable;
|
||
case 64: return &Bitstring32CommandWithCP56Time2a_VTable;
|
||
case 70: return &EndOfInitialization_VTable;
|
||
case 104: return &TestCommand_VTable;
|
||
case 106: return &DelayAcquisitionCommand_VTable;
|
||
case 110: return &ParameterNormalizedValue_VTable;
|
||
case 111: return &ParameterScaledValue_VTable;
|
||
case 112: return &ParameterFloatValue_VTable;
|
||
case 113: return &ParameterActivation_VTable;
|
||
case 120: return &FileReady_VTable;
|
||
case 121: return &SectionReady_VTable;
|
||
case 122: return &FileCallOrSelect_VTable;
|
||
case 124: return &FileACK_VTable;
|
||
case 123: return &FileLastSegmentOrSection_VTable;
|
||
case 125: return &FileSegment_VTable;
|
||
case 126: return &FileDirectory_VTable;
|
||
case 127: return &QueryLog_VTable;
|
||
default: return NULL;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 功能:读取已初始化对象的类型,并核对其编码函数表身份。
|
||
* 输入参数:object——已由具体Create或Get_From_Buffer初始化的基类指针,可为NULL。
|
||
* 输出参数:无。
|
||
* 返回值:身份匹配时返回Type ID;NULL、未知类型或函数表不匹配时返回0。
|
||
* 说明:不检查IOA、数值、品质或时标;这些字段在实际编码时验证。
|
||
*/
|
||
uint8_t IEC60870_InformationObject_Get_Type(const IEC60870_InformationObject_t *object)
|
||
{
|
||
const IEC60870_InformationObjectVTable *type;
|
||
if (object == NULL) { return 0; }
|
||
type = IEC60870_InformationObject_Get_Descriptor(object->type_id);
|
||
return type != NULL && object->virtual_function_table == type ? type->type_id : 0;
|
||
}
|
||
|
||
/**
|
||
* 功能:通过具体对象的函数表编码一个对象,可按SQ需要省略IOA。
|
||
* 输入参数:object——已初始化的非空具体对象基类,不能手工伪造类型或函数表。
|
||
* parameters——非空且合法的应用层参数,本函数使用其IOA宽度。
|
||
* is_sequence——0写入IOA;1仅写值载荷,适用于监视对象和文件目录。
|
||
* capacity——buffer实际可写容量,单位字节。
|
||
* 输出参数:buffer——调用方提供的对象字节缓冲区,不含ASDU头;不得与对象重叠。
|
||
* length——非空输出指针,成功时填写实际写入的IOA加载荷字节数。
|
||
* 返回值:OK为成功,FULL为空间不足,UNSUPPORTED为未知类型,ERROR为参数或字段非法。
|
||
* 说明:先核对身份并在临时区完成值编码,再检查容量并提交,失败保留buffer和length。
|
||
* SQ首对象仍须传0;地址连续性、对象数量和整条ASDU的上限由容器层维护。
|
||
*/
|
||
IEC60870_AsduResult_t IEC60870_InformationObject_Encode(
|
||
const IEC60870_InformationObject_t *object, const IEC60870_AppLayerParameters_t *parameters,
|
||
int is_sequence, uint8_t *buffer, uint16_t capacity, uint16_t *length)
|
||
{
|
||
const IEC60870_InformationObjectVTable *type;
|
||
uint8_t payload[IEC60870_OBJECT_MAX_PAYLOAD];
|
||
uint16_t address_size, payload_size, required;
|
||
if (object == NULL || buffer == NULL || length == NULL ||
|
||
!IEC60870_AppLayerParameters_Valid(parameters) ||
|
||
(is_sequence != 0 && is_sequence != 1)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
type = IEC60870_InformationObject_Get_Descriptor(object->type_id);
|
||
if (type == NULL) { return IEC60870_ASDU_UNSUPPORTED; }
|
||
/* 先比较受控静态表的地址,再解引用函数表,拒绝身份不匹配的对象。 */
|
||
if (object->virtual_function_table != type ||
|
||
object->ioa > IEC60870_Object_Max_IOA(parameters) ||
|
||
(is_sequence && !type->supports_sequence) ||
|
||
!object->virtual_function_table->encode(object, payload)) {
|
||
return IEC60870_ASDU_ERROR;
|
||
}
|
||
/* 函数表只生成值载荷;统一入口在前面补IOA,避免各类型重复处理宽度。 */
|
||
address_size = is_sequence ? 0U : (uint16_t)parameters->sizeOfIOA;
|
||
payload_size = type->get_payload_size ? type->get_payload_size(object) : type->payload_size;
|
||
if (payload_size > sizeof(payload)) { return IEC60870_ASDU_ERROR; }
|
||
required = (uint16_t)(address_size + payload_size);
|
||
if (capacity < required) { return IEC60870_ASDU_FULL; }
|
||
if (address_size != 0U) {
|
||
IEC60870_Object_Write_LE(buffer, object->ioa, address_size);
|
||
}
|
||
memcpy(buffer + address_size, payload, payload_size);
|
||
*length = required;
|
||
return IEC60870_ASDU_OK;
|
||
}
|
||
|
||
/**
|
||
* 功能:按Type ID分派具体载荷解析器,供ASDU校验和取对象共用。
|
||
* 输入参数:type_id——需要解析的具体类型。
|
||
* ioa——已还原的地址,0..0xFFFFFF。
|
||
* payload——不含IOA的载荷;只有0字节载荷的读命令允许NULL。
|
||
* length——载荷字节数,须精确匹配该类型。
|
||
* object_size——非空object的可用字节数,至少为该具体结构的sizeof。
|
||
* 输出参数:object——匹配具体类型的输出存储;NULL表示仅校验,不输出对象。
|
||
* 返回值:OK为成功,UNSUPPORTED为未知类型,ERROR为地址、长度、字段或存储尺寸非法。
|
||
* 说明:每个分支使用对应的局部具体对象,成功后才memcpy写回,不向调用方暴露部分结果。
|
||
* 存储尺寸检查不能替代类型匹配;调用方须依据Type ID选择正确的结构体。
|
||
*/
|
||
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)
|
||
{
|
||
const IEC60870_InformationObjectVTable *type = IEC60870_InformationObject_Get_Descriptor(type_id);
|
||
if (type == NULL) { return IEC60870_ASDU_UNSUPPORTED; }
|
||
if (object != NULL && object_size < type->object_size) { return IEC60870_ASDU_ERROR; }
|
||
/* 编码时对象已经有函数表;解码时只有Type ID,必须先选择对应结构及解析器。 */
|
||
switch (type_id) {
|
||
case 1: {
|
||
IEC60870_SinglePointInformation_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SinglePointInformation_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 3: {
|
||
IEC60870_DoublePointInformation_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_DoublePointInformation_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 9: {
|
||
IEC60870_MeasuredValueNormalized_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueNormalized_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 11: {
|
||
IEC60870_MeasuredValueScaled_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueScaled_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 13: {
|
||
IEC60870_MeasuredValueShort_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueShort_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 15: {
|
||
IEC60870_IntegratedTotals_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_IntegratedTotals_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 30: {
|
||
IEC60870_SinglePointWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SinglePointWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 31: {
|
||
IEC60870_DoublePointWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_DoublePointWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 34: {
|
||
IEC60870_MeasuredValueNormalizedWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueNormalizedWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 35: {
|
||
IEC60870_MeasuredValueScaledWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueScaledWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 36: {
|
||
IEC60870_MeasuredValueShortWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueShortWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 37: {
|
||
IEC60870_IntegratedTotalsWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_IntegratedTotalsWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 45: {
|
||
IEC60870_SingleCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SingleCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 46: {
|
||
IEC60870_DoubleCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_DoubleCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 47: {
|
||
IEC60870_StepCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_StepCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 48: {
|
||
IEC60870_SetpointCommandNormalized_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SetpointCommandNormalized_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 49: {
|
||
IEC60870_SetpointCommandScaled_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SetpointCommandScaled_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 50: {
|
||
IEC60870_SetpointCommandShort_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SetpointCommandShort_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 58: {
|
||
IEC60870_SingleCommandWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SingleCommandWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 59: {
|
||
IEC60870_DoubleCommandWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_DoubleCommandWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 60: {
|
||
IEC60870_StepCommandWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_StepCommandWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 61: {
|
||
IEC60870_SetpointCommandNormalizedWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SetpointCommandNormalizedWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 62: {
|
||
IEC60870_SetpointCommandScaledWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SetpointCommandScaledWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 63: {
|
||
IEC60870_SetpointCommandShortWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SetpointCommandShortWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 100: {
|
||
IEC60870_InterrogationCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_InterrogationCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 101: {
|
||
IEC60870_CounterInterrogationCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_CounterInterrogationCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 102: {
|
||
IEC60870_ReadCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ReadCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 103: {
|
||
IEC60870_ClockSynchronizationCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ClockSynchronizationCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 105: {
|
||
IEC60870_ResetProcessCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ResetProcessCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 107: {
|
||
IEC60870_TestCommandWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_TestCommandWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 5: {
|
||
IEC60870_StepPositionInformation_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_StepPositionInformation_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 7: {
|
||
IEC60870_BitString32_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_BitString32_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 2: {
|
||
IEC60870_SinglePointWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SinglePointWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 4: {
|
||
IEC60870_DoublePointWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_DoublePointWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 6: {
|
||
IEC60870_StepPositionWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_StepPositionWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 8: {
|
||
IEC60870_Bitstring32WithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_Bitstring32WithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 10: {
|
||
IEC60870_MeasuredValueNormalizedWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueNormalizedWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 12: {
|
||
IEC60870_MeasuredValueScaledWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueScaledWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 14: {
|
||
IEC60870_MeasuredValueShortWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueShortWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 16: {
|
||
IEC60870_IntegratedTotalsWithCP24Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_IntegratedTotalsWithCP24Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 32: {
|
||
IEC60870_StepPositionWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_StepPositionWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 33: {
|
||
IEC60870_Bitstring32WithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_Bitstring32WithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 17: {
|
||
IEC60870_EventOfProtectionEquipment_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_EventOfProtectionEquipment_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 18: {
|
||
IEC60870_PackedStartEventsOfProtectionEquipment_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_PackedStartEventsOfProtectionEquipment_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 19: {
|
||
IEC60870_PackedOutputCircuitInfo_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_PackedOutputCircuitInfo_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 38: {
|
||
IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_EventOfProtectionEquipmentWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 39: {
|
||
IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 40: {
|
||
IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_PackedOutputCircuitInfoWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 20: {
|
||
IEC60870_PackedSinglePointWithSCD_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_PackedSinglePointWithSCD_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 21: {
|
||
IEC60870_MeasuredValueNormalizedWithoutQuality_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_MeasuredValueNormalizedWithoutQuality_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 51: {
|
||
IEC60870_Bitstring32Command_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_Bitstring32Command_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 64: {
|
||
IEC60870_Bitstring32CommandWithCP56Time2a_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_Bitstring32CommandWithCP56Time2a_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 70: {
|
||
IEC60870_EndOfInitialization_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_EndOfInitialization_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 104: {
|
||
IEC60870_TestCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_TestCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 106: {
|
||
IEC60870_DelayAcquisitionCommand_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_DelayAcquisitionCommand_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 110: {
|
||
IEC60870_ParameterNormalizedValue_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ParameterNormalizedValue_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 111: {
|
||
IEC60870_ParameterScaledValue_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ParameterScaledValue_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 112: {
|
||
IEC60870_ParameterFloatValue_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ParameterFloatValue_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 113: {
|
||
IEC60870_ParameterActivation_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_ParameterActivation_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 120: {
|
||
IEC60870_FileReady_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_FileReady_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 121: {
|
||
IEC60870_SectionReady_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_SectionReady_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 122: {
|
||
IEC60870_FileCallOrSelect_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_FileCallOrSelect_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 124: {
|
||
IEC60870_FileACK_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_FileACK_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 123: {
|
||
IEC60870_FileLastSegmentOrSection_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_FileLastSegmentOrSection_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 125: {
|
||
IEC60870_FileSegment_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_FileSegment_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 126: {
|
||
IEC60870_FileDirectory_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_FileDirectory_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
case 127: {
|
||
IEC60870_QueryLog_t result;
|
||
IEC60870_AsduResult_t status = IEC60870_QueryLog_Get_From_Buffer(&result, ioa, payload, length);
|
||
if (status == IEC60870_ASDU_OK && object != NULL) { memcpy(object, &result, sizeof(result)); }
|
||
return status;
|
||
}
|
||
default: return IEC60870_ASDU_UNSUPPORTED;
|
||
}
|
||
}
|
||
|