ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

零基础实现IEC61850(七)细说数据更新

零基础实现IEC61850(七)细说数据更新

前言

前面的文章用到了数据更新,但是重点介绍的是方法,然而IEC61850提供了多种数据类型,都可能让使用者感觉无从下手,所以需要有一篇文章进行全面的介绍,本文重点根据类型区分介绍。
本文所有样例源码已经上传至https://gitee.com/yunxingtianxia/yx-tools 的 yx-pis-dll\example\07 updateData 目录

IEC61850都有哪些类型

类型类型描述协议栈定义
BOOLEAN布尔IEC61850_DATATYPE_BOOLEAN
INT8有符号整型IEC61850_DATATYPE_INT8
INT16有符号整型IEC61850_DATATYPE_INT16
INT32有符号整型IEC61850_DATATYPE_INT32
INT64有符号整型IEC61850_DATATYPE_INT64
INT8U无符号整型IEC61850_DATATYPE_INT8U
INT16U无符号整型IEC61850_DATATYPE_INT16U
INT32U无符号整型IEC61850_DATATYPE_INT32U
FLOAT32单精度浮点型IEC61850_DATATYPE_FLOAT32
FLOAT64双精度浮点型IEC61850_DATATYPE_FLOAT64
ENUMERATED枚举IEC61850_DATATYPE_ENUMERATED
CODEDENUM枚举IEC61850_DATATYPE_CODED_ENUM
OCTETSTRING八位组串IEC61850_DATATYPE_OCTET_STRING
VisibleString可视字符串IEC61850_DATATYPE_VISIBLE_STRING
UNICODESTRINGUnicode字符串IEC61850_DATATYPE_UNICODE_STRING
TimeStamp时间戳IEC61850_DATATYPE_TIMESTAMP
Quality品质IEC61850_DATATYPE_QUALITY

协议栈类型使用规则

我们统一使用数据属性结构体(IEC61850_DataAttributeData)来进行数据模型中数据属性进行赋值取值的操作

structIEC61850_DataAttributeData{unsignedchartype;/*!< 数据类型。<br>取值为 `enum IEC61850_DataType` 类型的枚举值之一。<br>若数据类型为数组或者结构体,则每个数组元素或结构体成员,都将是一个单独的 `IEC61850_DataAttributeData` 类型的数据。 */intarrayIndex;/*!< 数组元素索引。<br>若当前数据属性为数组类型数据中的某个元素时,该值有效,值为当前数据对应的数组元素索引;否则该值无意义,值为 0。 */unsignedintbitLength;/*!< 数据长度信息。其值的意义,因数据类型而异。<br>若数据类型是数组,则该值代表数组元素数量;<br>若数据类型是结构体,则代表结构体成员的数量;<br>若数据类型既不是数组也不是结构体,则该值代表对应数据类型所占的实际位(bit)数。(例如,INT32 类型数据大小为 32 bit,则该值对应为 32。) */void*pvData;/*!< 数据值的指针。<br>该指针指向数据值所在的内存空间地址。<br>若数据类型为数组数据,则该指针指向一个包含 `bitLength` 个 `IEC61850_DataAttributeData` 类型的数组元素的数组的首地址;<br>若数据类型为结构体,则该指针指向一个由 `bitLength` 个连续的 `IEC61850_DataAttributeData` 类型的结构体成员数据所构成的内存空间的首地址;<br>若数据类型既不是数组,也不是结构体,则可以按照对应的数据类型对该地址解引用来获取数据值。 */}

看看之前的例子

IEC61850_ErrorCodeUpdateMMXUPhsAMagi(){IEC61850_ErrorCode result=S_OK;S32 newVal=0;IEC61850_DataAttributeData daData={0};char*reference="TEMPLATELDevice1/MMXU0.A.phsA.cVal.mag.i";printf("Enter an S32 value: ");scanf("%d",&newVal);daData.bitLength=sizeof(S32)*8;daData.type=IEC61850_DATATYPE_INT32;daData.pvData=&newVal;result=IEC61850_UpdateWithReference(g_iec61850,reference,&daData);}

这里面和类型相关,会存在差异的部分只有这四行

S32 newVal=0;//定义合适的变量daData.bitLength=sizeof(S32)*8;//指定数据长度daData.type=IEC61850_DATATYPE_INT32;//指定数据类型daData.pvData=&newVal;//指针指向正确的变量

接下来就针对不同类型,交代不同类型的这四行代码如何写

建模

建模工具直接访问云端版:
http://scl.yunxing.tech:8888
也可在该地址下载桌面版。

创建一个CID模型


模型中尽量包含全面的数据类型。

详细可查看本样例代码提供的CID文件,这里为每个要更新的数据属性都设置了DAID。

