基于OPC协议的上位机PLC通讯 (一)

本小妞迷上赌 提交于 2019-12-10 07:19:26

    OPC技术是通常是用于PLC和上位机通讯的一个基于COM的一个通讯组件。比如某个项目是用西门子系列的PLC控制的自动化系统通过西门子的中间件通常会安装S7-200 PC Access或者SimaticNet的OPC服务端软件。这两个软件的目的就是在上位机的系统中搭建了一个OPC Server并提供访问可以编程实现遵循OPC技术使上位机与PLC通讯的功能。
    此外,需要强调一点,OPC并不是西门子的技术,它是一个标准,凡是遵循OPC技术的PLC都能共通过其标准与下位机通讯 。

    

 

几个关于OPC的概念:
    同步读:在调用OPC的接口函数时实时的将数据(组)通过出口参数传出
    同步写:在调用OPC的接口函数时实时的将数据写入寄存器
    异步读:调用OPC接口不会直接写入PLC寄存器,而是在注册的回调函数中拿到数据的相关信息
    异步写:也是在回调函数中将数据写入

组的概念:
    组中可以包含项,是多个项的一个集合
    组是和OPC提供的IO接口绑定的,OPC的IO接口是用于读写数据

项的概念:
    项其实就是对于了PLC上的对应地址,每种OPC服务器根据厂商不同定义的格式不同
 

关于封装的类

情况说明(这个类是本人在开发上位机软件与西门子S200系列PLC通信是所编写的 OPC服务器是SimaticNet)

几个疑惑点说明:

OPC服务器提供了几个接口的头文件需要在项目中添加

需要加到工程中的文件:

    opc.h    

    Pre_OPC.h

    Pre_OPC.cpp

以下几个文件不用添加到工程中但需要放在工作目录下

opcerror.h

opcda_i.c

opcda.h

opccomn_i.c

opccomn.h

 

相关文件OPC实现文件(c++)

 

封装的OPC 操作类

#ifndef OPCRES_H_
#define OPCRES_H_

#include "Pre_OPC.h"

#define    LOCALE_ID 0x409// Code 0x409 = ENGLISH
#define    ASYNC    0x01
#define    SYNC    0x10

class OPCRes{
public:
    OPCRes(int SyncItemNum,int AsyncItemNum,IOPCServer *pIOPCServer,HWND hWnd);
    ~OPCRes();
    void UninitRes();
    void OPC_AddGroup(LPCWSTR SyncGroupName,LPCWSTR AsyncGroupName);
    void OPC_AddItem(BOOL IsActive);
    void OPC_SetItem(DWORD flag,int Order,LPWSTR in_ID,CString Name);
    void OPC_ReadItem(DWORD flag);
    int  OPC_ReadItem(DWORD flag,CString Name);
    int  OPC_WriteItem(DWORD flag,int Order,int in_Value);
    void OPC_Subscribe(BOOL IsActiveCheck); 
    DWORD  GetAsyncCount();
    static void InitCOM(IOPCServer* &pIOPCServer,LPWSTR CLSID_ID);//传递IOPCServer指针类型的引用将外部声明的变量传进来
    static void UninitCOM(IOPCServer* &pIOPCServer);
    
private:

    OPCHANDLE              m_GrpSrvHandle;
    IOPCServer            *m_pIOPCServer;
    IOPCSyncIO            *m_pIOPCSyncIO_S;//用于同步访问数据项的同步读写
    IOPCSyncIO            *m_pIOPCSyncIO_A;//用于异步访问数据项的同步写入
    IOPCAsyncIO2          *m_pIOPCAsyncIO2;//用于异步访问数据项的异步读取
    IOPCGroupStateMgt     *m_pIOPCGroupStateMgt;

    IOPCItemMgt           *m_pIOPCItemMgt[2];    //数据项状态指针1异步0同步

    OPCITEMRESULT         *m_pAsyncItemResult;//异步数据项返回信息
    OPCITEMDEF            *m_AsyncItem;        //异步数据项指针
    CString               *m_AsyncItemName;    //异步数据项的指定名字
    HRESULT               *m_pAsyncErrors;    //异步数据错误信息
    DWORD                  m_AsyncItemCount;    //异步数据项的个数

    OPCITEMRESULT         *m_pSyncItemResult;    //同步数据项返回信息
    OPCITEMDEF            *m_SyncItem;        //同步数据项指针
    CString               *m_SyncItemName;    //同步数据项的指定名字
    HRESULT               *m_pSyncErrors;        //同步数据错误信息
    DWORD                  m_SyncItemCount;    //同步数据项的个数
    
    DWORD    m_flag;        //标记当前对象存在那种类型的数据项
    DWORD    m_dwAdvise;    //用于OPC Server返回的回调接口标识
    
public:    
    BOOL     m_ActiveCheck;
    
    int            *m_ReadVal_A;    //存放异步数据项的值
    CString        *m_ReadQu_A;    //存放异步数据项的品质标签
    CString        *m_ReadTs_A;    //存放异步数据项的时间戳

