现在的位置: 首页 > 程序设计> 正文
libiec61850在OpenSCADA系统中的使用(二)
2013年08月15日 程序设计 暂无评论 ⁄ 被围观 3,831+

上一篇文章《libiec61850在OpenSCADA系统中的使用》介绍了libiec61850和OpenSCADA系统的混合编译,编译是没有问题,但是做成模块的话运行起来还是会出现问题,其中最主要的问题就是库的链接,导致运行时函数找不到,原因出在C和C++函数相互调用的关系,libiec61850是C库,OpenSCADA是C++。

本文采用将libiec61850编译成动态库的方式供OpenSCADA系统调用,步骤如下:

动态库的编译安装

1. 修改libiec61850的 "lib61850\make\target_system.mk" 文件,编译选项添加fPIC

CFLAGS += -g
CFLAGS += -fPIC

2. 修改libiec61850 的“lib61850\Makefile”文件,添加生成动态库的参数soname

$(DYN_LIB_NAME): $(LIB_OBJS)
$(CC) $(LDFLAGS) -lpthread -shared -Wl,-soname -Wl,libiec61850.so -o $(DYN_LIB_NAME) $(LIB_OBJS) $(LDLIBS)

3. 编译生成动态库

$ make dynlib

生成 “lib61850\build\libiec61850.so”文件

4. 安装动态库到系统目录

$ /usr/bin/install -c lib61850/build/libiec61850.so /usr/lib/i386-linux-gnu/libiec61850.so

5. 修改OpenSCADA SP61850 module的 "Makefile.am" 文件,动态链接libiec61850.so

#!!! The module link flags
spec_SP61850_la_LDFLAGS = -module -avoid-version -no-undefined -Llib61850/build -liec61850 $(SP61850_LDLAGS)

############ for lib61850 include header file and lib file ##################
AM_CPPFLAGS = -Ilib61850/inc -Ilib61850/src/common -Ilib61850/src/mms/iso_presentation -Ilib61850/src/mms/iso_session -Ilib61850/src/mms/iso_cotp -Ilib61850/src/mms/iso_acse -Ilib61850/src/mms/iso_mms/common -Ilib61850/src/mms/iso_mms/client -Ilib61850/src/mms/iso_mms/server -Ilib61850/src/mms/iso_client -Ilib61850/src/mms/iso_server -Ilib61850/src/mms/asn1 -Ilib61850/src/iedcommon -Ilib61850/src/iedserver/mms_mapping -Ilib61850/src/iedserver/model -Ilib61850/src/iedserver -Ilib61850/src/iedclient -Ilib61850/src/hal -Ilib61850/src/hal/thread -Ilib61850/src/hal/socket -Ilib61850/src/goose
#############################################################################

测试代码的编写

1. 修改“SP61850\module.h”头文件,添加libiec6180的常用头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/////////////////////////////////////////////////////////
extern "C"
{
#include "iec61850_server.h"
#include "iso_server.h"
#include "acse.h"
#include "thread.h"
#include <stdlib.h>
#include <stdio.h>
 
#include "static_model.h"
 
/* import IEC 61850 device model created from SCL-File */
extern IedModel iedModel;
}
////////////////////////////////////////////////////////
 
////C++类(class Lib : public TSpecial)内部添加属性
///////////////////////////////////////////////////////////
 
int running;
IedServer iedServer;
///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
extern "C"
{
#include "iec61850_server.h"
#include "iso_server.h"
#include "acse.h"
#include "thread.h"
#include <stdlib.h>
#include <stdio.h>

#include "static_model.h"

/* import IEC 61850 device model created from SCL-File */
extern IedModel iedModel;
}
////////////////////////////////////////////////////////

////C++类(class Lib : public TSpecial)内部添加属性
///////////////////////////////////////////////////////////

int running;
IedServer iedServer;
///////////////////////////////////////////////////////////

2. 修改“SP61850\module.cpp”文件,控制服务器的启动与停止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//////// 启动服务器 void Lib::modStart( )
 
//61850 server.
if(! running)
{
iedServer = IedServer_create(&iedModel);
 
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
 
/* Instruct the server that we will be informed if a clients writes to a
* certain variables we are interested in.
*/
IedServer_observeDataAttribute(iedServer, IEDMODEL_Device1_DSCH1_NamPlt_vendor,
observerCallback);
 
IedServer_observeDataAttribute(iedServer, IEDMODEL_Device1_DSCH1_NamPlt_swRev,
observerCallback);
 
if (!IedServer_isRunning(iedServer))
{
mess_err(nodePath().c_str(),_("Start 61850 Server error."));
IedServer_destroy(iedServer);
}
else
{
running = 1;
}
}
 
