You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

310 lines
9.4 KiB
C#

1 year ago
using System;
using OPC;
using OPCDA;
using OPCDA.NET;
using System.Runtime.InteropServices;
namespace Mesnac.Basic
{
// 定义用于返回发生变化的项的值和其对应的客户句柄
public delegate void DataChange(READRESULT[] values, string[] itemsID);
/// <summary>
/// 自定义的结构
/// 用来保存读取到的数据(值,品质,时间戳)
/// </summary>
public struct READRESULT
{
public string readValue;
public string readQuality;
public string readTimeStamp;
}
public class OPCComm
{
OpcServer myOPCServer;//server object
SyncIOGroup readWriteGroup;//group object
ItemDef itemData;
BrowseTree itemTree;
READRESULT readRes;
//供回调函数使用
RefreshGroup asyncRefrGroup;
DataChangeEventHandler dch;
READRESULT[] dataChangeRes; //用来保存变量值发生变化时服务器的回调函数得到的变量数据
public READRESULT[] DataChangeRes
{
get { return dataChangeRes; }
set { dataChangeRes = value; }
}
public BrowseTree ItemTree
{
get { return itemTree; }
set { itemTree = value; }
}
public ItemDef ItemData
{
get { return itemData; }
set { itemData = value; }
}
internal READRESULT ReadRes
{
get { return readRes; }
set { readRes = value; }
}
DataChange dtChange;
public OPCComm(DataChange dataChange)
{
dtChange = dataChange;
}
#region 获得可访问的服务器名字列表
/// <summary>
/// 获得服务器名字列表
/// </summary>
/// <returns>返回包含服务器名字的字符串数组</returns>
public string[] GetSerList(string host)
{
OpcServerBrowser serList = new OpcServerBrowser(new OPC.Common.Host(host));
string[] serNames;
serList.GetServerList(out serNames);
return serNames;
}
#endregion
#region 浏览服务器地址空间
/// <summary>
/// 浏览服务器地址空间
/// </summary>
/// <returns>成功返回0 失败返回-1</returns>
public int GetItemList()
{
itemTree = new BrowseTree(myOPCServer);
int res = itemTree.CreateTree(); // Browse server from root
if (HRESULTS.Succeeded(res))
{
return 0;
}
return -1;
}
#endregion
#region 连接服务器
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="serName">服务器的名字</param>
/// <param name="serIP">服务器所在机器的IP</param>
/// <returns>成功返回0失败返回-1</returns>
public int Conn2Server(string serName, string serIP,int refresh)
{
int res;
try
{
myOPCServer = new OpcServer();
res = myOPCServer.Connect(serIP, serName);
if (HRESULTS.Failed(res))
{
myOPCServer = null;
return -1;
}
readWriteGroup = new SyncIOGroup(myOPCServer);
//供回调函数刷新变量值使用
dch = new DataChangeEventHandler(DataChangeHandler);
if (refresh<=0)
{
refresh = 1000;
}
asyncRefrGroup = new RefreshGroup(myOPCServer, dch, refresh);
}
catch
{
myOPCServer = null;
return -1;
}
return 0;
}
#endregion
#region 添加项
/// <summary>
/// 获得变量对象
/// </summary>
/// <param name="itemId">变量ID</param>
/// <returns>成功返回0 失败返回-1</returns>
int AddItem(string itemId)
{
itemData = readWriteGroup.Item(itemId);
if (itemData == null)
{
readWriteGroup.Add(itemId);
itemData = readWriteGroup.Item(itemId);
if (itemData == null)
{
return -1;
}
}
return 0;
}
#endregion
#region 读取一个变量
/// <summary>
/// 从服务器上读取数据,读取的数据保存在READRESULT结构中
/// </summary>
/// <param name="num">变量ID</param>
/// <returns>成功返回0 失败返回-1</returns>
public int Read(string itemId)
{
if (AddItem(itemId) == 0)
{
OPCItemState Rslt;
OPCDATASOURCE dsrc = OPCDATASOURCE.OPC_DS_DEVICE;
int rtc = readWriteGroup.Read(dsrc, itemData, out Rslt);
if (HRESULTS.Succeeded(rtc)) // read from OPC server successful
{
if (Rslt != null)
{
if (HRESULTS.Succeeded(Rslt.Error)) // item read successful
{
readRes.readValue = Rslt.DataValue.ToString();
readRes.readQuality = readWriteGroup.GetQualityString(Rslt.Quality);
DateTime dt = DateTime.FromFileTime(Rslt.TimeStamp);
readRes.readTimeStamp = dt.ToString();
return 0;
}
return -1;
}
return -1;
}
else
{
return -1;
}
}
return -1;
}
#endregion
#region 修改一个变量
/// <summary>
/// 修改一个变量
/// </summary>
/// <param name="itemId">变量ID</param>
/// <param name="value">变量的值</param>
/// <returns>返回写操作结果的字符串</returns>
public string Write(string itemId, object value)
{
if (AddItem(itemId) == 0)
{
int res = readWriteGroup.Write(itemData, value);
return readWriteGroup.GetErrorString(res);
}
return null;
}
#endregion
#region 向RefreshGroup组中添加一个变量
/// <summary>
/// 向RefreshGroup组中添加一个变量
/// </summary>
/// <param name="itemId">变量ID</param>
/// <returns>成功返回0失败返回-1</returns>
public int Add2RefrGroup2(string itemId,ref VarEnum DataType)
{
DataType = VarEnum.VT_EMPTY;
if (AddItem(itemId) == 0)
{
DataType = itemData.OpcIInfo.CanonicalDataType;
int res = asyncRefrGroup.Add(itemData.OpcIDef.ItemID);
if (HRESULTS.Failed(res))
{
return -1;
}
return 0;
}
return -1;
}
public int Add2RefrGroup(string itemId)
{
if (AddItem(itemId) == 0)
{
int res = asyncRefrGroup.Add(itemData.OpcIDef.ItemID);
if (HRESULTS.Failed(res))
{
return -1;
}
return 0;
}
return -1;
}
#endregion
#region 断开同服务器的连接
/// <summary>
/// 断开同服务器的连接
/// </summary>
/// <returns>成功返回0失败返回-1</returns>
public void DisConn()
{
if (myOPCServer != null)
{
asyncRefrGroup.Dispose();
readWriteGroup.Dispose();
myOPCServer.Disconnect();
myOPCServer = null;
}
}
#endregion
#region 回调函数
/// <summary>
/// 回调函数当RefreshGroup组里的数据发生变化时由服务器自动调用该函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void DataChangeHandler(object sender, DataChangeEventArgs e)
{
int count = e.sts.Length;
string[] itemsID = new string[count];
dataChangeRes = new READRESULT[count];
for (int i = 0; i < count; ++i)
{
int hnd = e.sts[i].HandleClient;
ItemDef item = asyncRefrGroup.FindClientHandle(hnd);
if (item != null)
{
//保存变量的ItemID
itemsID[i] = item.OpcIDef.ItemID;
}
object val = e.sts[i].DataValue;
string qt = asyncRefrGroup.GetQualityString(e.sts[i].Quality);
DateTime dt = DateTime.FromFileTime(e.sts[i].TimeStamp);
//将变量的值保存在READRESULT结构中
dataChangeRes[i].readValue = val.ToString();
dataChangeRes[i].readQuality = qt;
dataChangeRes[i].readTimeStamp = dt.ToString();
}
dtChange(dataChangeRes, itemsID);
}
#endregion
}
}