2023年11月30日发(作者:)

如何用FactorySoft OPC Server Toolkit实现

OPC数据访问服务器

How To Use FactorySoft OPC Server Toolkit

To Design An OPC Data Access Server

刘权

LiuQuan

摘要:本文介绍了一种简单方便的OPC服务器开发工具,并借用一个基于

DeviceNetOPC数据访问服务器的实例阐述了它的使用方法。

关键词:OPCCOM/DCOM,接口,客户/服务器,线程

AbstractThis article introduces an OPC server developing toolkit to the reader, and

uses a practical server example based on DeviceNet to illuminate the usage.

KeywordOPC, COM/DCOM, Interface, Client/Server, Thread

一、OPC数据访问技术概要

在一个过程工业的环境中有着多种多样的信息,这些信息从现场收集到后,被

集成到系统中供用户使用,但信息种类之繁多使信息的收集十分困难。一个客户端

应用需要调用多种驱动程序去进行信息收集,每种驱动程序的调用方法都可能不

同。系统中一旦出现不支持的驱动程序,就需要更改并重新编译客户端应用程序,

维护和扩展非常困难,因此需要有一种开放的高效的面向数据而不是数据类型的通

信体系结构来改变这种情况。OPCOLE for Process Control)就是这样一种基于

Windows操作系统COM/DCOM模型的通信体系结构标准。支持 OPC的客户端以

一种一致的方式去请求和获取 OPC服务器的数据,这种方式消除了繁杂的设备驱

动程序问题, 同时也加速了数据的传输。

OPC规范包含了数据访问规范、报警事件访问规范、历史数据访问规范等几个

部分,本文着重介绍OPC数据访问部分。一个OPC数据访问服务器向OPC客户

机提供多个OPC规范定义的COM接口,其体系结构如下图所示:

OPC定义的COM接口由定制接口(Custom Interfaces)和自动化接口

Automation Interfaces)两部分组成,一个OPC服务器必须实现所有的定制接

口,自动化接口主要用于VB开发的应用程序,可以选择实现。

一个OPC服务器由数个Server对象、Group对象和Item对象构成。Server

象包含了关于Server的信息并作为Group对象的容器;Group对象作为Item对象

的容器对Item对象进行逻辑上的组织,OPC支持对单个Group对象的禁止和使

能;每个Item代表对一个数据源的连接,而不是数据源本身。除Item外的每种对

象都实现了一套OPC定制接口,由OPC客户机调用来访问对象。Item对象不作为

OPC客户机可访问的对象,因此没有定义外部接口,所有对Item对象的访问都要

通过包含该Item对象的Group对象进行。

Server对象所包含的接口有:

IUnknown,每个COM接口所必须提供的标准接口,用于查询访问其它

COM接口。

IOPCCommon,提供了设置和查询指定客户机/服务器会话LocaleID的功

能,这个COM接口的实现使得每个客户机的动作彼此互不影响。

IOPCServer,是一个OPC服务器的主接口,提供了组对象管理和获取服务

器状态的功能,每个OPC服务器必须无条件的提供该COM接口。

IConnectionPointContainer,为IOPCShutdown接口提供对ConnectionPoint

的访问。

IOPCItemProperties,客户机使用该COM接口来浏览一个ITEMID所附带

的属性,并读取这些属性的当前值。该接口只适用于少量数据的浏览和读

取,大量数据可考虑实现可选接口IOPCBrowseServerAddressSpace

Group对象所包含的接口有:

IUnknown,每个COM接口所必须提供的标准接口,用于查询访问其它

COM接口。

IOPCItemMgt,为客户机提供了添加、删除Group中的Item及控制它的行

为的功能。

IOPCGroupStateMgt,为客户机提供了Group状态管理的功能,主要是改

变更新速率和激活状态。

IOPCSyncIO,为客户机提供对服务器的同步读写操作。

IOPCASyncIO2IOPCASyncIO的替代接口,为客户机提供了对服务器的

异步读写操作。IOPCASyncIO2引入了Transaction的概念,每次异步读写

都被看作是一个Transaction,被赋予一个TransactionID,以区分不同的异

步操作。

IConnectionPointContainer,为IOPCASyncIO2接口提供对ConnectionPoint

的访问。

二、FactorySoft OPC Server Toolkit

FactorySoft OPC Server Toolkit(下简称FS开发工具)是由美国FactorySoft

司制作的OPC服务器开发工具,它使用面向对象的技术将OPC规范所定义的

COM接口及其实现都封装到一个文件名为的动态链接库中,然后定义了

COPCCallback基类、COPCBrowser基类和CTag基类,这些类中定义了构建数据

路径、访问数据和提交数据的虚函数接口,开发者通过类的派生以及重载这些虚函

数来对数据的访问和提交进行定制。FS开发工具极大的简化了OPC服务器的开发