<LNinst="0"lnClass="GGIO"lnType="GGIO_0"prefix=""><DOIdesc="Behaviour"name="Beh"><DAIname="stVal"sAddr="@5.0.0.0.0"/><DAIname="d"sAddr="@5.0.0.0.1"/><DAIname="dU"sAddr="@5.0.0.0.2"/></DOI><DOIdesc="General single alarm"name="Alm_bool"><DAIname="stVal"sAddr="@0.0.0.0.1"/><DAIname="q"sAddr="@0.0.0.0.2"/><DAIname="t"sAddr="@0.0.0.0.3"/></DOI><DOIdesc="Analogue input"name="AnIn_int8"><SDIname="mag"><DAIname="i"sAddr="@1.0.0.0.8"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_int16"><SDIname="mag"><DAIname="i"sAddr="@1.0.0.0.16"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_int32"><SDIname="mag"><DAIname="i"sAddr="@1.0.0.0.32"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_int64"><SDIname="mag"><DAIname="i"sAddr="@1.0.0.0.64"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_int8u"><SDIname="mag"><DAIname="i"sAddr="@2.0.0.0.8"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_int16u"><SDIname="mag"><DAIname="i"sAddr="@2.0.0.0.16"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_int32u"><SDIname="mag"><DAIname="i"sAddr="@2.0.0.0.32"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_float32"><SDIname="mag"><DAIname="f"sAddr="@3.0.0.0.32"/></SDI></DOI><DOIdesc="Analogue input"name="AnIn_float64"><SDIname="mag"><DAIname="f"sAddr="@3.0.0.0.64"/></SDI></DOI><DOIdesc="Double point controllable status output"name="DPCSO11"><DAIname="stVal"sAddr="@6.0.0.0.0"/></DOI></LN>

BOOLEAN布尔

Boolean newVal=TRUE;daData.bitLength=8;daData.type=IEC61850_DATATYPE_BOOLEAN;daData.pvData=&newVal;

INT8有符号整型

S8 newVal=123; daData.bitLength=8;daData.type=IEC61850_DATATYPE_INT8;daData.pvData=&newVal;

INT16有符号整型

S16 newVal=123; daData.bitLength=16;daData.type=IEC61850_DATATYPE_INT16;daData.pvData=&newVal;

INT32有符号整型

S32 newVal=123; daData.bitLength=32;daData.type=IEC61850_DATATYPE_INT32;daData.pvData=&newVal;

INT64有符号整型

S64 newVal=123; daData.bitLength=64;daData.type=IEC61850_DATATYPE_INT64;daData.pvData=&newVal;

INT8U无符号整型

U8 newVal=123;daData.bitLength=8;daData.type=IEC61850_DATATYPE_INT8U;daData.pvData=&newVal;

INT16U无符号整型

U16 newVal=123;daData.bitLength=16;daData.type=IEC61850_DATATYPE_INT16U;daData.pvData=&newVal;

INT32U无符号整型

U32 newVal=123;daData.bitLength=32;daData.type=IEC61850_DATATYPE_INT32U;daData.pvData=&newVal;

FLOAT32单精度浮点型

Float32 newVal=0.8;daData.bitLength=32;daData.type=IEC61850_DATATYPE_FLOAT32;daData.pvData=&newVal;

FLOAT64双精度浮点型

Float64 newVal=0.8;daData.bitLength=64;daData.type=IEC61850_DATATYPE_FLOAT64;daData.pvData=&newVal;

ENUMERATED枚举

枚举类型还是有些特殊,在CID建模中,类型选择Enum,并要其指定具体的定义,不过一般我们用标准定义好的,比如Beh的状态值,定义如下:

<EnumTypeid="BehaviourModeKind"><EnumValord="1">on</EnumVal><EnumValord="2">blocked</EnumVal><EnumValord="3">test</EnumVal><EnumValord="4">test/blocked</EnumVal><EnumValord="5">off</EnumVal></EnumType>

其实所谓枚举值,就是为该值赋值枚举定义的值,这里面是1,2,3,4,5。以此为例代码如下:

tIEC61850Enum newVal=1;daData.bitLength=IEC61850_ENUM_BITSIZE;daData.type=IEC61850_DATATYPE_ENUMERATED;daData.pvData=&newVal;

CODEDENUM固定枚举

这种是不需要自定义枚举值的,而是固定的一些类型,比如CID模型中的Tcmd、Dbpos等
以Dbpos为例子,其他的因为不常用,如果确实用到可以联系我们

eDbPosValues newVal=DBPOS_ON;daData.bitLength=IEC61850_DBPOS_BITSIZE;daData.type=IEC61850_DATATYPE_DBPOS;daData.pvData=&newVal;

OCTETSTRING八位组串

这个就略了,因为几乎没有需要用户去更新和使用该类型的场景,如果确实用到可以联系我们

VisibleString可视字符串

char*newVal="this is new VisibleString";daData.bitLength=strnlen(newVal,255)*8;daData.type=IEC61850_DATATYPE_VISIBLE_STRING;daData.pvData=newVal;

UNICODESTRINGUnicode字符串

注意:这里源码文件本身采用了utf8编码,目前所使用的vs2022用安装了Force UTF-8(No Bom)2022插件

char*newVal="这里是中文";daData.bitLength=strnlen(newVal,255)*8;daData.type=IEC61850_DATATYPE_UNICODE_STRING;daData.pvData=newVal;

TimeStamp时间戳

IEC61850_TimeStamp t={0};IEC61850_GetTime(NULL,&t);daData.bitLength=IEC61850_TIMESTAMP_BITSIZE;daData.type=IEC61850_DATATYPE_TIMESTAMP;daData.pvData=&t;

Quality品质

IEC61850_QualityFlag q=IEC61850_QUALITY_GOOD;daData.bitLength=IEC61850_QUALITY_BITSIZE;daData.type=IEC61850_DATATYPE_QUALITY;daData.pvData=&q;
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进