    int            *m_ReadVal_S;    //存放同步数据项的值
    CString        *m_ReadQu_S;    //存放同步数据项的品质标签
    CString        *m_ReadTs_S;    //存放同步数据项的时间戳
};


#endif //OPCRES_H_

 

 

实现

#include "stdafx.h"
#include "callback.h"
#include "OPCRes.h"

CComModule _Module;//必须定义此全局变量否则无法使用COM组件

/*****************************************************
函数名称:构造函数
参数说明:    
in 1、指定同步组的数据项个数 
in 2、指定异步组的数据项个数
in 3、传进窗口类定义的OPC服务接口指针
******************************************************/
OPCRes::OPCRes(int SyncNum,int AsyncNum,IOPCServer *pIOPCServer)
    :m_SyncItemCount(SyncNum),m_AsyncItemCount(AsyncNum),m_pIOPCServer(pIOPCServer),m_ActiveCheck(FALSE),m_flag(0x00)
{    
    if(!(AsyncNum+SyncNum))
    {
        AfxMessageBox("必须设置监控的数据项",MB_ICONERROR);
        ExitProcess(0);
    }
    if( SyncNum>0 )
    {
        m_flag|=SYNC;
        m_SyncItem=new OPCITEMDEF[SyncNum];//同步的数据项数组
        m_SyncItemName=new CString[SyncNum];

        m_ReadVal_S=new int[SyncNum];
        m_ReadQu_S=new CString[SyncNum];
        m_ReadTs_S=new CString[SyncNum];

    }
    if( AsyncNum>0 )
    {
        m_flag|=ASYNC;
        m_AsyncItem=new OPCITEMDEF[AsyncNum];//异步的数据项数组
        m_AsyncItemName=new CString[AsyncNum];

        m_ReadVal_A=new int[AsyncNum];
        m_ReadQu_A=new CString[AsyncNum];
        m_ReadTs_A=new CString[AsyncNum];

    }
    m_pAsyncItemResult = NULL;
    m_pSyncItemResult = NULL;
}

