You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1807 lines
100 KiB
1807 lines
100 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using Opc.Ua;
|
|
using Opc.Ua.Client;
|
|
|
|
using System.Data;
|
|
using DBFactory;
|
|
using CommonLib;
|
|
using Siemens.OpcUA;
|
|
using CommLayerFactory;
|
|
using ICommLayer;
|
|
using System.Collections.Concurrent;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace OPCClient
|
|
{
|
|
public class WorkItem
|
|
{
|
|
public object Parameter1 { get; set; }
|
|
public DataValue Parameter2 { get; set; }
|
|
// 可以添加更多的属性和参数
|
|
|
|
public WorkItem(object param1, DataValue param2)
|
|
{
|
|
Parameter1 = param1;
|
|
Parameter2 = param2;
|
|
}
|
|
}
|
|
public static class CCommonOPCClient
|
|
{
|
|
static Model.MDevice _device = null;
|
|
private static ushort S7NameSpace = 2;//20151120,默认值是32位系统的值2,64位系统的值是3
|
|
private static Model.MDevice devinfo;
|
|
private static Object thisLock = new Object();
|
|
static ISendDeviceOrder sdo;
|
|
static Model.MDevice modifypathdevinfo;
|
|
static Model.MDevice askDevinfo;
|
|
static StringBuilder[] wv = { new StringBuilder("2") };
|
|
static StringBuilder[] witemnames = { new StringBuilder("") };
|
|
|
|
/// <summary>
|
|
/// 一个周期内一个订阅组发送所有标签的个数
|
|
/// </summary>
|
|
static Dictionary<string, int> _opcSubsTagCount = new Dictionary<string, int>();
|
|
/// <summary>
|
|
/// 每个订阅组里对应设备发送标签名称集合
|
|
/// </summary>
|
|
static Dictionary<string, Dictionary<int, StringBuilder[]>> _opcItemNamesDicInfo = new Dictionary<string, Dictionary<int, StringBuilder[]>>();
|
|
/// <summary>
|
|
/// 每个订阅组里对应设备发送标签数值集合
|
|
/// </summary>
|
|
static Dictionary<string, Dictionary<int, StringBuilder[]>> _opcItemValuesDicInfo = new Dictionary<string, Dictionary<int, StringBuilder[]>>();
|
|
|
|
public static event RefreshMonitorEventHandler RefreshMonitor;
|
|
public static void OnRefreshMonitor(RefreshMonitorEventArgs e)
|
|
{
|
|
if (RefreshMonitor != null)
|
|
{
|
|
RefreshMonitor(e);
|
|
}
|
|
}
|
|
public static event CUpdateDBEventHandler DealSQLExe;
|
|
public static void OnDealSQLExe(object sender, CUpdateDBChangeEventArgs e)
|
|
{
|
|
DealSQLExe?.Invoke(sender, e);
|
|
}
|
|
public static event CUpdateDBEventHandler PublishDeviceState;
|
|
public static void OnPublishDeviceState(object sender,CUpdateDBChangeEventArgs e)
|
|
{
|
|
PublishDeviceState?.Invoke(sender, e);
|
|
}
|
|
public static DBOperator dbo =new DBOperator(); //20130510
|
|
|
|
//20110726
|
|
private static Dictionary<string, int> _connectCount = new Dictionary<string, int>();
|
|
//20110726
|
|
public static Dictionary<string, int> ConnectCount
|
|
{
|
|
get { return CCommonOPCClient._connectCount; }
|
|
set { CCommonOPCClient._connectCount = value; }
|
|
}
|
|
|
|
private static int[] _plcStates=null ;
|
|
|
|
public static int[] PlcStates
|
|
{
|
|
get { return CCommonOPCClient._plcStates; }
|
|
//set { CCommonOPCClient._plcStates = value; }
|
|
}
|
|
private static Server m_Server = null;
|
|
private static Siemens.OpcUA.Subscription m_Subscription;
|
|
public static BlockingCollection<WorkItem> buffer = new BlockingCollection<WorkItem>();
|
|
private static Task pollingTask = Task.Run(() => PollMethod());
|
|
/// <summary>
|
|
/// 20110309订阅的组内标签数据变化事件
|
|
/// </summary>
|
|
/// <param name="subscriptionHandle">客户端句柄</param>
|
|
/// <param name="requestHandle">请求句柄</param>
|
|
/// <param name="values">标签值数组</param>
|
|
public static void OnDataChange(object clientHandle, DataValue value)
|
|
{
|
|
buffer.Add(new WorkItem(clientHandle, value));
|
|
|
|
|
|
}
|
|
public static void kkkk()
|
|
{
|
|
if (buffer.Count > 0)
|
|
{
|
|
foreach (WorkItem item in buffer.GetConsumingEnumerable())
|
|
{
|
|
lock (thisLock)
|
|
{
|
|
//根据subscriptionHandle对应设备索引,依据设备种类(不同类型设备通讯数据帧不同)
|
|
//分别处理:完成,报警,光电开关,PLC发起的请求
|
|
int deviceindex = 0;
|
|
try
|
|
{
|
|
if (item.Parameter1.ToString().IndexOf("split") >= 0)
|
|
{
|
|
deviceindex = System.Convert.ToInt32(item.Parameter1.ToString().Substring(5));
|
|
}
|
|
else
|
|
{
|
|
deviceindex = System.Convert.ToInt32(item.Parameter1);
|
|
}
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(deviceindex);
|
|
if (StatusCode.IsNotGood(item.Parameter2.StatusCode))
|
|
{
|
|
if (devinfo == null)
|
|
{
|
|
OpcError = string.Format("设备索引{0}在数据库不存在!", item.Parameter1);
|
|
|
|
return;
|
|
}
|
|
|
|
//触发一个特殊事件提示PLC断开连接
|
|
if (ConnectCount.ContainsKey(devinfo.S7Connection) == false)//20110726
|
|
{
|
|
ConnectCount.Add(devinfo.S7Connection, 0);
|
|
}
|
|
|
|
OpcError = string.Format("{0}所在的PLC已经离线!订阅标签状态:" + item.Parameter2.StatusCode.ToString(), item.Parameter1);
|
|
if (ConnectCount[devinfo.S7Connection] > 3)//20150204
|
|
{
|
|
_opcError = "订阅返回数据时:OPC Server没连接到PLC:" + devinfo.S7Connection.ToString() + ",人工确认后进行【PLC初始化】";//20150204
|
|
return;
|
|
}
|
|
ConnectCount[devinfo.S7Connection]++;//20150204
|
|
return;
|
|
|
|
}
|
|
|
|
ConnectCount[devinfo.S7Connection] = 0;
|
|
if (item.Parameter1.ToString().IndexOf("split") >= 0)
|
|
{
|
|
Array arr = (Array)item.Parameter2.Value;
|
|
byte[] GDKG = null;
|
|
|
|
GDKG = new byte[arr.GetLength(0)];
|
|
Array.Copy(arr, GDKG, arr.GetLength(0));
|
|
#region 解析订阅返回光电开关数据
|
|
DealWithDeviceState(out string errText, deviceindex, GDKG, null);
|
|
#endregion
|
|
|
|
}
|
|
else
|
|
{
|
|
Array arr = (Array)item.Parameter2.Value;
|
|
byte[] itemnamevalue = new byte[arr.GetLength(0)];
|
|
Array.Copy(arr, itemnamevalue, arr.GetLength(0));
|
|
int head = 0;
|
|
head = itemnamevalue[0];//读写标志
|
|
|
|
#region 解析订阅返回状态数据,并发布主线程可订阅的事件
|
|
DealWithDeviceState(out string errText, deviceindex, null, itemnamevalue);
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{//20120420
|
|
OpcError = string.Format("OPC服务器订阅事件异常:{0},{1}", ex.Message, ex.StackTrace);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
static void PollMethod()
|
|
{
|
|
while (true) // 无限循环,模拟轮询
|
|
{
|
|
// 这里放置你的轮询逻辑
|
|
kkkk();
|
|
|
|
// 休眠一段时间,例如1秒
|
|
Thread.Sleep(1000);
|
|
}
|
|
}
|
|
static bool DealWithDeviceState(out string errtext, int deviceindex, byte[] splitbyteValue, byte[] devicestates)
|
|
{//deviceindex设备组代表的订阅,首先把设备组按照F_DBW2Address由小到大排序,拆分到具体每个设备
|
|
//20230811richard.liu周期内按S7连接批量发送,重构CControl.cs,CCommonOPCClient.cs\DealWithDeviceState;文件夹Communication、Common内通讯CSendDeviceOrder: ISendDeviceOrder相关文件
|
|
lock (thisLock)
|
|
{
|
|
|
|
|
|
_opcSubsTagCount.Clear();
|
|
_opcItemNamesDicInfo.Clear();
|
|
_opcItemValuesDicInfo.Clear();
|
|
Dictionary<int, StringBuilder> DeviceStateInfos=new Dictionary<int, StringBuilder>();
|
|
|
|
errtext = string.Empty;
|
|
|
|
DataView dvDevice = new DataView();//device表的设备信息
|
|
DataView dvPLCASK = new DataView();//PLCASK表数据不能更改
|
|
DataView dvbc = new DataView();//临时表可随意用
|
|
int devicebegin = 0; int DBW2Addressbegin = 0; string S7Connection = string.Empty;//int SplitBytebegin = 0;
|
|
int SplitByteLength = 0;
|
|
try
|
|
{
|
|
StringBuilder sql = new StringBuilder(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE f_controldevice='1' and (F_DeviceKindIndex !=33) AND (F_ReadSubscription = '{0}') AND (F_DBW2Address IS NOT NULL) ORDER BY F_DBW2Address", deviceindex));//20151120,增加字段是否需要服务端处理设备的订阅
|
|
dvDevice = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
if (dvDevice.Count > 0)
|
|
{//订阅组第一个设备,设备编码是订阅组ID
|
|
devicebegin = Convert.ToInt32(dvDevice[0]["F_DeviceIndex"]);
|
|
DBW2Addressbegin = Convert.ToInt32(dvDevice[0]["F_DBW2Address"]);
|
|
//SplitBytebegin = Convert.ToInt32(dvDevice[0]["F_SplitByte"]);
|
|
S7Connection = dvDevice[0]["F_S7Connection"].ToString();
|
|
//sql.Clear();
|
|
//sql.Append(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE (F_DeviceKindIndex =33) AND (F_ReadSubscription = '{0}') ORDER BY F_DBW2Address", deviceindex));
|
|
//dvPLCASK = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
//if (dvPLCASK.Count > 0)
|
|
//{
|
|
// SplitByteLength = Convert.ToInt32(dvPLCASK[0]["F_DBWGetLength"]);
|
|
//}
|
|
}
|
|
else
|
|
{//非订阅组第一个设备
|
|
sql = new StringBuilder(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE (F_DeviceIndex = '{0}') AND (F_DBW2Address IS NOT NULL) ORDER BY F_DBW2Address", deviceindex));
|
|
dvDevice = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
if (dvDevice.Count > 0)
|
|
{
|
|
devicebegin = Convert.ToInt32(dvDevice[0]["F_DeviceIndex"]);
|
|
DBW2Addressbegin = Convert.ToInt32(dvDevice[0]["F_DBW2Address"]);
|
|
//SplitBytebegin = Convert.ToInt32(dvDevice[0]["F_SplitByte"]);
|
|
S7Connection = dvDevice[0]["F_S7Connection"].ToString();
|
|
sql = new StringBuilder(string.Format("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_SplitByte,F_S7Connection FROM T_Base_Device WHERE (F_DeviceKindIndex =33) AND (F_ReadSubscription = '{0}') ORDER BY F_DBW2Address", deviceindex));
|
|
dvPLCASK = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
if (dvPLCASK.Count > 0)
|
|
{
|
|
SplitByteLength = Convert.ToInt32(dvPLCASK[0]["F_DBWGetLength"]);
|
|
}
|
|
}
|
|
else
|
|
{//20120420
|
|
RefreshMonitorEventArgs rmea = new RefreshMonitorEventArgs("tsStatus", string.Format("CCommonOPCClient.DealWithDeviceState时,订阅组:{0}对应的设备索引不存在!", deviceindex));
|
|
OnRefreshMonitor(rmea);
|
|
errtext = string.Format("CCommonOPCClient.DealWithDeviceState时,订阅组:{0}对应的设备索引不存在!", deviceindex);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#region 设备状态采集分解
|
|
int tempdb2addr = 0; StringBuilder sss = new StringBuilder(); StringBuilder barcode = new StringBuilder();
|
|
if (devicestates != null)
|
|
{
|
|
//遍历订阅内所有设备
|
|
for (int di = 0; di < dvDevice.Count; di++)
|
|
{
|
|
int devidx = Convert.ToInt32(dvDevice[di]["F_DeviceIndex"]);
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(devidx);
|
|
if (DeviceStateInfos.ContainsKey(devidx) == false)
|
|
{
|
|
DeviceStateInfos.Add(devidx, new StringBuilder(devidx.ToString() + "#"));
|
|
}
|
|
witemnames[0].Clear();
|
|
witemnames[0].Append(Model.CGeneralFunction.DBGet).Append(".").Append(Convert.ToString(devinfo.Dbw2Address + 0)).Append(",b");//20141201张磊发现误写为Dbw1Address
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
int taskindex = 0; int state = 0;
|
|
int xc = 0; int yc = 0;
|
|
int devkind = devinfo.DeviceKind;
|
|
//以下代码重新开发CStaticClass.MutiS7ConnReturns改为按照F_ReadSubscription
|
|
tempdb2addr = Convert.ToInt32(dvDevice[di]["F_DBW2Address"]) - DBW2Addressbegin;
|
|
if (3 < devinfo.Dbw2Getlength&&devkind!=5&& devkind != 13)
|
|
{
|
|
//state = devicestates[tempdb2addr + 1];
|
|
taskindex = (devicestates[tempdb2addr + 2] << 8) + devicestates[tempdb2addr + 3];
|
|
}
|
|
if (1 < devinfo.Dbw2Getlength&&devkind!=7)
|
|
{
|
|
state = devicestates[tempdb2addr + 1];
|
|
|
|
}
|
|
if (1 == devinfo.Dbw2Getlength )
|
|
{
|
|
state = devicestates[tempdb2addr];
|
|
|
|
}
|
|
if (devkind == 13 && devinfo.UnControl!="1")
|
|
{//richard.liu20230718鸿安环穿0-1是心跳单独订阅;2是可下任务状态0:不可下命令,1:可下命令
|
|
state = devicestates[tempdb2addr + 1] == 0 ? 1 : 0;//可下任务状态
|
|
taskindex = (devicestates[tempdb2addr + 2] << 8) + devicestates[tempdb2addr + 3];
|
|
}
|
|
|
|
#region 通用物流设备状态
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(devidx);
|
|
if (devinfo.RunState != 4)//20121203
|
|
{
|
|
string errText = string.Empty;
|
|
if (state >= 30)
|
|
{
|
|
#region 20160501故障信息变化,上一故障结束,新故障开始
|
|
Model.MError errs;
|
|
if (devinfo.ErrorCode != state && devinfo.ErrorCode >= 30)
|
|
{
|
|
if (taskindex == 0 || taskindex >= 30000)
|
|
{
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state));
|
|
}
|
|
#region 上一次报警或者故障时间分别统计记录
|
|
errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + devinfo.ErrorCode.ToString()));
|
|
if (errs != null)
|
|
{
|
|
DataView dverr = dbo.ExceSQL(string.Format("SELECT F_ManageTaskNo,F_DeviceIndex,F_ErrorIndex,F_DateTime FROM T_Base_Device_Error_Log where F_DeviceIndex={0} and F_ErrorIndex={1} order by F_DateTime desc", devidx, errs.ErrorIndex)).Tables[0].DefaultView;
|
|
if (dverr.Count > 0)
|
|
{//richard.liu20181212对报警记录更新最近一个的修复时间
|
|
sql.Remove(0, sql.Length);
|
|
sql.Append("UPDATE T_Base_Device_Error_Log SET F_FixDateTime ='").Append(DateTime.Now.ToString("u")).Append("' Where F_DeviceIndex=")
|
|
.Append(devidx).Append(" and F_ErrorIndex=").Append(errs.ErrorIndex).Append(" and F_ManageTaskNo=").Append(Convert.ToInt32(dverr[0]["F_ManageTaskNo"]));
|
|
//dbo.ExceSQL(sql.ToString());
|
|
StringBuilder[] dboArrary = new StringBuilder[1] { new StringBuilder("DBFactory") };
|
|
StringBuilder[] sqlArrary = new StringBuilder[1] { sql };
|
|
CUpdateDBChangeEventArgs exeSql = new CUpdateDBChangeEventArgs(dboArrary, sqlArrary);
|
|
OnDealSQLExe("OPCClient.CCommonOPCClient.OnDataChange", exeSql);
|
|
}
|
|
if (errs.IfAlarm == '1')
|
|
{
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0
|
|
//, 0, ccf.GetAlarmTimeSpan(devidx),errs.ErrorKind, 0, out errText);//统计上次报警
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='-' where F_DeviceIndex ={0}", devidx));
|
|
}
|
|
else
|
|
{
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0
|
|
//, ccf.GetErrorTimeSpan(devidx), 0,errs.ErrorKind, 0, out errText);//统计上次故障
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='-' where F_DeviceIndex ={0}", devidx));
|
|
}
|
|
}
|
|
#endregion
|
|
//新的报警或故障开始计时
|
|
errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + state.ToString()));
|
|
if (errs != null)
|
|
{
|
|
if (errs.IfAlarm == '1')
|
|
{
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19)));
|
|
//CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 0, 1,
|
|
// 0, 0, 0, 'O', 0, out errText);//richard.liu20181212报警数量增加1
|
|
}
|
|
else
|
|
{
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19)));
|
|
//CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 1, 0,
|
|
// 0, 0, 0, 'O', 0, out errText);//richard.liu20181212故障数量增加1
|
|
}
|
|
}
|
|
}
|
|
else if (devinfo.ErrorCode != state && devinfo.ErrorCode < 30)
|
|
{
|
|
if (taskindex == 0 || taskindex >= 30000)
|
|
{
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state));
|
|
}
|
|
//求上一次运行时间
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, ccf.GetConveyorRunTimeSpan(devidx)
|
|
// ,0,0,'O',0, out errText);//统计上次运行时间
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='-' where F_DeviceIndex ={0}", devidx));
|
|
//新的报警或故障开始计时
|
|
errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + state.ToString()));
|
|
if (errs != null)
|
|
{
|
|
if (errs.IfAlarm == '1')
|
|
{
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19)));
|
|
//CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 0, 1,
|
|
// 0, 0, 0, 'O', 0, out errText);//richard.liu20181212报警数量增加1
|
|
}
|
|
else
|
|
{
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19)));
|
|
//CStaticClass.UpdateDeviceOEE(devinfo.DeviceIndex, DateTime.Now.Date, 0, 1, 0,
|
|
// 0, 0, 0, 'O', 0, out errText);//richard.liu20181212故障数量增加1
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
devinfo.ErrorCode = state;
|
|
devinfo.RunState = 2;
|
|
}
|
|
else
|
|
{//0,1,2
|
|
#region 20160501上一故障结束,输送机任务变化:任务数增加1
|
|
//输送机状态变化:0->1开始运行;1->0运行结束,运行时间增加
|
|
if (devinfo.ErrorCode >= 30)
|
|
{
|
|
#region 如果上一次报警或者故障结束,清除时间,改为运行时间
|
|
Model.MError errs = Model.CGetInfo.GetErrorInfo(Convert.ToInt32(devkind.ToString() + devinfo.ErrorCode.ToString()));
|
|
if (errs != null)
|
|
{
|
|
DataView dverr = dbo.ExceSQL(string.Format("SELECT F_ManageTaskNo,F_DeviceIndex,F_ErrorIndex,F_DateTime FROM T_Base_Device_Error_Log where F_DeviceIndex={0} and F_ErrorIndex={1} order by F_DateTime desc", devidx, errs.ErrorIndex)).Tables[0].DefaultView;
|
|
if (dverr.Count > 0)
|
|
{//richard.liu20181212对报警记录更新最近一个的修复时间
|
|
sql.Remove(0, sql.Length);
|
|
sql.Append("UPDATE T_Base_Device_Error_Log SET F_FixDateTime ='").Append(DateTime.Now.ToString("u")).Append("' Where F_DeviceIndex=")
|
|
.Append(devidx).Append(" and F_ErrorIndex=").Append(errs.ErrorIndex).Append(" and F_ManageTaskNo=").Append(Convert.ToInt32(dverr[0]["F_ManageTaskNo"]));
|
|
//dbo.ExceSQL(sql.ToString());
|
|
StringBuilder[] dboArrary = new StringBuilder[1] { new StringBuilder("DBFactory") };
|
|
StringBuilder[] sqlArrary = new StringBuilder[1] { sql };
|
|
CUpdateDBChangeEventArgs exeSql = new CUpdateDBChangeEventArgs(dboArrary, sqlArrary);
|
|
OnDealSQLExe("OPCClient.CCommonOPCClient.OnDataChange", exeSql);
|
|
}
|
|
if (errs.IfAlarm == '1')
|
|
{
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0
|
|
//, 0, ccf.GetAlarmTimeSpan(devidx),errs.ErrorKind, 0, out errText);
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_AlarmStartTime='-' where F_DeviceIndex ={0}", devidx));
|
|
}
|
|
else
|
|
{
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, 0
|
|
//, ccf.GetErrorTimeSpan(devidx), 0,errs.ErrorKind, 0, out errText);
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ErrorStartTime='-' where F_DeviceIndex ={0}", devidx));
|
|
}
|
|
//开始记录运行时间
|
|
if (devkind == 2)
|
|
{
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19)));
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
else
|
|
{//状态变化:0->1开始运行;1->0()运行结束,运行时间增加
|
|
if (devinfo.ErrorCode == 0 && state == 1 && devkind == 2)
|
|
{
|
|
//开始记录运行时间
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='{1}' where F_DeviceIndex ={0}", devidx, DateTime.Now.ToString("u").Substring(0, 19)));
|
|
}
|
|
else if (devinfo.ErrorCode == 1 && (state == 0 || state == 2) && devkind == 2)
|
|
{
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date, 0, 0, 0, ccf.GetConveyorRunTimeSpan(devidx)
|
|
//, 0, 0,'O', 0, out errText);//统计上次运行时间
|
|
//dbo.ExecuteSql(string.Format("update T_Base_Device set F_ConveyorRunStartTime='-' where F_DeviceIndex ={0}", devidx));
|
|
}
|
|
}
|
|
//任务变化
|
|
if (devinfo.TaskNo != taskindex && devkind == 2 && taskindex > 0)
|
|
{
|
|
//CStaticClass.UpdateDeviceOEE(devidx, DateTime.Now.Date,1, 0, 0, 0
|
|
// ,0, 0,'O', 0, out errText);
|
|
}
|
|
#endregion
|
|
if (state == 2)
|
|
{
|
|
devinfo.RunState = 5;
|
|
}
|
|
else
|
|
{
|
|
devinfo.RunState = state;
|
|
}
|
|
devinfo.ErrorCode = state;
|
|
}
|
|
}
|
|
|
|
devinfo.TaskNo = taskindex;
|
|
if ((devinfo.DeviceKind == 1) || (devinfo.DeviceKind == 4) || (devinfo.DeviceKind == 14))
|
|
{
|
|
devinfo.XCoor = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标
|
|
if (devinfo.DeviceKind == 1)
|
|
{
|
|
devinfo.YCoor = devicestates[tempdb2addr + 11] + (devicestates[tempdb2addr + 10] << 8) + (devicestates[tempdb2addr + 9] << 16) + (devicestates[tempdb2addr + 8] << 32);//Y坐标
|
|
devinfo.ZCoor = devicestates[tempdb2addr + 12];//Z相对坐标(1或2\3)
|
|
|
|
}
|
|
}
|
|
|
|
Model.CGetInfo.SetDeviceInfo(devinfo);
|
|
modifypathdevinfo = Model.CGetInfo.GetModifyPathDeviceInfo(devidx);
|
|
if (modifypathdevinfo != null)
|
|
{
|
|
modifypathdevinfo.RunState = devinfo.RunState;
|
|
modifypathdevinfo.ErrorCode = devinfo.ErrorCode;
|
|
modifypathdevinfo.TaskNo = devinfo.TaskNo;
|
|
Model.CGetInfo.SetModifyPathDeviceInfo(modifypathdevinfo);
|
|
}
|
|
#endregion
|
|
|
|
#region 处理设备完成、报警、运行状态;条码信息
|
|
|
|
string bc = string.Empty;
|
|
int[] states = new int[(int)devinfo.Dbw2Getlength];
|
|
Array.Copy(devicestates, tempdb2addr, states, 0, (int)devinfo.Dbw2Getlength);
|
|
|
|
switch (devkind)
|
|
{
|
|
#region 堆垛机
|
|
case 1:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
#region 更新堆垛机光电开关状态
|
|
devinfo.SplitByte_0 = (devicestates[tempdb2addr + 13] & 1) == 1 ? 1 : 0;
|
|
devinfo.SplitByte_1 = (devicestates[tempdb2addr + 13] & 2) == 2 ? 1 : 0;
|
|
devinfo.SplitByte_2 = (devicestates[tempdb2addr + 13] & 4) == 4 ? 1 : 0;
|
|
devinfo.SplitByte_3 = (devicestates[tempdb2addr + 13] & 8) == 8 ? 1 : 0;
|
|
devinfo.SplitByte_4 = (devicestates[tempdb2addr + 13] & 16) == 16 ? 1 : 0;
|
|
devinfo.SplitByte_5 = (devicestates[tempdb2addr + 13] & 32) == 32 ? 1 : 0;
|
|
devinfo.SplitByte_6 = (devicestates[tempdb2addr + 13] & 64) == 64 ? 1 : 0;
|
|
devinfo.SplitByte_7 = (devicestates[tempdb2addr + 13] & 128) == 128 ? 1 : 0;
|
|
Model.CGetInfo.SetDeviceInfo(devinfo);
|
|
#endregion
|
|
if (IsEquals(devinfo.ReturnMessage, states, 4) == false)
|
|
{
|
|
bc = GetBarcodeFromMonitorIndex(taskindex);
|
|
xc = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标
|
|
yc = devicestates[tempdb2addr + 11] + (devicestates[tempdb2addr + 10] << 8) + (devicestates[tempdb2addr + 9] << 16) + (devicestates[tempdb2addr + 8] << 32);//Y坐标
|
|
|
|
devinfo.ReturnMessage = states;
|
|
Model.CGetInfo.SetDeviceMessage(devinfo);
|
|
sss.Remove(0, sss.Length);
|
|
sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex)
|
|
.Append("**列坐标" + xc).Append("**层坐标" + yc);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到堆垛机状态", devidx.ToString(), sss.ToString());
|
|
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
if ((state <= 0) || (taskindex <= 0))
|
|
{
|
|
|
|
continue;
|
|
}
|
|
AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state);
|
|
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state));
|
|
//cgs.GetKindDeviceState(taskindex, devidx, state);
|
|
|
|
}
|
|
break;
|
|
#endregion
|
|
|
|
#region 类输送机
|
|
case 2:
|
|
#region 更新输送机光电开关状态
|
|
|
|
devinfo.SplitByte_0 = (devicestates[tempdb2addr + 4] & 1) == 1 ? 1 : 0;
|
|
devinfo.SplitByte_1 = (devicestates[tempdb2addr + 4] & 2) == 2 ? 1 : 0;
|
|
devinfo.SplitByte_2 = (devicestates[tempdb2addr + 4] & 4) == 4 ? 1 : 0;
|
|
devinfo.SplitByte_3 = (devicestates[tempdb2addr + 4] & 8) == 8 ? 1 : 0;
|
|
devinfo.SplitByte_4 = (devicestates[tempdb2addr + 4] & 16) == 16 ? 1 : 0;
|
|
devinfo.SplitByte_5 = (devicestates[tempdb2addr + 4] & 32) == 32 ? 1 : 0;
|
|
devinfo.SplitByte_6 = (devicestates[tempdb2addr + 4] & 64) == 64 ? 1 : 0;
|
|
devinfo.SplitByte_7 = (devicestates[tempdb2addr + 4] & 128) == 128 ? 1 : 0;
|
|
Model.CGetInfo.SetDeviceInfo(devinfo);
|
|
#endregion
|
|
if (IsEquals(devinfo.ReturnMessage, states, 4) == false)
|
|
{
|
|
bc = GetBarcodeFromMonitorIndex(taskindex);
|
|
devinfo.ReturnMessage = states;
|
|
|
|
Model.CGetInfo.SetDeviceMessage(devinfo);
|
|
|
|
sss.Remove(0, sss.Length);
|
|
sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号:" + taskindex);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到输送机机状态", devidx.ToString(), sss.ToString());
|
|
|
|
//if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
if (state <= 0 || taskindex <= 0)//20140305
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (taskindex > 0)
|
|
{
|
|
AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state);
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state));
|
|
//cgs.GetKindDeviceState(taskindex, devidx, state);
|
|
|
|
}
|
|
}
|
|
break;
|
|
#endregion
|
|
|
|
#region 穿梭车RGV
|
|
case 4:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
#region 更新穿梭车光电开关状态
|
|
devinfo.SplitByte_0 = (devicestates[tempdb2addr + 8] & 1) == 1 ? 1 : 0;
|
|
devinfo.SplitByte_1 = (devicestates[tempdb2addr + 8] & 2) == 2 ? 1 : 0;
|
|
devinfo.SplitByte_2 = (devicestates[tempdb2addr + 8] & 4) == 4 ? 1 : 0;
|
|
devinfo.SplitByte_3 = (devicestates[tempdb2addr + 8] & 8) == 8 ? 1 : 0;
|
|
devinfo.SplitByte_4 = (devicestates[tempdb2addr + 8] & 16) == 16 ? 1 : 0;
|
|
devinfo.SplitByte_5 = (devicestates[tempdb2addr + 8] & 32) == 32 ? 1 : 0;
|
|
devinfo.SplitByte_6 = (devicestates[tempdb2addr + 8] & 64) == 64 ? 1 : 0;
|
|
devinfo.SplitByte_7 = (devicestates[tempdb2addr + 8] & 128) == 128 ? 1 : 0;
|
|
#endregion
|
|
Model.CGetInfo.SetDeviceInfo(devinfo);
|
|
if (IsEquals(devinfo.ReturnMessage, states, 4) == false)
|
|
{
|
|
bc = GetBarcodeFromMonitorIndex(taskindex);
|
|
xc = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标
|
|
devinfo.ReturnMessage = states;
|
|
devinfo.XCoor = xc;
|
|
Model.CGetInfo.SetDeviceMessage(devinfo);
|
|
sss.Remove(0, sss.Length);
|
|
sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex)
|
|
.Append("**列坐标" + xc);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到RGV状态", devidx.ToString(), sss.ToString());
|
|
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
if ((state <= 0) || (taskindex <= 0))
|
|
{
|
|
continue;
|
|
}
|
|
AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state);
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state));
|
|
//cgs.GetKindDeviceState(taskindex, devidx, state);
|
|
|
|
}
|
|
break;
|
|
#endregion
|
|
|
|
#region 条形码字符串信息
|
|
case 7:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
int BoxInspection = devicestates[tempdb2addr + 1]; //尺寸检测/数量
|
|
//20140109申请任务(任务不存在)或者条码比对(任务已经存在)
|
|
dvPLCASK = dbo.ExceSQL(string.Format("select F_BarCode,F_Time, F_PalletBarcodeLength,F_PalletBarcodeReservedLength,F_BarcodeReservedLength,F_WareHouse,F_ManageAskkind,F_BarcodeForkAmount,F_BarcodeLength,F_BindingDevice,F_Askkind,F_Remark from T_Base_PLC_Ask WHERE (F_DeviceIndex = {0}) ", devidx)).Tables[0].DefaultView; //20130510F_ManageAskkind
|
|
if (dvPLCASK.Count > 0)
|
|
{
|
|
StringBuilder warehouse = new StringBuilder(dvPLCASK[0]["F_WareHouse"].ToString());
|
|
int dcode = Convert.ToInt32(dvPLCASK[0]["F_BindingDevice"]);
|
|
int apptype = Convert.ToInt32(dvPLCASK[0]["F_ManageAskkind"]);//20130510
|
|
int BarcodeForkAmount = Convert.ToInt32(dvPLCASK[0]["F_BarcodeForkAmount"]); //多叉堆垛机存放箱条码的最大组数
|
|
|
|
byte[] weightbyte = new byte[4] { devicestates[tempdb2addr + 2], devicestates[tempdb2addr + 3], devicestates[tempdb2addr + 4], devicestates[tempdb2addr + 5] };
|
|
float weights = CommonClassLib.CCarryConvert.ByteToFloat(weightbyte);//重量信息
|
|
int BarcodeLength = Convert.ToInt32(dvPLCASK[0]["F_BarcodeLength"]);//多叉堆垛机取货站台上报条码、周转箱叠箱、托盘码垛
|
|
int BarcodeReservedLength = Convert.ToInt32(dvPLCASK[0]["F_BarcodeReservedLength"]);//多叉堆垛机取货站台上报条码、周转箱叠箱、托盘码垛
|
|
if (BarcodeReservedLength < BarcodeLength)
|
|
{
|
|
BarcodeReservedLength = BarcodeLength;
|
|
}
|
|
//int BarcodeTotalLength = BarcodeReservedLength * BoxInspection;
|
|
int PalletBarcodeLength = Convert.ToInt32(dvPLCASK[0]["F_PalletBarcodeLength"]);//托盘条码
|
|
int PalletBarcodeReservedLength = Convert.ToInt32(dvPLCASK[0]["F_PalletBarcodeReservedLength"]);
|
|
if (PalletBarcodeReservedLength < PalletBarcodeLength)
|
|
{
|
|
PalletBarcodeReservedLength = PalletBarcodeLength;
|
|
}
|
|
StringBuilder incompleteBarcode = new StringBuilder();// 1111111111111111.......
|
|
StringBuilder noneBarcode = new StringBuilder();// \0\0\0\0..........
|
|
StringBuilder appbarcode = new StringBuilder();
|
|
StringBuilder[] appbarArray = new StringBuilder[BarcodeForkAmount];
|
|
StringBuilder parameter = new StringBuilder();//存放给管理上报的纸箱条码组
|
|
|
|
#region 初始化接收条码
|
|
|
|
//for (int j = 1; j <= BarcodeLength; j++)
|
|
//{
|
|
// incompleteBarcode.Append("1");//PLC扫到残码,但是有货物,转换为字符'1'
|
|
// noneBarcode.Append("0");//PLC没扫描,没货物,保留的空值0,转换为字符'\0'
|
|
//}
|
|
//for (int j = 0; j < BarcodeForkAmount; j++)
|
|
//{//多叉堆垛机,在取货前上报条码格式:头+数量+条码//20140218
|
|
// appbarArray[j] = new StringBuilder(ASCIIEncoding.ASCII.GetString(devicestates, tempdb2addr + 2 + j * BarcodeReservedLength, BarcodeReservedLength).Substring(0, BarcodeLength));
|
|
|
|
//}
|
|
barcode.Clear();
|
|
if (PalletBarcodeLength > 0)
|
|
{//普通扫描单箱的条码申请\机器人码垛的托盘条码
|
|
incompleteBarcode.Clear();//20150103
|
|
noneBarcode.Clear();//20150103
|
|
for (int j = 1; j <= PalletBarcodeLength; j++)
|
|
{//20150103
|
|
incompleteBarcode.Append("1");//PLC扫到残码,但是有货物,转换为字符'1'
|
|
noneBarcode.Append("0");//PLC没扫描,没货物,保留的空值0,转换为字符'\0'
|
|
}
|
|
for (int j = 4; j < PalletBarcodeLength + 4; j++)
|
|
{
|
|
barcode.Append(Convert.ToChar(devicestates[tempdb2addr + j]).ToString().ToUpper());
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (IsEquals(devinfo.ReturnMessage, states, states.Length) == false)
|
|
{
|
|
devinfo.ReturnMessage = states;
|
|
Model.CGetInfo.SetDeviceMessage(devinfo);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "读PLC条码", devidx.ToString(), "读标志1**条码:" + barcode.ToString().Trim('\0').ToUpper()+"高度:"+ BoxInspection.ToString()+"任务号:"+taskindex);
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
//20130831richard
|
|
DateTime appdt = new DateTime();
|
|
if (dvPLCASK[0]["F_Time"] == DBNull.Value)
|
|
{
|
|
appdt = DateTime.Now.AddSeconds(-10);
|
|
}
|
|
else
|
|
{
|
|
DateTime.TryParse(dvPLCASK[0]["F_Time"].ToString(), out appdt);
|
|
}
|
|
if (dvPLCASK[0]["F_BarCode"] != DBNull.Value)
|
|
{
|
|
if ((appdt.AddSeconds(15) > DateTime.Now) && (dvPLCASK[0]["F_BarCode"].ToString() == barcode.ToString()))
|
|
{
|
|
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "PLC重复上报条码:", devidx.ToString(), ",站台:" + dcode + ",条码:" + barcode.ToString().ToUpper());
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
switch (dvPLCASK[0]["F_Askkind"].ToString())
|
|
{
|
|
case "4":
|
|
//普通条码申请任务
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 4, barcode.ToString().Trim('\0'), BoxInspection));
|
|
|
|
break;
|
|
case "6":
|
|
//103合托后申请入库
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", taskindex, 0, 6, barcode.ToString().Trim('\0'), BoxInspection));
|
|
|
|
break;
|
|
case "8":
|
|
//二合一
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", taskindex, 0, 8, barcode.ToString().Trim('\0'), BoxInspection));
|
|
|
|
break;
|
|
case "5":
|
|
//比对任务报完成,申请任务
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", taskindex, 0, 5, barcode.ToString().Trim('\0'), BoxInspection));
|
|
|
|
break;
|
|
case "7":
|
|
//组件扫码成品入库
|
|
#region 组件条码申请任务
|
|
barcode.Clear();
|
|
|
|
|
|
for (int j = 2; j < PalletBarcodeLength; j++)
|
|
{
|
|
if (devicestates[tempdb2addr + j] == 13)
|
|
{
|
|
break;
|
|
}
|
|
barcode.Append(Convert.ToChar(devicestates[tempdb2addr + j]).ToString().ToUpper());
|
|
}
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 7, barcode.ToString().Trim('\0'), BoxInspection));
|
|
|
|
#endregion
|
|
break;
|
|
case "9":
|
|
//大叠托机申请离开
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 5, barcode.ToString().Trim('\0'), BoxInspection));
|
|
break;
|
|
case "13":
|
|
//条码报告完成,考虑第一个扫描器没扫到,但是第二个扫描器却扫到
|
|
//没扫到或者有码无对应任务的改道异常口
|
|
#region 条码报告完成
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 13, barcode.ToString(), BoxInspection));
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写条码应答", devidx.ToString(), "写标志:2" + "**源条码:" + barcode.ToString().ToUpper());
|
|
|
|
#endregion
|
|
break;
|
|
|
|
|
|
case "17":
|
|
#region 叠箱机上报个数和箱条码
|
|
|
|
if (parameter.ToString().Length > 0)
|
|
{
|
|
#region 向管理申请叠箱后入库任务
|
|
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "向管理申请叠箱入库任务", devidx.ToString(), dcode + "条码" + barcode.ToString().ToUpper() + "垛条码:" + parameter.ToString());
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}#{3}#{4}", 0, 0, 17, barcode.ToString(), BoxInspection));
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
#endregion
|
|
break;
|
|
|
|
default:
|
|
//无类型,条码比对或者记录条码
|
|
break;
|
|
}
|
|
|
|
AddBatchReponse(Model.CGeneralFunction.DBGet, 0, devidx, 2);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写条码应答", devidx.ToString(), "写标志2" + "**源条码:" + barcode.ToString().ToUpper());
|
|
|
|
}
|
|
break;
|
|
#endregion
|
|
#region 落地机按钮申请空母托对应设备
|
|
|
|
case 36:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
//0字节代表命令字:1表示PLC上报,2表示PC应答
|
|
//1字节:1申请空母托
|
|
AddBatchReponse(Model.CGeneralFunction.DBGet, 0, devidx, 2);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写落地机按钮申请空母托应答", devidx.ToString(), "写标志2**申请空母托标识:" + devicestates[tempdb2addr + 1].ToString() + ";" + witemnames[0].ToString());
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}", 0, 0, devicestates[tempdb2addr + 1]));
|
|
|
|
break;
|
|
|
|
#endregion
|
|
|
|
#region 拆叠盘机申请出入库对应设备
|
|
|
|
case 38:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
//0字节代表命令字:1表示PLC上报,2表示PC应答
|
|
//1字节:1申请入库;2申请出库
|
|
AddBatchReponse(Model.CGeneralFunction.DBGet, 0, devidx, 2);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "写拆叠盘机申请出入库应答", devidx.ToString(), "写标志2**出入库任务类型:" + devicestates[tempdb2addr + 1].ToString() + ";" + witemnames[0].ToString());
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}#{2}", 0, 0, devicestates[tempdb2addr + 1]));
|
|
|
|
break;
|
|
|
|
#endregion
|
|
|
|
#region 出入库方向电气申请变更
|
|
|
|
case 39:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
|
|
|
|
break;
|
|
|
|
#endregion
|
|
#region 鸿安环穿主站
|
|
case 13:
|
|
//if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
if (devinfo.UnControl == "1")
|
|
{//主站心跳
|
|
#region 心跳反馈和判断,把电气值+1
|
|
int xt = (devicestates[tempdb2addr + 0] << 8) + devicestates[tempdb2addr + 1];
|
|
//发送心跳
|
|
if (xt >= 30000) xt = 0;
|
|
devinfo.SendInterval = xt;
|
|
StringBuilder[] itemname; StringBuilder[] itemvalue;
|
|
itemname = new StringBuilder[1] { new StringBuilder("") };
|
|
itemname[0].Append(Model.CGeneralFunction.DBSend).Append(".").Append(devinfo.Dbw1Address).Append(",i");
|
|
itemvalue = new StringBuilder[1] { new StringBuilder("") };
|
|
itemvalue[0].Append(xt + 1);
|
|
CCommonOPCClient.Hostname = CommonClassLib.AppSettings.GetValue("HostName");
|
|
CCommonOPCClient.ProgID = CommonClassLib.AppSettings.GetValue("OPCProgID");
|
|
AsyncWriteAllItemValue(devinfo.S7Connection, itemname, itemvalue);
|
|
|
|
//AddBatchReponse(Model.CGeneralFunction.DBSend, 0, devidx, xt+1);
|
|
//CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "发送环穿主站心跳", devidx.ToString(), string.Format("收到心跳:{0},发送心跳:{1}",xt,xt+1));
|
|
#endregion
|
|
}
|
|
else
|
|
{
|
|
if (IsEquals(devinfo.ReturnMessage, states, states.Length) == false)
|
|
{//主站
|
|
#region 更新主站故障报警状态
|
|
int ies = (devicestates[tempdb2addr + 4] << 8) + devicestates[tempdb2addr + 5];
|
|
int isd = (devicestates[tempdb2addr + 6] << 8) + devicestates[tempdb2addr + 7];
|
|
int islg = (devicestates[tempdb2addr + 8] << 8) + devicestates[tempdb2addr + 9];
|
|
for (int hi = 0; hi <= 15; hi++)
|
|
{
|
|
devinfo.EmergencyStop[hi] = (ies & Convert.ToUInt16(Math.Pow(2, hi))) == Math.Pow(2, hi);//BIT0--BIT15代表#1..#16紧急停止状态BIT=0表示正常,BIT=1表示异常
|
|
devinfo.SafetyDoor[hi] = (isd & Convert.ToUInt16(Math.Pow(2, hi))) == Math.Pow(2, hi);//BIT0--BIT15代表#1..#16安全门状态BIT=0表示正常,BIT=1表示异常
|
|
devinfo.SafetyLightGrid[hi] = (islg & Convert.ToUInt16(Math.Pow(2, hi))) == Math.Pow(2, hi);// BIT0--BIT15代表#1..#16安全光栅状态BIT=0表示正常,BIT=1表示异常
|
|
}
|
|
|
|
#endregion
|
|
bc = GetBarcodeFromMonitorIndex(taskindex);
|
|
devinfo.ReturnMessage = states;
|
|
|
|
Model.CGetInfo.SetDeviceMessage(devinfo);
|
|
sss.Remove(0, sss.Length);
|
|
sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex).Append("接收结果:").Append(devicestates[tempdb2addr + 3])
|
|
.Append("**列坐标" + xc);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到环穿主站状态", devidx.ToString(), sss.ToString());
|
|
|
|
//if (devicestates[tempdb2addr + 0] != 1) continue;//WCS可下命令
|
|
if ((devicestates[tempdb2addr + 1] <= 0) || (taskindex <= 0))
|
|
{//1:正常接收,解锁主站,接收下一个命令;2:任务异常
|
|
continue;
|
|
}
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, devicestates[tempdb2addr + 1]));
|
|
//不需要回复数据AddBatchReponse("DB1", taskindex, devidx, state);
|
|
//cgs.GetKindDeviceState(taskindex, devidx, devicestates[tempdb2addr + 3]);
|
|
|
|
}
|
|
}
|
|
break;
|
|
#endregion
|
|
#region 鸿安环形穿梭车RGV
|
|
case 14:
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
|
|
#region 更新环形穿梭车光电开关状态
|
|
devinfo.SplitByte_0 = (devicestates[tempdb2addr + 8] & 1) == 1 ? 1 : 0;
|
|
devinfo.SplitByte_1 = (devicestates[tempdb2addr + 8] & 2) == 2 ? 1 : 0;
|
|
devinfo.SplitByte_2 = (devicestates[tempdb2addr + 8] & 4) == 4 ? 1 : 0;
|
|
devinfo.SplitByte_3 = (devicestates[tempdb2addr + 8] & 8) == 8 ? 1 : 0;
|
|
devinfo.SplitByte_4 = (devicestates[tempdb2addr + 8] & 16) == 16 ? 1 : 0;
|
|
devinfo.SplitByte_5 = (devicestates[tempdb2addr + 8] & 32) == 32 ? 1 : 0;
|
|
devinfo.SplitByte_6 = (devicestates[tempdb2addr + 8] & 64) == 64 ? 1 : 0;
|
|
devinfo.SplitByte_7 = (devicestates[tempdb2addr + 8] & 128) == 128 ? 1 : 0;
|
|
#endregion
|
|
Model.CGetInfo.SetDeviceInfo(devinfo);
|
|
if (IsEquals(devinfo.ReturnMessage, states, 4) == false)
|
|
{
|
|
bc = GetBarcodeFromMonitorIndex(taskindex);
|
|
xc = devicestates[tempdb2addr + 7] + (devicestates[tempdb2addr + 6] << 8) + (devicestates[tempdb2addr + 5] << 16) + (devicestates[tempdb2addr + 4] << 32);//X坐标
|
|
devinfo.ReturnMessage = states;
|
|
|
|
Model.CGetInfo.SetDeviceMessage(devinfo);
|
|
sss.Remove(0, sss.Length);
|
|
sss.Append("**条码:").Append(bc).Append("**读标志" + devicestates[tempdb2addr + 0]).Append("**状态" + state).Append("**任务号" + taskindex)
|
|
.Append("**列坐标" + xc);
|
|
CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "收到环穿RGV状态", devidx.ToString(), sss.ToString());
|
|
|
|
if (devicestates[tempdb2addr + 0] != 1) continue;
|
|
if ((state <= 0) || (taskindex <= 0))
|
|
{
|
|
continue;
|
|
}
|
|
AddBatchReponse(Model.CGeneralFunction.DBSend, taskindex, devidx, state);
|
|
DeviceStateInfos[devidx].Append(string.Format("{0}#{1}", taskindex, state));
|
|
//cgs.GetKindDeviceState(taskindex, devidx, state);
|
|
|
|
}
|
|
break;
|
|
#endregion
|
|
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
#region 一个订阅组内设备按订阅ID deviceindex一批发送应答20230811richard.liu
|
|
StringBuilder[] itmenames = null; StringBuilder[] itmevalues = null;
|
|
StringBuilder[] sbDdeviceStateInfos = new StringBuilder[DeviceStateInfos.Count];
|
|
if (_opcSubsTagCount.ContainsKey(deviceindex.ToString()) == true)
|
|
{
|
|
itmenames = new StringBuilder[_opcSubsTagCount[deviceindex.ToString()]];
|
|
itmevalues = new StringBuilder[_opcSubsTagCount[deviceindex.ToString()]];
|
|
int deviceTagCount = 0;
|
|
if (_opcItemNamesDicInfo.Count > 0)
|
|
{
|
|
foreach (int devidx in _opcItemNamesDicInfo[deviceindex.ToString()].Keys)
|
|
{
|
|
Array.Copy(_opcItemNamesDicInfo[deviceindex.ToString()][devidx], 0, itmenames, deviceTagCount, _opcItemNamesDicInfo[deviceindex.ToString()][devidx].Length);
|
|
Array.Copy(_opcItemValuesDicInfo[deviceindex.ToString()][devidx], 0, itmevalues, deviceTagCount, _opcItemValuesDicInfo[deviceindex.ToString()][devidx].Length);
|
|
deviceTagCount += _opcItemNamesDicInfo[deviceindex.ToString()][devidx].Length;
|
|
}
|
|
}
|
|
}
|
|
int i = 0;
|
|
foreach (int devidx in DeviceStateInfos.Keys)
|
|
{
|
|
if (DeviceStateInfos[devidx].ToString().Split('#').Length > 2)
|
|
{
|
|
sbDdeviceStateInfos[i] = DeviceStateInfos[devidx];
|
|
i++;
|
|
}
|
|
}
|
|
if (i > 0 || itmenames != null)
|
|
{
|
|
StringBuilder[] sbDdeviceStateInfosNew = new StringBuilder[i];
|
|
Array.Copy(sbDdeviceStateInfos, sbDdeviceStateInfosNew, i);
|
|
CUpdateDBChangeEventArgs udbe = new CUpdateDBChangeEventArgs(deviceindex, sbDdeviceStateInfosNew, itmenames, itmevalues);
|
|
string ss = "";
|
|
for (int kk = 0; kk < sbDdeviceStateInfosNew.Length; kk++)
|
|
{
|
|
ss += sbDdeviceStateInfosNew[kk].ToString();
|
|
}
|
|
//CommonClassLib.CCarryConvert.WriteDarkCasket("OPCClient", "调用on", deviceindex.ToString(), ss);
|
|
OnPublishDeviceState("OPCClient.CCommonOPCClient.OnDataChange", udbe);
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
#endregion
|
|
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RefreshMonitorEventArgs rmea = new RefreshMonitorEventArgs("tsStatus", "CCommonOPCClient.DealWithDeviceState时" + ex.Message + ex.StackTrace);
|
|
OnRefreshMonitor(rmea);
|
|
errtext = ex.Message + ex.StackTrace;
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
|
|
|
|
dvDevice.Dispose();
|
|
dvbc.Dispose();
|
|
dvPLCASK.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#region 自定义方法
|
|
static string _stockCodeCheck = "^[B|D|G|P][A-Z][0-9]{4}$";
|
|
/// <summary>
|
|
/// 条码格式检查
|
|
/// </summary>
|
|
public static string StockCodeCheck
|
|
{
|
|
|
|
get { return _stockCodeCheck; }
|
|
set
|
|
{
|
|
int aa;
|
|
if (int.TryParse(_stockCodeCheck, out aa) == true)
|
|
{
|
|
_stockCodeCheck = value;
|
|
}
|
|
else
|
|
{
|
|
_stockCodeCheck = "^[B|D|G|P][A-Z][0-9]{4}$";
|
|
}
|
|
}
|
|
}
|
|
private static void AddBatchReponse(string DBBlock, int taskindex, int devidx, int state)
|
|
{
|
|
StringBuilder[] itemnames = new StringBuilder[0]; StringBuilder[] itemvalues = new StringBuilder[0];
|
|
try
|
|
{
|
|
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(devidx);
|
|
int devKind = devinfo.DeviceKind;
|
|
if (DBBlock == "DB1")
|
|
{//根据devidx类型和state判断发送应答
|
|
if (state == 1)
|
|
{//运行
|
|
if ((devKind == 1)) //堆垛机
|
|
{
|
|
int[] sendmes = new int[10] { 0, 0, 0, devidx, 0, 0, 0, 0, 0, 0 };
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(devidx);
|
|
if (IsEquals(devinfo.SendMessage, sendmes, 10) == false)
|
|
{
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(0, 0, 0, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues);
|
|
}
|
|
}
|
|
else if (devKind == 4 || devKind == 2)
|
|
{//输送机、RGV运行清零
|
|
int[] sendmes = new int[5] { 0, 0, 0, devidx, 0 };
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(devidx);
|
|
if (devinfo.IfClearDB1 == "1" && IsEquals(devinfo.SendMessage, sendmes, 5) == false)
|
|
{
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(0, 0, 0, devidx, 0, out itemnames, out itemvalues);
|
|
}
|
|
}
|
|
}
|
|
else if (state == 2)
|
|
{//完成
|
|
if ((devKind == 1)) //堆垛机
|
|
{
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(2, 0, 0, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues);
|
|
}
|
|
else if (devKind == 14)
|
|
{//环穿小车应答任务号richard.liu20230718
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(2, taskindex, 99, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues);
|
|
}
|
|
else if (devKind == 4 || devKind == 2)
|
|
{//输送机、RGV
|
|
int taskRGV = 0;
|
|
//richard.liu20230718,增加给取货输送机发送环穿取货指令索引
|
|
object obt = dbo.GetSingle(string.Format("select F_CHANNELSINDEX from T_BASE_RGV_GATE, t_base_device where F_CHANNELSINDEX=f_deviceindex and f_devicekindindex=13 and F_RGVGATEDEVICEINDEX={0}", devidx));
|
|
if (obt != null)
|
|
{
|
|
obt = dbo.GetSingle(string.Format("select f_monitorindex from t_monitor_task where f_monitorindex >{0} and f_deviceindex= {1} order by f_monitorindex asc", taskindex, Convert.ToInt32(obt)));
|
|
if (obt != null)
|
|
{
|
|
taskRGV = Convert.ToInt32(obt);
|
|
}
|
|
}
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(2, taskRGV, 0, devidx, 0, out itemnames, out itemvalues);
|
|
}
|
|
else
|
|
{
|
|
//按state值发送应答
|
|
itemnames = new StringBuilder[1] { new StringBuilder() };
|
|
itemvalues = new StringBuilder[1] { new StringBuilder() };
|
|
itemnames[0].Append(DBBlock).Append(".").Append(Convert.ToString(devinfo.Dbw2Address + 0)).Append(",b");
|
|
itemvalues[0].Append(state);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (devKind == 1) //堆垛机
|
|
{//报警,堆垛机清零去掉残留任务
|
|
int[] sendmes = new int[10] { 0, 0, 0, devidx, 0, 0, 0, 0, 0, 0 };
|
|
if (IsEquals(devinfo.SendMessage, sendmes, 10) == false)
|
|
{
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(0, 0, 0, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues);
|
|
}
|
|
}
|
|
else if (devKind == 13)
|
|
{//发送心跳,头99
|
|
sdo = CommModeCreate.CreateSendDeviceOrder(devidx);
|
|
sdo.SendDeviceOrder(99, 0, state, devidx, 0, 0, 0, 0, 0, 0, out itemnames, out itemvalues);
|
|
}
|
|
}
|
|
}
|
|
else if (DBBlock == "DB2")
|
|
{//按state值发送应答
|
|
itemnames = new StringBuilder[1] { new StringBuilder()};
|
|
itemvalues = new StringBuilder[1] { new StringBuilder() };
|
|
itemnames[0].Append(DBBlock).Append(".").Append(Convert.ToString(devinfo.Dbw2Address + 0)).Append(",b");
|
|
itemvalues[0].Append(state);
|
|
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
//20230811richard.liu暂存标签数据
|
|
if (itemnames.Length > 0)
|
|
{
|
|
AddOPCSendData(devidx, itemnames, itemvalues);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
|
|
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 暂存标签数据
|
|
/// </summary>
|
|
/// <param name="deviceIndex">设备编号</param>
|
|
/// <param name="itemnames">地址区标签名称数组</param>
|
|
/// <param name="itemvalues">标签值数组</param>
|
|
private static void AddOPCSendData(int deviceIndex, StringBuilder[] itemnames, StringBuilder[] itemvalues)
|
|
{//20230811richard.liu周期内按S7连接批量发送,重构CControl.cs,CCommonOPCClient.cs\DealWithDeviceState;文件夹Communication、Common内通讯CSendDeviceOrder: ISendDeviceOrder相关文件
|
|
|
|
try
|
|
{
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(deviceIndex);
|
|
if (_opcItemNamesDicInfo.ContainsKey(devinfo.ReadSubscription))
|
|
{//添加OPC订阅组+dic 设备编码+数组 发送数据
|
|
if (_opcItemNamesDicInfo[devinfo.ReadSubscription].ContainsKey(devinfo.DeviceIndex) == false)
|
|
{
|
|
_opcSubsTagCount[devinfo.ReadSubscription] += itemnames.Length;
|
|
_opcItemNamesDicInfo[devinfo.ReadSubscription].Add(devinfo.DeviceIndex, itemnames);
|
|
_opcItemValuesDicInfo[devinfo.ReadSubscription].Add(devinfo.DeviceIndex, itemvalues);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Dictionary<int, StringBuilder[]> OPCDeviceSendtagNamedic = new Dictionary<int, StringBuilder[]>();
|
|
Dictionary<int, StringBuilder[]> OPCDeviceSendtagValuedic = new Dictionary<int, StringBuilder[]>();
|
|
OPCDeviceSendtagNamedic.Add(devinfo.DeviceIndex, itemnames);
|
|
OPCDeviceSendtagValuedic.Add(devinfo.DeviceIndex, itemvalues);
|
|
|
|
_opcSubsTagCount.Add(devinfo.ReadSubscription, itemnames.Length);
|
|
_opcItemNamesDicInfo.Add(devinfo.ReadSubscription, OPCDeviceSendtagNamedic);
|
|
_opcItemValuesDicInfo.Add(devinfo.ReadSubscription, OPCDeviceSendtagValuedic);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 比较两个值型一维数组变量是否值相等
|
|
/// </summary>
|
|
/// <param name="array1">值型一维数组1</param>
|
|
/// <param name="array2">值型一维数组2</param>
|
|
/// <returns>比较结果,相等则true,否则false</returns>
|
|
static public bool IsEquals(Array array1, Array array2, int arraylength)
|
|
{//20090902新增加arraylength
|
|
//比较类型是否一样
|
|
if ((array1 == null) || (array2 == null)) return false;
|
|
if (!Object.ReferenceEquals(array1.GetType(), array2.GetType()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//比较长度是否一样
|
|
if (array1.GetLength(0) != array2.GetLength(0))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//比较成员是否对应相等
|
|
ValueType v1, v2;
|
|
for (int i = 0; i < arraylength; i++)
|
|
{
|
|
v1 = (ValueType)array1.GetValue(i);
|
|
v2 = (ValueType)array2.GetValue(i);
|
|
|
|
if (!v1.Equals(v2))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static string GetBarcodeFromMonitorIndex(int taskindex)
|
|
{
|
|
DataView dvb = new DataView(); StringBuilder sss = new StringBuilder("");
|
|
try
|
|
{
|
|
|
|
sss.Append("SELECT F_TxtParam FROM T_Monitor_Task WHERE (F_MonitorIndex = ").Append(taskindex).Append(")");
|
|
dvb = dbo.ExceSQL(sss.ToString()).Tables[0].DefaultView;
|
|
if (dvb.Count > 0)
|
|
{
|
|
return dvb[0]["F_TxtParam"].ToString();
|
|
}
|
|
else
|
|
{
|
|
return "-";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dvb.Dispose();
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
static private string _PLCconnectionID = "S7 connection_1";//OPC.UA的新写法"ns=2,S7 connection_1.db2.0,b,5"表示:"S7:[S7 connection_1]的db2.DBB0开始5个字节"
|
|
/// <summary>
|
|
/// 建立PLC连接的ID,例如:"S7:[S7 connection_1]"
|
|
/// 或者"S7:[@LOCALSERVER]"
|
|
/// </summary>
|
|
public static string PlcConnectionID
|
|
{
|
|
get { return CCommonOPCClient._PLCconnectionID; }
|
|
set { CCommonOPCClient._PLCconnectionID = value; }
|
|
}
|
|
static private string _opcError;
|
|
static private bool _IfConnectOPCServer=false ;
|
|
static private string _hostname;
|
|
/// <summary>
|
|
/// OPC Server的机器名称或者IP地址
|
|
/// </summary>
|
|
public static string Hostname
|
|
{
|
|
get { return CCommonOPCClient._hostname; }
|
|
set { CCommonOPCClient._hostname = value; }
|
|
}
|
|
static private string _progID;
|
|
/// <summary>
|
|
/// OPC Server的程序标识,例如:OPC.SimaticNET
|
|
/// </summary>
|
|
public static string ProgID
|
|
{
|
|
get { return CCommonOPCClient._progID; }
|
|
set { CCommonOPCClient._progID = value; }
|
|
}
|
|
public static string OpcError
|
|
{
|
|
get { return CCommonOPCClient._opcError; }
|
|
set {
|
|
CCommonOPCClient._opcError = value;
|
|
RefreshMonitorEventArgs rme = new RefreshMonitorEventArgs("tsStatus", _opcError);
|
|
OnRefreshMonitor(rme);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 《设备索引,对应设备订阅》
|
|
/// </summary>
|
|
public static SubscriptionCollection SubscriptionGroup = new SubscriptionCollection();//定义组对象集合(订阅者集合)//20110309
|
|
|
|
/// <summary>
|
|
/// 20110309每个设备创建一个订阅和DataChange事件
|
|
/// </summary>
|
|
public static void CreateSubscriptionGroup()
|
|
{
|
|
|
|
if (_IfConnectOPCServer == false)
|
|
{
|
|
_hostname = CommonClassLib.AppSettings.GetValue("HostName");
|
|
_progID = CommonClassLib.AppSettings.GetValue("OPCProgID");
|
|
if (ConnectOPCServer(_hostname, _progID) == false) return ;
|
|
}
|
|
//DataView dv = dbo.ExceSQL("SELECT F_ReadSubscription, F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection, F_SplitByte FROM T_Base_Device WHERE (F_ReadSubscription IS NOT NULL) AND (F_ReadSubscription =F_DeviceIndex) and ((f_localport!=3 and f_localport!=4 and f_localport!=7 and f_localport!=10) or f_devicekindindex=2) ORDER BY F_ReadSubscription").Tables[0].DefaultView;
|
|
DataView dv = dbo.ExceSQL("SELECT F_ReadSubscription, F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection, F_SplitByte FROM T_Base_Device WHERE (F_ReadSubscription IS NOT NULL) AND (F_ReadSubscription =F_DeviceIndex) ORDER BY F_ReadSubscription").Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
if (dv.Count < SubscriptionGroup.Count) return;
|
|
}
|
|
DataView dvx;
|
|
for (int i = 0; i < dv.Count; i++)
|
|
{
|
|
string dt = DateTime.Now.Minute.ToString() + "-" + DateTime.Now.Second.ToString() + "-" + DateTime.Now.Millisecond.ToString();
|
|
dvx = dbo.ExceSQL(string.Format("SELECT (MAX(F_DBW2Address) + F_DBWGetLength) as maxdbw2 FROM T_Base_Device WHERE (F_ReadSubscription = {0}) AND (F_DeviceKindIndex != 33) GROUP BY F_DBWGetLength ORDER BY maxdbw2 DESC", dv[i]["F_ReadSubscription"])).Tables[0].DefaultView;
|
|
if (dvx.Count > 0)
|
|
{
|
|
NodeId nodeId;
|
|
if (dv[i]["F_S7Connection"].ToString() == "@localserver"|| (Convert.ToInt32(dv[i]["F_DeviceIndex"])>=34091&& Convert.ToInt32(dv[i]["F_DeviceIndex"]) <= 34100))
|
|
{
|
|
nodeId = new NodeId(dv[i]["F_S7Connection"].ToString() + "." +
|
|
"DB1" + "." +
|
|
dv[i]["F_DBW2Address"].ToString() + ",b," +
|
|
(System.Convert.ToInt32(System.Convert.ToInt32(dvx[0]["maxdbw2"]) - System.Convert.ToInt32(dv[i]["F_DBW2Address"]))).ToString(), S7NameSpace);
|
|
}
|
|
else
|
|
{
|
|
nodeId = new NodeId(dv[i]["F_S7Connection"].ToString() + "." +
|
|
Model.CGeneralFunction.DBGet + "." +
|
|
dv[i]["F_DBW2Address"].ToString() + ",b," +
|
|
(System.Convert.ToInt32(System.Convert.ToInt32(dvx[0]["maxdbw2"]) - System.Convert.ToInt32(dv[i]["F_DBW2Address"]))).ToString(), S7NameSpace);//20151120
|
|
}
|
|
|
|
// Add the attribute name/value to the list view.
|
|
object serverHandle = null;
|
|
|
|
|
|
try
|
|
{
|
|
// Add the item and apply any changes to it.
|
|
m_Subscription.AddDataMonitoredItem(nodeId, dv[i]["F_ReadSubscription"].ToString(), OnDataChange, 700, out serverHandle);
|
|
|
|
}
|
|
catch (ServiceResultException monitoredItemResult)
|
|
{
|
|
OpcError = "建立OPC订阅组时:" + monitoredItemResult.Message;
|
|
if (ConnectCount.ContainsKey(dv[i]["F_S7Connection"].ToString()) == false)//20110726
|
|
{
|
|
ConnectCount.Add(dv[i]["F_S7Connection"].ToString(), 1);
|
|
}
|
|
else
|
|
{
|
|
ConnectCount[dv[i]["F_S7Connection"].ToString()]++;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
dv = dbo.ExceSQL("SELECT F_ReadSubscription, F_DeviceIndex, F_DBW2Address, F_DBWGetLength, F_S7Connection, F_SplitByte FROM T_Base_Device WHERE (F_ReadSubscription IS NOT NULL) AND (F_DeviceKindIndex=33) ORDER BY F_ReadSubscription").Tables[0].DefaultView;
|
|
|
|
for (int i = 0; i < dv.Count; i++)
|
|
{
|
|
NodeId nodeId = new NodeId(dv[i]["F_S7Connection"].ToString() + "." +
|
|
Model.CGeneralFunction.DBGet + "." +
|
|
dv[i]["F_DBW2Address"].ToString() + ",b," + System.Convert.ToInt32(dv[i]["F_DBWGetLength"]).ToString(), S7NameSpace);//20151120
|
|
|
|
// Add the attribute name/value to the list view.
|
|
object serverHandle = null;
|
|
|
|
|
|
try
|
|
{
|
|
// Add the item and apply any changes to it.
|
|
m_Subscription.AddDataMonitoredItem(nodeId, "split" + dv[i]["F_ReadSubscription"].ToString(), OnDataChange, 100, out serverHandle);
|
|
|
|
}
|
|
catch (ServiceResultException monitoredItemResult)
|
|
{
|
|
OpcError = "建立OPC订阅组时:" + monitoredItemResult.Message;
|
|
if (ConnectCount.ContainsKey(dv[i]["F_S7Connection"].ToString()) == false)//20110726
|
|
{
|
|
ConnectCount.Add(dv[i]["F_S7Connection"].ToString(), 1);
|
|
}
|
|
else
|
|
{
|
|
ConnectCount[dv[i]["F_S7Connection"].ToString()]++;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 通过设置订阅的监控模式,刷新订阅
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static bool RefreshMonitoringMode()
|
|
{//20150103增加断网恢复
|
|
if (m_Subscription != null)
|
|
{
|
|
m_Subscription.RefreshMonitoringMode();
|
|
}
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// 连接指定主机的OPC服务器
|
|
/// </summary>
|
|
/// <param name="hostname">主机名称</param>
|
|
/// <param name="ProgID">OPC服务器程序标识例如:"OPC.SimaticNET"</param>
|
|
/// <returns></returns>
|
|
public static bool ConnectOPCServer(string hostname, string ProgID)
|
|
{
|
|
try
|
|
{
|
|
if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726
|
|
{
|
|
ConnectCount.Add(_PLCconnectionID, 0);
|
|
}
|
|
if (ConnectCount[_PLCconnectionID] > 1)//20150204
|
|
{
|
|
_opcError = "WCS没连接到OPC Server:" + _PLCconnectionID.ToString() + ",人工确认后进行【PLC初始化】";//20150204
|
|
return false ;
|
|
}
|
|
//Uri discoveryUrl = new Uri("opc.tcp://" + hostname + ":4845");
|
|
Uri discoveryUrl = new Uri("opc.tcp://" + hostname + ":55101");
|
|
Discovery discovery = new Discovery();
|
|
EndpointDescriptionCollection endpoints = null;
|
|
string rr = discovery.GetEndpoints(discoveryUrl, ref endpoints);
|
|
if(endpoints == null)
|
|
{
|
|
if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726
|
|
{
|
|
ConnectCount.Add(_PLCconnectionID, 0);
|
|
}
|
|
ConnectCount[_PLCconnectionID]++;
|
|
OpcError = "连接OPC数据存取服务器时:GetEndpoints没找到OPC服务器!";
|
|
_IfConnectOPCServer = false;
|
|
return false;
|
|
}
|
|
for (int i = 0; i < endpoints.Count; i++)
|
|
{
|
|
endpoints[i].EndpointUrl = discoveryUrl.ToString();
|
|
if ((endpoints[i].Server.ApplicationName.Text.IndexOf( ProgID)>-1)
|
|
&& (endpoints[i].SecurityMode == MessageSecurityMode.None))//20151120
|
|
{
|
|
m_Server = new Server();
|
|
m_Server.CertificateEvent += new certificateValidation(m_Server_CertificateEvent);
|
|
m_Server.Connect(endpoints[i]);
|
|
_IfConnectOPCServer = true;
|
|
if (m_Subscription == null)
|
|
{
|
|
m_Subscription = m_Server.AddSubscription(100);
|
|
}
|
|
#region 自动读取“S7:”的命名空间索引//20151120
|
|
|
|
DataValueCollection m_currentValues;
|
|
NodeId nodeId=new NodeId(2255);
|
|
NodeIdCollection nodesToRead = new NodeIdCollection(1);
|
|
nodesToRead.Add(nodeId);
|
|
m_Server.ReadValues(nodesToRead, out m_currentValues);
|
|
if (m_currentValues.Count > 0)
|
|
{
|
|
string[] arr;
|
|
arr =(string[]) m_currentValues[0].Value;
|
|
S7NameSpace =(ushort) Array.IndexOf(arr, "S7:");
|
|
|
|
}
|
|
#endregion
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726
|
|
{
|
|
ConnectCount.Add(_PLCconnectionID, 0);
|
|
}
|
|
ConnectCount[_PLCconnectionID]++;
|
|
OpcError = "连接OPC数据存取服务器时:配置项OPCProgID和HostName不准确!";
|
|
_IfConnectOPCServer = false;
|
|
return false;
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726
|
|
{
|
|
ConnectCount.Add(_PLCconnectionID, 0);
|
|
}
|
|
ConnectCount[_PLCconnectionID]++;
|
|
OpcError = "连接OPC数据存取服务器时:" + ex.Message;
|
|
_IfConnectOPCServer = false;
|
|
return false;
|
|
}
|
|
|
|
}
|
|
public static DataValueCollection SyncReadAllItemValue(StringBuilder[] itemnames)
|
|
{
|
|
DataValueCollection m_currentValues;
|
|
if (_IfConnectOPCServer == false)
|
|
{
|
|
if (ConnectOPCServer(_hostname, _progID) == false) return null;
|
|
}
|
|
|
|
NodeIdCollection nodesToRead = new NodeIdCollection(itemnames.GetLength(0));
|
|
|
|
foreach (StringBuilder item in itemnames)
|
|
{
|
|
// NodeIds.
|
|
String sNodeId = _PLCconnectionID + "." + item.ToString();
|
|
NodeId nodeId = new NodeId(sNodeId,S7NameSpace);//20151120
|
|
nodesToRead.Add(nodeId);
|
|
}
|
|
|
|
// Call to ClientAPI.
|
|
m_Server.ReadValues(
|
|
nodesToRead,
|
|
out m_currentValues);
|
|
return m_currentValues;
|
|
}
|
|
public static bool SyncWriteAllItemValue(StringBuilder[] itemnames, StringBuilder[] itemvalues)
|
|
{
|
|
try
|
|
{
|
|
if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726
|
|
{
|
|
ConnectCount.Add(_PLCconnectionID, 0);
|
|
}
|
|
if (ConnectCount[_PLCconnectionID] > 1)//20150204
|
|
{
|
|
return false;
|
|
}
|
|
if (_IfConnectOPCServer == false)
|
|
{
|
|
if (ConnectOPCServer(_hostname, _progID) == false) return false;
|
|
}
|
|
|
|
NodeIdCollection nodesToWrite = new NodeIdCollection(itemnames.GetLength(0));
|
|
DataValueCollection values = new DataValueCollection(itemnames.GetLength(0));
|
|
StatusCodeCollection results = null;
|
|
int i = 0;
|
|
|
|
foreach (StringBuilder item in itemnames)
|
|
{
|
|
// Values to write.
|
|
String sValue = itemvalues[i].ToString();
|
|
|
|
// Leave current value if write value is empty.
|
|
if (sValue.Length == 0)
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
#region win7等64位操作系统需要指定确切的数据类型//20151120
|
|
|
|
Type gt = typeof(byte);
|
|
if (item.ToString().IndexOf(",b") >= 0)//无符号字节型0--255
|
|
{
|
|
gt = typeof(byte);
|
|
}
|
|
else if (item.ToString().IndexOf(",i") >= 0)//short:有符号两个字节的单字-32768至32767
|
|
{
|
|
gt = typeof(short);
|
|
}
|
|
else if (item.ToString().IndexOf(",w") >= 0)//ushort:无符号两个字节的单字0至65535
|
|
{
|
|
gt = typeof(ushort);
|
|
}
|
|
else if (item.ToString().IndexOf(",di") >= 0)//int:有符号四个字节的双字-2147483648至2147483647
|
|
{
|
|
gt = typeof(int);
|
|
}
|
|
else if (item.ToString().IndexOf(",dw") >= 0)//uint:无符号四个字节的双字0至4294967295
|
|
{
|
|
gt = typeof(uint);
|
|
}
|
|
else if (item.ToString().IndexOf(",dt") >= 0)//DateTime:日期和时间类型:05/31/2016 08:21:10.123 PM
|
|
{
|
|
gt = typeof(DateTime);
|
|
}
|
|
|
|
Variant variant = new Variant(Convert.ChangeType(sValue, gt));
|
|
#endregion
|
|
|
|
DataValue value = new DataValue(variant);
|
|
values.Add(value);
|
|
|
|
// NodeIds.
|
|
String sNodeId =_PLCconnectionID+"."+ item.ToString();
|
|
NodeId nodeId = new NodeId(sNodeId, S7NameSpace); //20151120
|
|
nodesToWrite.Add(nodeId);
|
|
|
|
i++;
|
|
}
|
|
|
|
// Call to ClientAPI.
|
|
m_Server.WriteValues(
|
|
nodesToWrite,
|
|
values,
|
|
out results);
|
|
int ia = 0;//richard.liu20141110
|
|
foreach (StatusCode sc in results)
|
|
{//richard.liu20141110
|
|
if (sc.Code != StatusCodes.Good)
|
|
{
|
|
ConnectCount[_PLCconnectionID]++;//20150204
|
|
OpcError =string.Format( "向OPC数据存取服务器写数据时,WriteValues:{0},{1}" ,nodesToWrite[ia].ToString() , "的返回值有错误!"+sc.ToString());
|
|
return false;
|
|
}
|
|
ia++;
|
|
}
|
|
ConnectCount[_PLCconnectionID] = 0;//20150204
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConnectCount[_PLCconnectionID]++;//20150204
|
|
OpcError =string.Format( "向OPC数据存取服务器写数据时:{0},{1}" , ex.Message,ex.StackTrace);
|
|
_IfConnectOPCServer = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//以异步的方式写入OPC数据
|
|
public static bool AsyncWriteAllItemValue(string _PLCconnectionID,StringBuilder[] itemnames, StringBuilder[] itemvalues)
|
|
{
|
|
lock (thisLock)////20130306richard.liu
|
|
{
|
|
try
|
|
{
|
|
if (_IfConnectOPCServer == false)
|
|
{
|
|
if (ConnectOPCServer(_hostname, _progID) == false) return false;
|
|
}
|
|
if (ConnectCount.ContainsKey(_PLCconnectionID) == false)//20110726
|
|
{
|
|
ConnectCount.Add(_PLCconnectionID, 0);
|
|
}
|
|
if (ConnectCount[_PLCconnectionID] > 3)//20150204
|
|
{
|
|
_opcError = "写数据时:OPC Server没连接到PLC:" + _PLCconnectionID.ToString() + ",人工确认后进行【PLC初始化】";//20150204
|
|
return false;
|
|
}
|
|
NodeIdCollection nodesToWrite = new NodeIdCollection(itemnames.GetLength(0));
|
|
DataValueCollection values = new DataValueCollection(itemnames.GetLength(0));
|
|
StatusCodeCollection results = null;
|
|
int i = 0;
|
|
|
|
foreach (StringBuilder item in itemnames)
|
|
{
|
|
// Values to write.
|
|
String sValue = itemvalues[i].ToString();
|
|
|
|
// Leave current value if write value is empty.
|
|
if (sValue.Length == 0)
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
#region win7等64位操作系统需要指定确切的数据类型//20151120
|
|
|
|
Type gt = typeof(byte);
|
|
if (item.ToString().IndexOf(",b") >= 0)//无符号字节型0--255
|
|
{
|
|
gt = typeof(byte);
|
|
}
|
|
else if (item.ToString().IndexOf(",i") >= 0)//short:有符号两个字节的单字-32768至32767
|
|
{
|
|
gt = typeof(short);
|
|
}
|
|
else if (item.ToString().IndexOf(",w") >= 0)//ushort:无符号两个字节的单字0至65535
|
|
{
|
|
gt = typeof(ushort);
|
|
}
|
|
else if (item.ToString().IndexOf(",di") >= 0)//int:有符号四个字节的双字-2147483648至2147483647
|
|
{
|
|
gt = typeof(int);
|
|
}
|
|
else if (item.ToString().IndexOf(",dw") >= 0)//uint:无符号四个字节的双字0至4294967295
|
|
{
|
|
gt = typeof(uint);
|
|
}
|
|
else if (item.ToString().IndexOf(",dt") >= 0)//DateTime:日期和时间类型:05/31/2016 08:21:10.123 PM
|
|
{
|
|
gt = typeof(DateTime);
|
|
}
|
|
|
|
Variant variant = new Variant(Convert.ChangeType(sValue, gt));
|
|
#endregion
|
|
|
|
DataValue value = new DataValue(variant);
|
|
values.Add(value);
|
|
|
|
// NodeIds.
|
|
String sNodeId = _PLCconnectionID + "." + item.ToString();
|
|
NodeId nodeId = new NodeId(sNodeId, S7NameSpace); //20151120
|
|
nodesToWrite.Add(nodeId);
|
|
|
|
i++;
|
|
}
|
|
|
|
// Call to ClientAPI.
|
|
m_Server.BeginWriteValues(
|
|
nodesToWrite,
|
|
values,
|
|
out results);
|
|
//results返回值一直为null,异常在ClientAPI writeCallBack处理后赋给OpcError
|
|
ConnectCount[_PLCconnectionID] = 0;//20150204
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConnectCount[_PLCconnectionID]++;//20150204
|
|
OpcError =string.Format( "向OPC数据存取服务器写数据时:{0},{1}", ex.Message,ex.StackTrace);
|
|
_IfConnectOPCServer = false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获得设备类型索引
|
|
/// </summary>
|
|
/// <param name="devIdx">设备索引</param>
|
|
/// <returns>设备类型索引</returns>
|
|
static int GetDeviceKindIdx(int devIdx)
|
|
{
|
|
System.Object lockThis = new System.Object();
|
|
lock (lockThis)
|
|
{
|
|
try
|
|
{
|
|
|
|
DataView dv= dbo.ExceSQL(string.Format("SELECT F_DeviceKindIndex FROM T_Base_Device WHERE F_DeviceIndex={0}", devIdx)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
return System.Convert.ToInt32(dv[0]["F_DeviceKindIndex"]);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
}
|
|
}
|
|
public static void DisConnectOPCServer()
|
|
{
|
|
try
|
|
{
|
|
int result;
|
|
if (m_Server == null) return;
|
|
|
|
|
|
result = m_Server.Disconnect();
|
|
|
|
// Disconnect succeeded.
|
|
if (result == 0)
|
|
{
|
|
m_Subscription.RemoveAllMonitoredItems();//20150103增加断网恢复
|
|
m_Server.RemoveSubscription(m_Subscription);
|
|
m_Subscription = null;
|
|
}
|
|
_IfConnectOPCServer = false;//20140514张博在山东电力发现此问题
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
OpcError = "关闭OPC数据存取服务器时:" + ex.Message;
|
|
}
|
|
}
|
|
static void m_Server_CertificateEvent(CertificateValidator validator, CertificateValidationEventArgs e)
|
|
{
|
|
e.Accept = true;
|
|
|
|
}
|
|
}
|
|
}
|