过程,使得开发者不用去实现OPC规范的每个细节,而集中精力到数据的访问和

提交上。一个用FS开发工具开发的OPC服务器的结构如下图所示:

App

Call

back

tag

tag

tag

L

L

.

D

e

r

r

v

S

e

F

S

OPC

Client

共输出了7API接口和3个类,描述如下:

1StartFSServer()

功能:开始的操作。

定义:void StartFSServer(HINSTANCE hInstance, CLSID* pCLSID)

参数:hInstanceOPC服务器程序的实例句柄。

PCLSID,指向OPC服务器程序CLSID的指针。

2StopFSServer()

功能:停止的操作。

定义:void StopFSServer()

3RegisterServer()

功能:在注册表中注册OPC服务器信息。

定义:HRESULT RegisterServer()

返回值:从ATL注册脚本处理器返回的HRESULT

4UnregisterServer()

功能:从注册表中删除OPC服务器的注册信息。

定义:HRESULT UnregisterServer()

返回值:从ATL注册脚本处理器返回的HRESULT

5SetCallbackObject()

功能:传递OPC服务器的Callback对象指针给。

定义:void SetCallbackObject(COPCCallback* pNewCallback )

参数:pNewCallback,指向新的Callback对象的指针。

6FSServerInUse()

功能:测试OPC服务器是否存在已经连接的客户端程序。

定义:void FSServerInUse()

返回值:如果存在已经连接的客户端则返回True,否则返回False

7MatchPattern()

功能:字符串匹配函数,用于浏览等功能。

定义:BOOL MatchPattern( LPCTSTR String, LPCTSTR Pattern, BOOL

bCaseSensitive )

参数:String,匹配的字符串,如Item名称等。

Pattern,用于匹配的表达式,语法遵照BASIC语言。

BcaseSensitiveTrue表示区分大小写,False表示不区分。

返回值:如果匹配成功返回True,否则返回False

8CTag

CTag类保存了每个Item的数据、质量、时间标签、访问权限和引用计数,使

CTag类访问Item的当前数据。引用计数用来判断CTag是否正在使用,当

Callback对象返回一个CTag指针时,引用计数加1,当使用完毕时,引用计数减

1,当引用计数为0时,可以对CTag进行删除或从扫描列表中移除等操作。CTag

的数据成员描述如下:

m_

value,保存Tag的数据值,VARIANT类型。

m_quality,,字,保存Tag数据的质量。

m_

timestampFILETIME类型,Tag数据的时间标签。

m_nativeTypeVARTYPE类型,保存Tag数据的类型。

OPC服务器程序访问现场数据时,应对值、质量和时间进行更新,然后通

过传递给客户端程序。OPC服务器程序可以从CTag类派生出自己的Tag类并加入

需要的其它信息,Callback对象的接口函数将使用CTag指针,开发者在定制

Callback对象时可将这些CTag指针强制转换为派生类指针。

9COPCCallback

COPCCallback类定义了FSServer DLLOPC服务器程序之间的接口,这些接

口提供了一个OPC服务器所需的全部基本行为。OPC服务器程序如果需要定制某

些接口,可从COPCCallback类派生自己的Callback类,然后重载要定制的接口函

数。COPCCallback中的Scan()用于扫描客户机需要访问的所有Tag,但是对于非

常慢的设备或者只有状态改变才产生数据的设备,应由OPC服务器程序创建子线

程访问这些数据,然后保存到缓冲区中等待客户端的访问,不要在Scan()中包含这

些设备。ReadTag()WriteTag()用于对数据的直接访问,当然,在Scan中也可以

调用ReadTag来读取数据。COPCCallback的主要接口函数(虚函数)描述如下:

(篇幅所限,恕不能一一详述)

QueryNumProperties(),查询指定名称对应Tag的属性个数。

QueryAvailableProperties(),查询指定名称对应Tag的属性ID、描述和类型。

GetItemProperties(),获取指定名称对应Tag的属性值。

LookupItemIDs(),根据属性查询对应的Tag名称。

CreateBrowser(),创建一个COPCBrowser对象并传递给。

SetUpdateRate(),设置Group更新间隔。

AddTag(),客户端添加Item后调用本接口函数,允许服务器端进行事后处理。

ValidateTag(),验证Tag的名称、访问路径和数据类型的合法性。

Remove(),通知服务器这些Tag已经被从Group中删除。

GetTagName(),获取指定Tag的名称。

Scan(),扫描添加到客户端的Tag,更新Tag的数据、质量和时间标签。

Read(),成批读取指定的Tag数据。

ReadTag(),读取指定Tag的数据。

Write(),修改指定Tag的数据。

WriteTag(),成批修改指定Tag数据。

GetServerState(),获取OPC服务器状态。

10COPCBrowser