/*****************************************************
函数名称:析构函数
说明:    释放OPC资源
******************************************************/
OPCRes::~OPCRes()
{
    if( (m_flag&SYNC) == SYNC)
    {
        delete[] m_SyncItem;
        delete[] m_ReadVal_S;
        delete[] m_ReadQu_S;
        delete[] m_ReadTs_S;
        delete[] m_SyncItemName;
    }
    if( (m_flag&ASYNC) == ASYNC)
    {
        delete[] m_AsyncItem;
        delete[] m_ReadVal_A;
        delete[] m_ReadQu_A;
        delete[] m_ReadTs_A;
        delete[] m_AsyncItemName;
    }
}
/*****************************************************
函数名称:增加数据组
参数说明:    
in 1、指定同步组名 
in 2、指定异步组名
返回值:        无返回值
情况说明:    每个对象各有一个同步组一个异步组
******************************************************/
void OPCRes::OPC_AddGroup(LPCWSTR SyncGroupName,LPCWSTR AsyncGroupName)
{
    HRESULT     r1;                //接收AddGroup函数的返回值用于判断
    long        TimeBias = 0;        //in     与标准时间的校正值
    float       PercentDeadband = 0.0;    //in     要舍弃的数据
    DWORD       RevisedUpdateRate;        //out     服务器的数据刷新率
    CString     szErrorText;        //记录输出信息

    //创建同步的数据组
    if( (m_flag & SYNC) == SYNC)
    {
        //添加组对象并查询IOPCItemMgt接口
        r1=m_pIOPCServer->AddGroup(SyncGroupName,FALSE,500,1,&TimeBias,&PercentDeadband,LOCALE_ID,\
            &m_GrpSrvHandle,&RevisedUpdateRate,IID_IOPCItemMgt,(LPUNKNOWN*)&m_pIOPCItemMgt[0]);
        if(r1 == OPC_S_UNSUPPORTEDRATE)
        {
            szErrorText.Format ("同步数据组的实际刷新率为%d,与请求值不同",RevisedUpdateRate );
            AfxMessageBox (szErrorText);
        }
        else if (FAILED(r1))
        {    
            AfxMessageBox("无法创建同步数据组到服务器", MB_OK+MB_ICONERROR);
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
    }
    //创建异步的数据组
    if( (m_flag & ASYNC) == ASYNC)
    {
        r1=m_pIOPCServer->AddGroup(AsyncGroupName,FALSE,500,1,&TimeBias,&PercentDeadband,LOCALE_ID,\
            &m_GrpSrvHandle,&RevisedUpdateRate,IID_IOPCItemMgt,(LPUNKNOWN*)&m_pIOPCItemMgt[1]);
        if (r1 == OPC_S_UNSUPPORTEDRATE)
        {
            szErrorText.Format ("异步数据组的实际刷新率为%d,与请求值不同",RevisedUpdateRate );
            AfxMessageBox (szErrorText);
        }
        else if (FAILED(r1))
        {    AfxMessageBox("无法创建异步数据组到服务器", MB_OK+MB_ICONERROR);
        m_pIOPCServer->Release();
        m_pIOPCServer = NULL;
        CoUninitialize();
        return;
        }
    }

} 
/*****************************************************
函数名称:设置数据项
参数说明:    
in 1、指定设置同步/异步类型 
in 2、指定要设置的数据项序号(数组序)
in 3、指定数据项的ID(例如:L"S7:[S7 connection_1]DB1,W4326")
in 4、指定数据项的名称(同数据项的序号对应)
返回值:        无
情况说明:    通过参数设置每个数据项的ID和名字
******************************************************/
void OPCRes::OPC_SetItem(DWORD flag,int Order,LPWSTR in_ID,CString in_Name)
{
    if(SYNC == flag)
    {
        m_SyncItem[Order].szItemID=in_ID;
        m_SyncItemName[Order]=in_Name;
    }
    else if(ASYNC == flag)
    {
        m_AsyncItem[Order].szItemID=in_ID;
        m_AsyncItemName[Order]=in_Name;
    }
    else
    {
        AfxMessageBox("指定标记错误",MB_ICONERROR);
    }
}
/*****************************************************
函数名称:添加数据项
参数说明:    无
返回值:        无返回值
情况说明:    将设置好的数据项添加到组中
******************************************************/
void OPCRes::OPC_AddItem(BOOL IsActive)
{
    HRESULT        r1;            //接收AddGroup函数的返回值用于判断
    LPWSTR        *ErrorStr;    //out 存放返回的错误信息字符串
    DWORD        i;            //循环控制

    if( (m_flag & SYNC)==SYNC)
    {
        for(i=0;i<m_SyncItemCount;i++)
        {
            m_SyncItem[i].szAccessPath= L"";        //OPC服务器存取路径
            m_SyncItem[i].bActive= TRUE;            //活动状态
            m_SyncItem[i].hClient= i;                //操作句柄(主要用于异步项的回调)
            m_SyncItem[i].dwBlobSize= 0;            //pBlob大小
            m_SyncItem[i].pBlob= NULL;                //二进制指针
            m_SyncItem[i].vtRequestedDataType = 2;    //数据类型(2:int型)
        }
        CString    szOut="";//用来输出提示信息
        ErrorStr=new LPWSTR[m_SyncItemCount];
        r1 = m_pIOPCItemMgt[0]->AddItems(m_SyncItemCount,m_SyncItem,&m_pSyncItemResult,&m_pSyncErrors);
        if ( (r1 != S_OK) && (r1 != S_FALSE) )
        {
            AfxMessageBox("同步数据项添加失败!",  MB_OK+MB_ICONERROR);
            m_pIOPCItemMgt[0]->Release();
            m_pIOPCItemMgt[0] = NULL;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
        else
        {
            for(i=0;i<m_SyncItemCount;i++)
            {
                m_pIOPCServer->GetErrorString(m_pSyncErrors[i], LOCALE_ID, &ErrorStr[i]);//获取错误信息
            }

            CString *tempInfo;//存放每一个数据项的提示信息
            tempInfo=new CString[m_SyncItemCount];
            for(i=0;i<m_SyncItemCount;i++)
            {
                tempInfo[i].Format("Sync Item%d :%ls\n",i,ErrorStr[i]);
                szOut+=tempInfo[i];//把每一项的提示信息组合到输出提示字符串中
                CoTaskMemFree(ErrorStr[i]);
            }
            AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);
            delete[] tempInfo;
        }
        
        //检查数据项的读写性
        for(i=0;i<m_SyncItemCount;i++)
        {
            if (m_pSyncItemResult[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE))
            {
                szOut.Format("同步数据项%d不可读写!\n",i);
                AfxMessageBox(szOut, MB_OK+MB_ICONEXCLAMATION);
            }
        }
        
        //查询同步IO接口
        r1 = m_pIOPCItemMgt[0]->QueryInterface(IID_IOPCSyncIO,(void**)&m_pIOPCSyncIO_S);
        if (r1 < 0)
        {
            AfxMessageBox("同步接口IOPCSyncIO未找到!", MB_OK+MB_ICONERROR);
            CoTaskMemFree(m_pAsyncItemResult);
            m_pIOPCItemMgt[0]->Release();
            m_pIOPCItemMgt[0] = 0;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
    }

    //添加异步数据项
    if( (m_flag & ASYNC) == ASYNC)
    {
        for(i=0;i<m_AsyncItemCount;i++)
        {
            m_AsyncItem[i].szAccessPath= L"";
            m_AsyncItem[i].bActive= TRUE;
            m_AsyncItem[i].hClient= i;//操作句柄(项的序号),在异步回调函数中和参数phClientItems[?]对应
            m_AsyncItem[i].dwBlobSize= 0;
            m_AsyncItem[i].pBlob= NULL;
            m_AsyncItem[i].vtRequestedDataType = 2;
        }
        CString    szOut="";
        ErrorStr=new LPWSTR[m_AsyncItemCount];
        r1 = m_pIOPCItemMgt[1]->AddItems(m_AsyncItemCount,m_AsyncItem,&m_pAsyncItemResult,&m_pAsyncErrors);
        if ( (r1 != S_OK) && (r1 != S_FALSE) )
        {
            AfxMessageBox("异步数据项添加失败!",  MB_OK+MB_ICONERROR);
            m_pIOPCItemMgt[1]->Release();
            m_pIOPCItemMgt[1] = NULL;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
        else
        {
            for(i=0;i<m_AsyncItemCount;i++)
            {
                m_pIOPCServer->GetErrorString(m_pAsyncErrors[i], LOCALE_ID, &ErrorStr[i]);//获取错误信息
            }
            CString *tempInfo;
            tempInfo=new CString[m_AsyncItemCount];
            for(i=0;i<m_AsyncItemCount;i++)
            {
                tempInfo[i].Format("Async Item%d :%ls\n",i,ErrorStr[i]);
                szOut+=tempInfo[i];
                CoTaskMemFree(ErrorStr[i]);
            }
            AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);
            delete[] tempInfo;
        }
        
        //检查数据项的读写性
        for(i=0;i<m_AsyncItemCount;i++)
        {
            if (m_pAsyncItemResult[i].dwAccessRights != (OPC_READABLE + OPC_WRITEABLE))
            {
                szOut.Format("异步数据项%d不可读写!\n",i);
                AfxMessageBox(szOut, MB_OK+MB_ICONEXCLAMATION);
            }
        }
        
        //为了异步组的对象可以同步写入所以也要查询同步接口
        r1 = m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCSyncIO,(void**)&m_pIOPCSyncIO_A);
        if (r1 < 0)
        {
            AfxMessageBox("同步接口IOPCSyncIO未找到!", MB_OK+MB_ICONERROR);
            CoTaskMemFree(m_pAsyncItemResult);
            m_pIOPCItemMgt[1]->Release();
            m_pIOPCItemMgt[1] = 0;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
        
        //获得GroupStateMgt组状态接口
        r1=m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCGroupStateMgt, (void**)&m_pIOPCGroupStateMgt);
        if (r1 != S_OK)
        {
            AfxMessageBox("组状态接口IOPCGroupStateMgt未找到!", MB_OK+MB_ICONERROR);
            CoTaskMemFree(m_pAsyncItemResult);
            m_pIOPCItemMgt[1]->Release();
            m_pIOPCItemMgt[1]= 0;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
        
        //查询组对象异步接口
        r1 = m_pIOPCItemMgt[1]->QueryInterface(IID_IOPCAsyncIO2,(void**)&m_pIOPCAsyncIO2);
        if (r1 < 0)
        {
            AfxMessageBox("异步接口IOPCAsyncIO未找到!", MB_OK+MB_ICONERROR);
            CoTaskMemFree(m_pAsyncItemResult);
            m_pIOPCItemMgt[1]->Release();
            m_pIOPCItemMgt[1] = 0;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }

        // Activate Group according to Checkbox
        if(IsActive)//激活订阅
        {
            OPC_Subscribe(IsActive);
        }
        // Establish Callback for all Async operations     建立异步回调
        CComObject<COPCDataCallback>* pCOPCDataCallback;// Pointer to Callback Object

        // Create Instance of Callback Object using an ATL template 通过ATL模板创建回调对象的实例
        CComObject<COPCDataCallback>::CreateInstance(&pCOPCDataCallback);

        // pass pointer of this call Object to callback object
        pCOPCDataCallback->InformAbout(this);
        
        // query IUnknown interface of callback object, needed for the ATL Advise  查询IUnknown接口
        LPUNKNOWN pCbUnk;
        pCbUnk = pCOPCDataCallback->GetUnknown();

        // Creates a connection between the OPC Server's connection point and
        // this client's sink (the callback object).建立一个服务器的连接点与客户程序接收器之间的连接
        HRESULT hRes = AtlAdvise( m_pIOPCGroupStateMgt, pCbUnk,IID_IOPCDataCallback,&m_dwAdvise );
        if (hRes != S_OK)
        {
            AfxMessageBox("Advise failed!");
            CoTaskMemFree(m_pAsyncItemResult);
            m_pIOPCItemMgt[1]->Release();
            m_pIOPCItemMgt[1] = 0;
            m_GrpSrvHandle = 0;
            m_pIOPCServer->Release();
            m_pIOPCServer = NULL;
            CoUninitialize();
            return;
        }
    }

}
/*****************************************************
函数名称:读取数据项(全体读取版本)
参数说明:    in 1、指定读取的同步/异步组
返回值:        无返回值
情况说明:    此函数将读取指定的组中所有数据项的值
******************************************************/
//读取一组中所有寄存器的值
void OPCRes::OPC_ReadItem(DWORD flag)
{    
    HRESULT        r1;                    //接收ReadItem函数的返回值用于判断
    OPCHANDLE    *phServer;            //in     Item的的服务句柄
    DWORD        dwCancelID;            //out     异步读取返回服务器Cancel ID
    OPCITEMSTATE    *pItemValue;    //out     OPCITEMSTATE结构数组指针(返回同步读取的数据项信息) 
    HRESULT        *pErrors;            //out     返回的错误指针保存每一项的错误信息编号
    LPWSTR        *ErrorStr;            //用于保存错误编号对应的错误信息内容
    CString        szOut;                //存放输出信息
    DWORD         i;                    //控制循环

    if(flag==SYNC)
    {
        if( (m_flag&SYNC) != SYNC)
        {
            AfxMessageBox("同步组不存在!");
            return;
        }
        for(i=0;i<m_SyncItemCount;i++)
        {
            if (m_pSyncErrors[i] != S_OK)//判断Item的可用性
            {
                szOut.Format("OPC Async Item%d not available!",i);
                AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
                return;
            }
        }

        phServer = new OPCHANDLE[m_SyncItemCount];// Memory allocation really needed, if more than 1 item to be read

        for(i=0;i<m_SyncItemCount;i++)
        {
            phServer[i] = m_pSyncItemResult[i].hServer;// Select item by server handle, received at AddItem
        }

        r1 = m_pIOPCSyncIO_S->Read(OPC_DS_DEVICE,m_SyncItemCount,phServer,&pItemValue,&pErrors);

        delete[] phServer;

        ErrorStr=new LPWSTR[m_SyncItemCount];

        if(r1 == S_OK)
        {
            for (i = 0; i<m_SyncItemCount; i++)
            {
                m_ReadVal_S[i]=pItemValue[i].vDataValue.intVal;
                //GetQualityText(pItemValue[i].wQuality);
                m_ReadTs_S[i]=COleDateTime(pItemValue[i].ftTimeStamp).Format();
            }
        }
        if (r1 == S_FALSE)
        {
            for(i=0;i<m_SyncItemCount;i++)
            {
                m_pIOPCServer->GetErrorString(m_pSyncErrors[i], LOCALE_ID, &ErrorStr[i]);
            }

            CString *tempInfo;//存放输出提示信息
            tempInfo=new CString[m_SyncItemCount];
            for(i;i<m_SyncItemCount;i++)
            {
                tempInfo[i].Format("Async Item%d:%ls\n",i,ErrorStr[i]);
                AfxMessageBox(tempInfo[i], MB_OK+MB_ICONERROR);
                CoTaskMemFree(ErrorStr[i]);
            }
            delete[] tempInfo;
        }
        if (FAILED(r1))
        {
            szOut.Format ("Method call IOPCSyncIO::Read failed with error code %x", r1);
            AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
        }
        else
        {    // release [out] parameter in case of not failed
            CoTaskMemFree(pErrors);
            CoTaskMemFree(pItemValue);
        }
    }

    if( flag==ASYNC )
    {
        if( (m_flag&ASYNC) != ASYNC)
        {
            AfxMessageBox("异步组不存在!");
            return;
        }
        for(i=0;i<m_AsyncItemCount;i++)
        {
            if (m_pAsyncErrors[i] != S_OK) // Item not available
            {
                szOut.Format("OPC Async Item%d not available!",i);
                AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
                return;
            }
        }

        phServer = new OPCHANDLE[m_AsyncItemCount];// Memory allocation really needed, if more than 1 item to be read

        for(i=0;i<m_AsyncItemCount;i++)
        {
            phServer[i] = m_pAsyncItemResult[i].hServer;// Select item by server handle, received at AddItem
        }

        r1 = m_pIOPCAsyncIO2->Read(m_AsyncItemCount,phServer,10,&dwCancelID,&pErrors);

        delete[] phServer;

        ErrorStr=new LPWSTR[m_AsyncItemCount];
        if (r1 == S_FALSE)
        {
            for(i=0;i<m_AsyncItemCount;i++)
            {
                m_pIOPCServer->GetErrorString(m_pAsyncErrors[i], LOCALE_ID, &ErrorStr[i]);
            }

            CString *tempInfo;//存放输出提示信息
            tempInfo=new CString[m_AsyncItemCount];
            for(i;i<m_AsyncItemCount;i++)
            {
                tempInfo[i].Format("Async Item%d:%ls\n",i,ErrorStr[i]);
                AfxMessageBox(tempInfo[i], MB_OK+MB_ICONERROR);
                CoTaskMemFree(ErrorStr[i]);
            }
            delete[] tempInfo;
        }
        if (FAILED(r1))
        {
            szOut.Format ("Method call IOPCAsyncIO2::Read failed with error code %x", r1);
            AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
        }
        else
        {    // release [out] parameter in case of not failed
            CoTaskMemFree(pErrors);
        }
    }
}
/*****************************************************
函数名称:读取数据项(指定读取版本)
参数说明:    
in 1、指定读取的同步/异步组
in 2、指定读取的数据项名称
返回值:        若同步读取成功直接返回数据项的值,异步读取成功:0,失败:-1,指定名称未找到:-2
情况说明:    此函数将读取指定的组中数据项的值
******************************************************/
int OPCRes::OPC_ReadItem(DWORD flag,CString Name)
{        
    HRESULT            r1;                //接收ReadItem函数的返回值用于判断
    OPCHANDLE        *phServer;        //in     Item的的服务句柄
    DWORD            dwCancelID;        //out     异步读取返回服务器Cancel ID
    OPCITEMSTATE    *pItemValue;    //out     OPCITEMSTATE结构数组指针(返回同步读取的数据项信息) 
    HRESULT            *pErrors;        //out     返回的错误指针保存每一项的错误信息编号
    LPWSTR            ErrorStr;        //用于保存错误编号对应的错误信息内容
    CString            szOut;            //存放输出信息
    DWORD             i;                //控制循环

    if(flag==SYNC)
    {
        if( (m_flag&SYNC) != SYNC)
        {
            AfxMessageBox("同步组不存在!");
            return -1;
        }

        for(i=0;i<m_SyncItemCount;i++)
        {
            if (m_pSyncErrors[i] != S_OK) // Item not available
            {
                szOut.Format("OPC SyncItem[%d] not available!",i);
                AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
                return -1;
            }
        }

        for(i=0;i<m_SyncItemCount;i++)//遍历查找
        {
            if( Name==m_SyncItemName[i] )
            {
                phServer=new OPCHANDLE[1];
                phServer[0] = m_pSyncItemResult[i].hServer;
                //AfxMessageBox("找到指定寄存器");
                r1 = m_pIOPCSyncIO_S->Read(OPC_DS_DEVICE,1,phServer,&pItemValue,&pErrors);
                delete[] phServer;
                if(r1 == S_OK)
                {
                    return pItemValue[0].vDataValue.intVal;//数值
                    //GetQualityText(pItemValue[0].wQuality);//品质
                    //COleDateTime(pItemValue[0].ftTimeStamp).Format();//时间
                }
                if (r1 == S_FALSE)
                {
                    m_pIOPCServer->GetErrorString(m_pSyncErrors[0], LOCALE_ID, &ErrorStr);
                    CString tempInfo;//存放输出提示信息
                    tempInfo.Format("%s:%ls\n",m_SyncItemName[i],ErrorStr);
                    AfxMessageBox(tempInfo, MB_OK+MB_ICONERROR);
                    CoTaskMemFree(ErrorStr);
                    return -1;
                }

                if (FAILED(r1))
                {
                    szOut.Format ("Method call IOPCSyncIO::Read failed with error code %x", r1);
                    AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
                    return -1;
                }
                else
                {    // release [out] parameter in case of not failed
                    CoTaskMemFree(pErrors);
                    CoTaskMemFree(pItemValue);
                    return -1;
                }
                break;
            }

        }
        return -2;//未找到
    }
    /////////////////////////////////////////////////////////////////////
    else if( flag==ASYNC )
    {
        if( (m_flag&ASYNC) != ASYNC)
        {
            AfxMessageBox("异步组不存在!");
            return -1;
        }

        for(i=0;i<m_AsyncItemCount;i++)
        {
            if (m_pAsyncErrors[i] != S_OK) // Item not available
            {
                szOut.Format("OPC AsyncItem[%d] not available!",i);
                AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
                return -1;
            }
        }

        for(i=0;i<m_AsyncItemCount;i++)//遍历查找
        {
            if( Name==m_AsyncItemName[i])
            {
                phServer=new OPCHANDLE[1];
                phServer[0] = m_pAsyncItemResult[i].hServer;
                //AfxMessageBox("找到指定寄存器");
                r1 = m_pIOPCAsyncIO2->Read(1,phServer,10,&dwCancelID,&pErrors);
                delete[] phServer;
                if (r1 == S_FALSE)
                {
                    m_pIOPCServer->GetErrorString(m_pSyncErrors[0], LOCALE_ID, &ErrorStr);
                    CString tempInfo;//存放输出提示信息
                    tempInfo.Format("%s:%ls\n",m_AsyncItemName[i],ErrorStr);
                    AfxMessageBox(tempInfo, MB_OK+MB_ICONERROR);
                    CoTaskMemFree(ErrorStr);
                    return -1;
                }
                if (FAILED(r1))
                {
                    szOut.Format ("Method call IOPCAsyncIO2::Read failed with error code %x", r1);
                    AfxMessageBox(szOut, MB_OK+MB_ICONERROR);
                    return -1;
                }
                else
                {    // release [out] parameter in case of not failed
                    CoTaskMemFree(pErrors);
                    return 0;
                }
            }

        }
        return -2;//未找到
    }
    else
    {
        AfxMessageBox("寄存器标志有误");
        return -1;
    }

}
/*****************************************************
函数名称:同步写入数据项(指定读取版本)
参数说明:    
in 1、指定写入的同步/异步组
in 2、指定写入的数据项序号(数组序)
in 3、指定写入的数据项值
返回值:        若异步读取成功直接返回数据项的值,同步读取成功:0,失败:-1,指定名称未找到:-2
情况说明:    通过指定组的指定序号向寄存器写入一个值
******************************************************/
int OPCRes::OPC_WriteItem(DWORD Flag,int Order,int in_Value)
{
    OPCHANDLE        *phServer; 
    HRESULT            *pErrors; 
    VARIANT            values[1]; 
    HRESULT            r1; 
    LPWSTR            ErrorStr; 
    CString            szOut; 

    if(Flag==SYNC)
    {
        if( (m_flag&SYNC) != SYNC)
        {
            AfxMessageBox("同步组不存在!");
            return -1;
        }

        for(DWORD i=0;i<m_SyncItemCount;i++)
        {
            if (m_pSyncErrors[i] != S_OK)        //Item not available 
            {     
                szOut.Format("Sync Item%d not available!",i);
                AfxMessageBox(szOut,  MB_OK+MB_ICONERROR); 
                return -2; 
            }
        }

        //Select item by server handle received at AddItem 
        phServer = new OPCHANDLE[1]; 
        phServer[0] = m_pSyncItemResult[Order].hServer;

        //Set Variant with datatype and received value
        values[0].vt = VT_I2; 
        values[0].intVal = in_Value; 

        r1 = m_pIOPCSyncIO_S->Write(1, phServer, values, &pErrors); 
    }
    else if(Flag==ASYNC)
    {
        if( (m_flag&ASYNC) != ASYNC)
        {
            AfxMessageBox("异步组不存在!");
            return -1;
        }
        for(DWORD i=0;i<m_AsyncItemCount;i++)
        {
            if (m_pAsyncErrors[i] != S_OK)        //Item not available 
            {     
                szOut.Format("Async Item%d not available!",i);
                AfxMessageBox(szOut,  MB_OK+MB_ICONERROR); 
                return -2; 
            }
        }

        //    Select item by server handle received at AddItem 
        phServer = new OPCHANDLE[1]; 
        phServer[0] = m_pAsyncItemResult[Order].hServer;

        //    Set Variant with datatype and received value 
        values[0].vt = VT_I2; 
        values[0].intVal = in_Value; 

        r1 = m_pIOPCSyncIO_A->Write(1, phServer, values, &pErrors); 
    }

    delete[] phServer; 

    if(r1 == S_OK)//写入成功
    {
        ;
    }
    else if (r1 == S_FALSE)
    {
        m_pIOPCServer->GetErrorString(pErrors[0], LOCALE_ID, &ErrorStr); 
        szOut.Format("提示:%ls",ErrorStr);
        AfxMessageBox(szOut); 
        AfxMessageBox("请检查PLC连接");
        CoTaskMemFree(pErrors);    
        return -1;
    }

    if (FAILED(r1))
    { 
        szOut.Format("Method call IOPCSyncIO::Write failed with error code %x", r1); 
        AfxMessageBox(szOut, MB_OK+MB_ICONERROR); 
        return -1;
    } 
    else
    {
        CoTaskMemFree(pErrors);
        return 0;
    }
}

//激活订阅模式
void OPCRes::OPC_Subscribe(BOOL IsActiveCheck)
{
    DWORD dwRevUpdateRate;
    DWORD dwRequestedUpdateRate=50;
    FLOAT fPercentDeadband=50;
    m_ActiveCheck=IsActiveCheck;

    HRESULT  r1=m_pIOPCGroupStateMgt->SetState(&dwRequestedUpdateRate,&dwRevUpdateRate, &m_ActiveCheck, NULL,&fPercentDeadband,NULL,NULL);
    if (FAILED(r1))
    {
        AfxMessageBox("Set State failed", MB_OK+MB_ICONERROR);
        return;
    }
}


//释放资源
void OPCRes::UninitRes()
{
    HRESULT        r1;
    OPCHANDLE    *phServer;

    if( (m_flag & SYNC) == SYNC)
    {
        HRESULT        *pErrors;
        LPWSTR        ErrorStr;
        CString        szOut="";

        phServer = new OPCHANDLE[m_SyncItemCount];
        for(DWORD i=0;i<m_SyncItemCount;i++)
        {
            phServer[i] = m_pSyncItemResult[i].hServer;
        }

        r1 = m_pIOPCItemMgt[0]->RemoveItems(m_SyncItemCount, phServer, &pErrors);

        if ( (r1 != S_OK) && (r1 != S_FALSE) )
        {
            AfxMessageBox("Remove SyncItems failed!", MB_OK+MB_ICONERROR);
        }
        else
        {    
            CString tempInfo;
            for(DWORD i=0;i<m_SyncItemCount;i++)
            {
                m_pIOPCServer->GetErrorString(pErrors[i], LOCALE_ID, &ErrorStr);
                tempInfo.Format("%ls\n",ErrorStr);
                szOut+=tempInfo;
            }
            //AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);
            CoTaskMemFree(ErrorStr);
        }
        delete[] phServer;
        CoTaskMemFree(pErrors);
        CoTaskMemFree(m_pSyncItemResult);
        m_pSyncItemResult=NULL;
        CoTaskMemFree(m_pSyncErrors);
        m_pSyncErrors = NULL;
        
        if(m_SyncItemCount>0)//Release interface for sync calls
        {
            m_pIOPCSyncIO_S->Release();
            m_pIOPCSyncIO_S = NULL;
        }
        
        if(m_AsyncItemCount>0)//Release interface for Async calls
        {
            m_pIOPCSyncIO_A->Release();
            m_pIOPCSyncIO_A = NULL;
        }
        //Release ItemManagement interface
        m_pIOPCItemMgt[0]->Release();
        m_pIOPCItemMgt[0] = NULL;
    }

    if((m_flag & ASYNC) == ASYNC)
    {
        LPWSTR        ErrorStr;
        HRESULT        *pErrors;
        CString        szOut="";

        phServer = new OPCHANDLE[m_AsyncItemCount];
        for(DWORD i=0;i<m_AsyncItemCount;i++)
        {
            phServer[i] = m_pAsyncItemResult[i].hServer;
        }

        r1 = m_pIOPCItemMgt[1]->RemoveItems(m_AsyncItemCount, phServer, &pErrors);

        if ( (r1 != S_OK) && (r1 != S_FALSE) )
        {
            AfxMessageBox("Remove AsyncItems failed!", MB_OK+MB_ICONERROR);
        }
        else
        {
            CString tempInfo;
            for(DWORD i=0;i<m_AsyncItemCount;i++)
            {    
                m_pIOPCServer->GetErrorString(pErrors[i], LOCALE_ID, &ErrorStr);
                tempInfo.Format("%ls\n",ErrorStr);
                szOut+=tempInfo;
            }
            //AfxMessageBox(szOut, MB_OK+MB_ICONINFORMATION);
            CoTaskMemFree(ErrorStr);
        }
        delete[] phServer;
        CoTaskMemFree(pErrors);
        CoTaskMemFree(m_pAsyncItemResult);
        m_pAsyncItemResult=NULL;
        CoTaskMemFree(m_pAsyncErrors);
        m_pAsyncErrors = NULL;
        //Release interface for sync calls
        m_pIOPCAsyncIO2->Release();
        m_pIOPCAsyncIO2 = NULL;
        //Release ItemManagement interface
        m_pIOPCItemMgt[1]->Release();
        m_pIOPCItemMgt[1] = NULL;
    }

    //Remove Group
    r1=m_pIOPCServer->RemoveGroup(m_GrpSrvHandle, TRUE);
    if (r1 != S_OK)
    {
        AfxMessageBox("RemoveGroup failed!", MB_OK+MB_ICONERROR);
    }
    m_GrpSrvHandle = NULL;
}


DWORD OPCRes::GetAsyncCount()
{
    return m_AsyncItemCount;    
}



//初始化COM库,需要在创建类的窗口中通过静态函数调用
//西门子的OPC Server是L"OPC.SimaticNET"
void OPCRes::InitCOM(IOPCServer* &pIOPCServer,LPWSTR CLSID_ID)//传递一个IOPCServer*类型的引用即实参本身
{
    HRESULT     r1;
    CLSID       clsid;
    CString     szErrorText;

    // Initialize the COM library
    r1 = CoInitialize(NULL);
    if (r1 != S_OK)
    {
        if (r1 == S_FALSE)
        {   
            //AfxMessageBox("COM Library already initialized",MB_OK+MB_ICONEXCLAMATION);
        }
        else
        {
            szErrorText.Format("Initialisation of COM Library failed. ErrorCode= %4x", r1);
            AfxMessageBox(szErrorText, MB_OK+MB_ICONERROR);
            return;
        }
    }
    // Given a ProgID, this looks up the associated CLSID in the registry
    r1 = CLSIDFromProgID(CLSID_ID,&clsid);
    if (r1 != S_OK)
    {          
        AfxMessageBox("Retrival of CLSID failed", MB_OK+MB_ICONERROR);
        CoUninitialize();
        return;
    }
    // Create the OPC server object and querry for the IOPCServer interface of the object
    r1 = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER ,IID_IOPCServer,(void**)&pIOPCServer);
    if (r1 != S_OK)
    {          
        AfxMessageBox("Creation of IOPCServer-Object failed", MB_OK+MB_ICONERROR);
        pIOPCServer = NULL;
        CoUninitialize();
        return;
    }
}


//释放COM库
void OPCRes::UninitCOM(IOPCServer* &pIOPCServer)
{
    //Release OPC-Server
    pIOPCServer->Release();
    pIOPCServer = NULL;
    //Uninit COM
    CoUninitialize();
}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!