零基础实现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)来进行数据模型中数据属性进行赋值取值的操作

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

看看之前的例子

IEC61850_ErrorCode UpdateMMXUPhsAMagi()
{
	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;	             //指针指向正确的变量

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

创建一个CID模型

在这里插入图片描述
模型中尽量包含全面的数据类型。
在这里插入图片描述

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

 <LN inst="0" lnClass="GGIO" lnType="GGIO_0" prefix="">
    <DOI desc="Behaviour" name="Beh">
       <DAI name="stVal" sAddr="@5.0.0.0.0"/>
       <DAI name="d" sAddr="@5.0.0.0.1"/>
       <DAI name="dU" sAddr="@5.0.0.0.2"/>
    </DOI>
    <DOI desc="General single alarm" name="Alm_bool">
       <DAI name="stVal" sAddr="@0.0.0.0.1"/>
       <DAI name="q" sAddr="@0.0.0.0.2"/>
       <DAI name="t" sAddr="@0.0.0.0.3"/>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int8">
       <SDI name="mag">
          <DAI name="i" sAddr="@1.0.0.0.8"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int16">
       <SDI name="mag">
          <DAI name="i" sAddr="@1.0.0.0.16"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int32">
       <SDI name="mag">
          <DAI name="i" sAddr="@1.0.0.0.32"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int64">
       <SDI name="mag">
          <DAI name="i" sAddr="@1.0.0.0.64"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int8u">
       <SDI name="mag">
          <DAI name="i" sAddr="@2.0.0.0.8"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int16u">
       <SDI name="mag">
          <DAI name="i" sAddr="@2.0.0.0.16"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_int32u">
       <SDI name="mag">
          <DAI name="i" sAddr="@2.0.0.0.32"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_float32">
       <SDI name="mag">
          <DAI name="f" sAddr="@3.0.0.0.32"/>
       </SDI>
    </DOI>
    <DOI desc="Analogue input" name="AnIn_float64">
       <SDI name="mag">
          <DAI name="f" sAddr="@3.0.0.0.64"/>
       </SDI>
    </DOI>
    <DOI desc="Double point controllable status output" name="DPCSO11">
       <DAI name="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的状态值,定义如下:

      <EnumType id="BehaviourModeKind">
         <EnumVal ord="1">on</EnumVal>
         <EnumVal ord="2">blocked</EnumVal>
         <EnumVal ord="3">test</EnumVal>
         <EnumVal ord="4">test/blocked</EnumVal>
         <EnumVal ord="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; 
为了从零开始掌握libiec61850库并实现IEC61850标准的SCADA通信,你需要一个系统的学习路径和资源。《libiec61850源代码目录结构》将是你理解库内部结构和机制的基石。 参考资源链接:[libiec61850源代码目录结构](https://wenku.csdn.net/doc/6412b53fbe7fbd1778d427a4?spm=1055.2569.3001.10343) 首先,你需要对IEC61850标准有一个基本的理解,包括它的模型、通信服务和数据对象等概念。接下来,你应当熟悉libiec61850库的源代码目录结构,这将帮助你理解库的功能划分和如何利用它提供的API。 开始实践前,确保你的开发环境已经配置好了libiec61850库和相应的依赖。你可以从创建一个简单的客户端或服务器示例开始,逐步学习如何读写数据、管理连接和处理报文。《libiec61850源代码目录结构》中的目录划分和API文档将为你提供明确的指导。 在学习过程中,不断地在项目中实践是非常重要的。你可以从模拟一个简单的数据交换开始,然后逐步加入更多的功能和复杂场景,如数据对象的动态订阅和报告控制。在这个过程中,你将学会如何使用libiec61850提供的API,例如iec61850_client_new、iec61850_server_new等函数来创建客户端和服务器实例,并实现所需的功能。 在项目实战中,你还需要考虑网络通信的稳定性和安全性。使用libiec61850库时,务必了解其内置的连接管理机制和数据传输过程中的加密处理选项。通过实际的调试和测试,你可以优化通信性能,并处理可能出现的异常情况。 最终,当你能够顺利地在项目中实现基本的SCADA通信功能时,你可以进一步探索如何集成其他工业通信协议、实现更高级的控制逻辑和数据处理功能。《libiec61850源代码目录结构》不仅提供了库的结构分析,还能帮助你理解如何扩展库的功能以满足特定的需求。 在掌握libiec61850库之后,建议继续深入学习IEC61850标准的高级主题,如MMS和GOOSE消息处理,以及如何在复杂的工业网络中部署和维护基于IEC61850的应用。此外,参与开源社区的讨论和贡献也是提升技能和获取最新资讯的有效途径。 参考资源链接:[libiec61850源代码目录结构](https://wenku.csdn.net/doc/6412b53fbe7fbd1778d427a4?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云行老乔

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值