COPCBrowser类用于对OPC服务器中的Item进行浏览。Callback对象的成员

函数CreateBrowser所创建的对象就是从COPCBrowser类派生出来的。当多个客户

端连接到OPC服务器时,Callback对象为每个客户端各创建一个Browser对象。

COPCBrowser类的接口函数(虚函数)描述如下:

~COPCBrowser()Browser对象的析购函数,派生类通过重载本函数来定制析

购过程。

QueryOrganization(),查询服务器的数据组织方式,树状模式或平板模式。

MoveUp(),将浏览位置移动到数据树的上一级,如果是平板模式返回False

MoveDown(),在数据树的当前浏览位置向下查询由参数指定的“树枝”,然

后将浏览位置移动这个“树枝”。如果数据树是平板模式返回False

GetNames(),设置浏览时的字符串过滤器、数据类型过滤器和访问过滤器,并

查询收集所有符合过滤条件的Tag名称。

GetItemID(),根据给定的Tag名称,获取其对应的ItemID(全路径)。

Next(),从GetNames()收集的Tag名称中,依次得到符合条件的每个Tag

称。

Reset(),重置Next()的开始位置。

GetAccessPaths(),获取给定Tag名称的所有访问路径。

NextAccessPath(),依次获取GetAccessPaths()所获得的每个访问路径。

三、一个OPC服务器的例子

为了充分说明FS开发工具的使用方法,现给出一个用FS开发工具开发的

DeviceNet OPC数据访问服务器的例子。

1、需求

用实现OPC数据访问接口。

DeviceNet OPC数据访问服务器应能自动查询总线上所挂接的设备,建立

设备扫描列表。

应可以自动与每个设备建立显式连接和I/O连接。

用子线程周期的对设备扫描列表中的每个设备的I/O数据进行扫描。

建立树状模式的OPC数据组织方式。

2、总体结构

初始化模块

D

e

设备扫描

Ov

线程

Pi

Cc

e

I/O数据处理模块

N

访e

t

I/O数据树

初始化模块完成的工作有:初始化OPC数据访问接口;初始化DeviceNet

通讯接口;查询DeviceNet总线上的设备建立设备扫描列表;与每个设备

建立I/O连接;创建设备扫描子线程;构建I/O数据树。

设备

扫描

列表

DeviceNet

总线

OPC

设备扫描线程负责周期性的对设备扫描列表中的每个设备进行扫描。

I/O数据处理模块一方面将设备扫描线程得到的I/O数据转换成OPC的数

据格式保存到I/O数据树的缓冲区中,另一方面将COPCCallback::Write()

COPCCallback::WriteTag()的数据转换成DeviceNet通讯帧发送到目的设

备中去。

3、代码片断

CApp::InitInstance()中初始化OPC数据访问接口:

BOOL CApp::InitInstance()

{

OleInitialize(NULL);

CDNetOpcCallback* pCallback = new CDNetOpcCallback;

if( !pCallback )

return FALSE;

if( !StartFSServer(m_hInstance, &CLSID_OPCServer) )

return FALSE;

//Register the Opc Server

……

SetCallbackObject( pHkopcCallback );

// Standard initialization

……

return TRUE;

}

CApp::ExitInstance()中停止

int CApp::ExitInstance()

{

StopFSServer();

OleUninitialize();

return CWinApp::ExitInstance();

}

CDnOpcCallback::AddTag()伪代码:

CTag* CDnOpcCallback::AddTag(LPCTSTR name, LPCTSTR accessPath,

VARTYPE requestedType)

{

return S_OK;

}

CDnOpcCallback::WriteTag()伪代码:

HRESULT CDnOpcCallback::WriteTag(CTag * pTag, VARIANT &value)

{

BYTE *pData = ConvertRequestedTypeToNativeType(pTag, value);

DN_FRAME *pFrame = PackDeviceNetFrame(pTag, pData);

SendDeviceNetFrame(pFrame);

return S_OK;

}

CDnOpcBrowser::MoveUp()代码:

BOOL CDnOpcBrowser::MoveUp()

{

if( m_pBranch->m_parent )

{

m_pBranch = m_pBranch->m_parent;

Reset();

return TRUE;

}

// at the "root" level, can't go up

参考文献

[1] Rockwell,《DeviceNet SpecificationRelease 2.01994

[2] OPC Foundation,《OPC SpecificationsRelease 2.0March1999

[3] FactorySoft,《OPC Server Toolkit GuideVersion 2.031999

作者简介:

刘权,男,1973年生,北方交通大学计算机科学系,计算机应用技术专业在读研

究生,现任北京华控技术有限责任公司副总工程师,一直从事现场总线相关软件设

计开发工作。

电话:010--852

Email

通信地址:群英科技园3号楼2

北京华控技术有限责任公司

邮政编码: 100085