////// 停止服务器 void Lib::modStop( )
//
if(running)
{
/* stop MMS server - close TCP server socket and all client sockets */
IedServer_stop(iedServer);
 
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
 
running = 0;
}
//////// 启动服务器 void Lib::modStart( )

//61850 server.
if(! running)
{
iedServer = IedServer_create(&iedModel);

/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);

/* Instruct the server that we will be informed if a clients writes to a
* certain variables we are interested in.
*/
IedServer_observeDataAttribute(iedServer, IEDMODEL_Device1_DSCH1_NamPlt_vendor,
observerCallback);

IedServer_observeDataAttribute(iedServer, IEDMODEL_Device1_DSCH1_NamPlt_swRev,
observerCallback);

if (!IedServer_isRunning(iedServer))
{
mess_err(nodePath().c_str(),_("Start 61850 Server error."));
IedServer_destroy(iedServer);
}
else
{
running = 1;
}
}

////// 停止服务器 void Lib::modStop( )
//
if(running)
{
/* stop MMS server - close TCP server socket and all client sockets */
IedServer_stop(iedServer);

/* Cleanup - free all resources */
IedServer_destroy(iedServer);

running = 0;
}

3. 注册数据监听函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
extern "C"
{
void observerCallback(DataAttribute* dataAttribute)
{
if (dataAttribute == IEDMODEL_Device1_DSCH1_NamPlt_vendor)
{
printf("GGIO.NamPlt.vendor changed to %s\n",
MmsValue_toString(dataAttribute->mmsValue));
}
else if (dataAttribute == IEDMODEL_Device1_DSCH1_NamPlt_swRev)
{
printf("GGIO.NamPlt.swRef changed to %s\n",
MmsValue_toString(dataAttribute->mmsValue));
}
}
}
extern "C"
{
void observerCallback(DataAttribute* dataAttribute)
{
if (dataAttribute == IEDMODEL_Device1_DSCH1_NamPlt_vendor)
{
printf("GGIO.NamPlt.vendor changed to %s\n",
MmsValue_toString(dataAttribute->mmsValue));
}
else if (dataAttribute == IEDMODEL_Device1_DSCH1_NamPlt_swRev)
{
printf("GGIO.NamPlt.swRef changed to %s\n",
MmsValue_toString(dataAttribute->mmsValue));
}
}
}

4. 生成测试数据,修改数据节点

1
2
3
4
5
6
7
8
9
10
11
12
////////////////////for test/////////////////////////////
if(running)
{
MmsValue* td = MmsValue_newIntegerFromInt32 (200);
IedServer_updateAttributeValue(iedServer, IEDMODEL_Device1_DSCH1_SchdSt_stVal, td);
MmsValue_delete(td);
 
td = MmsValue_newIntegerFromInt32 (202);
IedServer_updateAttributeValue(iedServer, IEDMODEL_Device1_DSCH1_Health_stVal, td);
MmsValue_delete(td);
}
////////////////////////////////////////////////
////////////////////for test/////////////////////////////
if(running)
{
MmsValue* td = MmsValue_newIntegerFromInt32 (200);
IedServer_updateAttributeValue(iedServer, IEDMODEL_Device1_DSCH1_SchdSt_stVal, td);
MmsValue_delete(td);

td = MmsValue_newIntegerFromInt32 (202);
IedServer_updateAttributeValue(iedServer, IEDMODEL_Device1_DSCH1_Health_stVal, td);
MmsValue_delete(td);
}
////////////////////////////////////////////////

系统测试

1. 编译SP61850 模块

$cd openscada-0.8.0.5/src/moduls/special/SP61850

$ make clean; make

$ ~/project/openscada-0.8.0.5/src/moduls/special/SP61850$ ldd .libs/spec_SP61850.so
linux-gate.so.1 => (0x00542000)
libiec61850.so => /usr/lib/i386-linux-gnu/libiec61850.so (0x007e7000)
libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0x00bc0000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0x00e84000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00110000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0x00273000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0x0028f000)
/lib/ld-linux.so.2 (0x00af2000)

$ sudo make install

2. 运行测试

$ sudo openscada

3. 利用61850客户端软件进行连接确认,例如IEDScout,连接[192.168.1.160:102]

参考资料

1. http://libiec61850.com/api/

2. http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

给我留言

留言无头像?


×
腾讯微博