数据更新及接口
IEC61850将电力装置抽象为服务及数据模型,就好像盖了一个IEC61850的大厦,大厦里有楼层有房间,房间里放着数据,例如储能设备某电芯的电压就在IEC61850的大厦的某个房间中存放,如何将测量到的电压写到对应的房间呢?这就用到了YX-PIS的数据更新接口。
YX-PIS目前提供了五个数据更新接口,本文介绍如下四个接口
IEC61850_UpdateWithReference()
IEC61850_UpdateWithShortAddr()
IEC61850_Update()
IEC61850_UpdateWithQT()
还有一个批量更新的接口是需要通过控制块进行更新数据,本文暂不介绍,接口名称如下:
IEC61850_BatchUpdateControlBlockDatas()
先做一些改进
本文承接上一文的代码进行,为了方便先做一些调整
调整环境变量
环境变量Path中添加动态库目录,这样就不用将dll拷贝到可执行文件目录了
调整CID文件位置
在项目目录中新建cidFiles目录,将cid文件从可执行文件目录拷贝到这个目录
加载cid部分的代码调整如下:
error = IEC61850_LoadSCLFile(g_iec61850, "../../../cidFiles/testIED.cid");
调整CMakeList
为了使得MMS和CMS的切换更方便,调整后如下:
cmake_minimum_required (VERSION 3.8)
project ("iec61850server")
set(COMMUNICATION_PROTOCOL "MMS") # 设置MMS或者CMS
if(COMMUNICATION_PROTOCOL STREQUAL "MMS")
include_directories("yx-pis-dll/mms/include")
link_directories(${CMAKE_SOURCE_DIR}/yx-pis-dll/mms)
#target_link_libraries(iec61850server mms-ctk)
elseif(COMMUNICATION_PROTOCOL STREQUAL "CMS")
include_directories("yx-pis-dll/cms/include")
link_directories(${CMAKE_SOURCE_DIR}/yx-pis-dll/cms)
#target_link_libraries(iec61850server cms-ctk)
endif()
add_executable (iec61850server "iec61850server.c" "IEC61850Functions.c")
if(COMMUNICATION_PROTOCOL STREQUAL "MMS")
target_link_libraries(iec61850server mms-ctk)
elseif(COMMUNICATION_PROTOCOL STREQUAL "CMS")
target_link_libraries(iec61850server cms-ctk)
endif()
建立好大厦的房间
通过建模工具打开模型文件testIED.cid文件,添加一个逻辑节点,相当于给大厦加盖一层楼
然后选择逻辑节点类
选择需要添加的数据
保存后效果如图:
那么这个数据i的引用我们可以看到是TEMPLATELDevice1/MMXU0.A.phsA.cVal.mag.i,这里面TEMPLATELDevice1是逻辑设备名称,由于我未设置逻辑设备名,所以采用IED名称+逻辑设备实例代替逻辑设备名。
保存这个模型后启动服务端,MMS通过iedscout读取,如图:
CMS通过cms-test-tool获取模型,如图:
添加源码文件
准备添加一个源码文件,专门用于一些函数调用的
改名为IEC61850Functions.c
同样方法增加IEC61850Functions.h文件
IEC61850Functions.h中增加代码
#pragma once
#include <stdio.h>
#include "IEC61850Types.h"
#include "IEC61850API.h"
#include "sysctype.h"
IEC61850Functions.c中增加代码
#include "IEC61850Functions.h"
extern IEC61850 g_iec61850;
iec61850server.c中
#include "IEC61850Types.h"
#include "IEC61850API.h"
#include "sysctype.h"
替换为
#include "IEC61850Functions.h"
通过引用更新
在IEC61850Functions.h增加函数原型IEC61850_ErrorCode UpdateMMXUPhsAMagi()
在IEC61850Functions.h增加函数定义
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);
}
iec61850server.c中main函数中getchar()之前调用该函数,调试运行程序按提示输入整数,例如12345,如图:
然后通过工具,读取当前值,MMS版如下图:
CMS版如下图:
说明数据更新成功。
通过短地址更新
再调整一下模型
按下图设置短地址
假设输入 B.i 然后保存
编码
在IEC61850Functions.h增加函数原型IEC61850_ErrorCode UpdateMMXUPhsBMagi()
在IEC61850Functions.h增加函数定义
IEC61850_ErrorCode UpdateMMXUPhsBMagi()
{
IEC61850_ErrorCode result = S_OK;
S32 newVal = 0;
IEC61850_DataAttributeData daData = { 0 };
char* sAddr = "B.i";
printf("Enter an S32 value: ");
scanf("%d", &newVal);
daData.bitLength = sizeof(S32) * 8;
daData.type = IEC61850_DATATYPE_INT32;
daData.pvData = &newVal;
result = IEC61850_UpdateWithShortAddr(g_iec61850, &sAddr, &daData, 1);
}
调用本函数并运行,输入整数,例如67890
MMS版本查询如图:
CMS版本查询截图略
通过DAID更新
在模型中添加DAID
在IEC61850Functions.h增加函数原型IEC61850_ErrorCode UpdateMMXUPhsCMagi()
在IEC61850Functions.h增加函数定义
IEC61850_ErrorCode UpdateMMXUPhsCMagi()
{
IEC61850_ErrorCode result = S_OK;
S32 newVal = 0;
IEC61850_DataAttributeID daid = { 1, 0, 0, 0, 0 };
IEC61850_DataAttributeData daData = { 0 };
printf("Enter an S32 value: ");
scanf("%d", &newVal);
daData.bitLength = sizeof(S32) * 8;
daData.type = IEC61850_DATATYPE_INT32;
daData.pvData = &newVal;
result = IEC61850_Update(g_iec61850, &daid, &daData, 1);
}
调用本函数并运行,输入整数,例如45678
MMS版本查询如图:
CMS版本查询截图略
更新数据及质量和时间
IEC61850_UpdateWithQT接口支持引用、短地址、DAID三种方式,本次以DAID为例
在IEC61850Functions.h增加函数原型IEC61850_ErrorCode UpdateMMXUPhsCMagiWithQT()
在IEC61850Functions.h增加函数定义
IEC61850_ErrorCode UpdateMMXUPhsCMagiWithQT()
{
IEC61850_ErrorCode result = S_OK;
S32 newVal = 0;
IEC61850_DataAttributeID daid = { 1, 0, 0, 0, 0 };
IEC61850_DataAttributeDataQT daData = { 0 };
tIEC61850Quality q = IEC61850_QUALITY_FAILURE;
IEC61850_TimeStamp t = { 0 };
IEC61850_DataMapMode mapMode = IEC61850_MAP_MODE_DAID;
printf("Enter an S32 value: ");
scanf("%d", &newVal);
IEC61850_GetTime(NULL, &t);
daData.dataVal.bitLength = sizeof(S32) * 8;
daData.dataVal.type = IEC61850_DATATYPE_INT32;
daData.dataVal.pvData = &newVal;
daData.q = &q;
daData.t = &t;
result = IEC61850_UpdateWithQT(g_iec61850, &daid, &daData, 1, mapMode);
}
调用该函数运行,输入整数,例如123
MMS版本查询如图:
可以看到出了数值123,质量和时间也同步得到了更新
CMS版查询截图略
IEC61850Functions.c中全部代码
#include "IEC61850Functions.h"
extern IEC61850 g_iec61850;
//采用引用方式更新A.PhsA数据
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);
}
//采用短地址方式更新A.PhsB数据
IEC61850_ErrorCode UpdateMMXUPhsBMagi()
{
IEC61850_ErrorCode result = S_OK;
S32 newVal = 0;
IEC61850_DataAttributeData daData = { 0 };
char* sAddr = "B.i";
printf("Enter an S32 value: ");
scanf("%d", &newVal);
daData.bitLength = sizeof(S32) * 8;
daData.type = IEC61850_DATATYPE_INT32;
daData.pvData = &newVal;
result = IEC61850_UpdateWithShortAddr(g_iec61850, &sAddr, &daData, 1);
}
//采用DAID方式更新A.PhsC数据
IEC61850_ErrorCode UpdateMMXUPhsCMagi()
{
IEC61850_ErrorCode result = S_OK;
S32 newVal = 0;
IEC61850_DataAttributeID daid = { 1, 0, 0, 0, 0 };
IEC61850_DataAttributeData daData = { 0 };
printf("Enter an S32 value: ");
scanf("%d", &newVal);
daData.bitLength = sizeof(S32) * 8;
daData.type = IEC61850_DATATYPE_INT32;
daData.pvData = &newVal;
result = IEC61850_Update(g_iec61850, &daid, &daData, 1);
}
//采用DAID方式更新A.PhsC数据,并同步更新质量和时间
IEC61850_ErrorCode UpdateMMXUPhsCMagiWithQT()
{
IEC61850_ErrorCode result = S_OK;
S32 newVal = 0;
IEC61850_DataAttributeID daid = { 1, 0, 0, 0, 0 };
IEC61850_DataAttributeDataQT daData = { 0 };
tIEC61850Quality q = IEC61850_QUALITY_FAILURE;
IEC61850_TimeStamp t = { 0 };
IEC61850_DataMapMode mapMode = IEC61850_MAP_MODE_DAID;
printf("Enter an S32 value: ");
scanf("%d", &newVal);
IEC61850_GetTime(NULL, &t);
daData.dataVal.bitLength = sizeof(S32) * 8;
daData.dataVal.type = IEC61850_DATATYPE_INT32;
daData.dataVal.pvData = &newVal;
daData.q = &q;
daData.t = &t;
result = IEC61850_UpdateWithQT(g_iec61850, &daid, &daData, 1, mapMode);
}