using System;
using System.Collections.Generic;
using ProjectBase.Data.Logs;
using SIMDP.Model;
using System.Timers;
using OPCAutomation;
using System.Reflection;
namespace SIMDP.Device
{
public class PlcOpcDA : AbstractBaseDevice
{
#region 数据定义
///
/// OPCServer Object
///
OPCServer KepServer;
///
/// OPCGroup Object
///
OPCGroup KepGroupAll;
///
/// OPCGroup Object
///
OPCGroup KepGroupSubscribe;
///
/// OPCItems Object
/// 客户端句柄
///
int itmHandleClient = 1234;
///
/// OPC点表
///
List opcPointList;
///
/// 数据节点字典 key-变量名称, value-节点信息
///
protected Dictionary allPoints = new Dictionary();
///
/// 监控节点列表
///
protected Dictionary monitorPoints = new Dictionary();
#endregion
#region TYPE定义
public class OpcDataPointInfo
{
// 节点配置信息
public MoDataPoint mo;
public OPCItem item;
public object value = null;
public MethodInfo proc = null;
public OpcDataPointInfo(MoDataPoint _mo, OPCItem _item)
{
mo = _mo; item = _item;
}
}
#endregion
#region 接口实现
public override void Start(MoPlcInfo _plcInfo, List _dataPoints)
{
KepServer = new OPCServer();
plcInfo = _plcInfo;
opcPointList = _dataPoints;
// PLC未连接状态
SetRedisPlcDisConnect();
// 初始化自定义函数
actionStart();
// 启动时尝试连接一次设备
Connect();
// 启动定时器
timer.Interval = 1000;
timerStopped = false;
timer.Start();
}
public override bool isConnected()
{
return (KepServer.ServerState == (int)OPCServerState.OPCRunning);
}
protected override bool Connect()
{
KepServer.Connect(plcInfo.LinkConfig);
if (KepServer.ServerState == (int)OPCServerState.OPCRunning)
{
LogHelper.log.Info("已连接到OPC:" + KepServer.ServerName);
if (CreateGroup())
SetRedisPlcConnected();
else
KepServer.Disconnect();
}
else //这里你可以根据返回的状态来自定义显示信息,请查看自动化接口API文档
{
LogHelper.log.Warn("未能连接到OPC,状态:" + KepServer.ServerState.ToString());
}
return isConnected();
}
protected override void Disconnect()
{
if (KepServer != null)
KepServer.Disconnect();
SetRedisPlcDisConnect();
}
///
/// 创建组
///
public bool CreateGroup()
{
try
{
OPCGroups KepGroups = ((IOPCAutoServer)KepServer).OPCGroups;
KepGroups.DefaultGroupDeadband = 0;
KepGroups.DefaultGroupIsActive = true;
KepGroups.DefaultGroupUpdateRate = 500;
KepGroupAll = KepGroups.Add("SIMDPOPCGROUP"); // 所有节点组(可读写)
KepGroupAll.IsSubscribed = false;
KepGroupSubscribe = KepGroups.Add("SIMDPSUBSCRIBE"); // 监控节点组(变更订阅)
KepGroupSubscribe.IsSubscribed = true;
// 添加节点到OPCGROUP
allPoints.Clear();
monitorPoints.Clear();
Type t = this.GetType();
OPCItems KepItems = KepGroupAll.OPCItems;
OPCItems KepItemsSubscribe = KepGroupSubscribe.OPCItems;
foreach (var mo in opcPointList)
{
OPCItem KepItem = KepItems.AddItem(mo.DataPointSource, itmHandleClient);
OpcDataPointInfo point = new OpcDataPointInfo(mo, KepItem);
allPoints.Add(mo.DataPointName, point);
//if (BLLFactory.Instance.IsSignalGroupById(mo.DataPointGroupId))
// 不再按照信号组类型区分是否为监控节点,只按照是否有执行逻辑
if (mo.DataProc.Trim() != "")
{
OPCItem monitorItem = KepItemsSubscribe.AddItem(mo.DataPointSource, itmHandleClient);
OpcDataPointInfo monitorPoint = new OpcDataPointInfo(mo, monitorItem);
monitorPoint.proc = t.GetMethod(mo.DataProc);
monitorPoints.Add(itmHandleClient, monitorPoint);
}
itmHandleClient++;
}
KepGroupSubscribe.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange);
}
catch (Exception err)
{
LogHelper.log.Error("创建组出现错误:" + err.Message);
return false;
}
return true;
}
#endregion
#region 读写操作
///
/// 每当项数据有变化时执行的事件
///
/// 处理ID
/// 项个数
/// 项客户端句柄
/// TAG值
/// 品质
/// 时间戳
void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
{
for (int i = 1; i <= NumItems; i++)
{
object value = ItemValues.GetValue(i);
if (value == null)
continue;
int iHandle = (int)ClientHandles.GetValue(i);
OpcDataPointInfo point;
if (!monitorPoints.TryGetValue(iHandle, out point))
continue;
// 处理信号
UpdataRedisDataPoint(point.mo, value.ToString(), true);
if (point.proc != null)
point.proc.Invoke(this, new object[] { value });
}
}
///
/// 写入OPC变量
///
public bool Write(string dataPointName, object value)
{
OpcDataPointInfo pointInfo;
if (allPoints.TryGetValue(dataPointName, out pointInfo))
{
pointInfo.item.Write(value);
UpdataRedisDataPoint(pointInfo.mo, value.ToString(), true);
return true;
}
else
{
LogHelper.log.Error("写入OPC变量错误,未定义变量名:" + dataPointName);
return false;
}
}
///
/// 读取OPC变量
///
public bool Read(string dataPointName, out object value)
{
OpcDataPointInfo pointInfo;
if (allPoints.TryGetValue(dataPointName, out pointInfo))
{
object quality;
object timestamp;
pointInfo.item.Read((short)OPCDataSource.OPCDevice, out value, out quality, out timestamp);
UpdataRedisDataPoint(pointInfo.mo, value.ToString(), true);
return true;
}
else
{
LogHelper.log.Error("读取OPC变量错误,未定义变量名:" + dataPointName);
value = null;
return false;
}
}
#endregion
}
}