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

7353 lines
366 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 信息对象的具体实现。每个类型分别定义值编解码、只读编码函数表及公开构造/解析入口。
* 带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;
}
}