天津康师傅调度系统
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.

597 lines
23 KiB

1 month ago
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Data;
using DBFactory;
using CommonLib;
using Snap7;
using System.Runtime.InteropServices;
using System.Linq;
using System.Collections;
using System.Reflection;
namespace Snap7Client
{
public static class CCommonSnap7Client
{
private static Object obj = new Object();
public static event CDataSourceChangeEventHandler DataChange;
public static event CUpdateDBEventHandler UpdateDB;
public static event CWriteDarkCasketEventHandler WriteDarkCasket;
public static event CSendDeviceOrderEventHandler SendDeviceOrder;
public static void OnSendDeviceOrder(CSendDeviceOrderEventArgs e)
{
if (SendDeviceOrder != null)
{
SendDeviceOrder(null, e);
}
}
public static void OnWriteDarkCasket(CWriteDarkCasketEventArgs e)
{
if (WriteDarkCasket != null)
{
WriteDarkCasket(null, e);
}
}
public static void OnDataChange(CDataChangeEventArgs e)
{
if (DataChange != null)
{
DataChange(null, e);
}
}
public static void OnUpdateDB(object sender, CUpdateDBChangeEventArgs e)
{
if (UpdateDB != null)
{
UpdateDB(sender, e);
}
}
public static event RefreshMonitorEventHandler RefreshMonitor;
public static void OnRefreshMonitor(RefreshMonitorEventArgs e)
{
if (RefreshMonitor != null)
{
RefreshMonitor(e);
}
}
public static DBOperator dbo = new DBOperator();//20130926
static StringBuilder sql = new StringBuilder();
// 存放每个 PLC 的 client 是否连接
static Dictionary<string, bool> _ifConnect = new Dictionary<string, bool>();
public static Dictionary<string, bool> IfConnect
{
get { return CCommonSnap7Client._ifConnect; }
set
{
DataView dv = dbo.ExceSQL("SELECT DISTINCT F_RemoteIP, F_Slot, F_Rack FROM T_Base_Device WHERE (F_CommType = 'Snap7Client' and F_RemoteIP is not null)").Tables[0].DefaultView;
for (int i = 0; i < dv.Count; i++)
{
if (value.ContainsKey(dv[i][0].ToString()) == false)
{
value.Add(dv[i][0].ToString(), false);
}
}
CCommonSnap7Client._ifConnect = value;
}
}
// 存放每个 PLC 的 s7.client
static Dictionary<string, S7Client> _snap7Clients = new Dictionary<string, S7Client>();
internal static Dictionary<string, S7Client> Snap7Clients { get => _snap7Clients; set => _snap7Clients = value; }
// 存放每个 PLC DB2 的所有数据,记录的是最近一次读取的 PLC DB2 数据
static Dictionary<string, byte[]> _DB2DeviceHisBuff = new Dictionary<string, byte[]>();
public static Dictionary<string, byte[]> DB2DeviceHisBuff { get => _DB2DeviceHisBuff; set => _DB2DeviceHisBuff = value; }
// 存放每个 PLC 本次读取的数据
static Dictionary<string, byte[]> _PLCReadBuff = new Dictionary<string, byte[]>();
public static Dictionary<string, byte[]> PLCReadBuff { get => _PLCReadBuff; set => _PLCReadBuff = value; }
// 在每个 PLC 的异步读写前,判断是否有其他异步操作未完成,有未完成的则值为 false;没有则值为 true,可以进行异步
static Dictionary<string, bool> _plcIsAsyncDone = new Dictionary<string, bool>();
public static Dictionary<string, bool> PlcIsAsyncDone { get => _plcIsAsyncDone; set => _plcIsAsyncDone = value; }
static string _snap7Error;
public static string Snap7Error
{
get { return _snap7Error; }
set
{
_snap7Error = value;
RefreshMonitorEventArgs rea = new RefreshMonitorEventArgs("tsStatus", string.Format("Snap7:{0}", _snap7Error));
OnRefreshMonitor(rea);
}
}
private static S7Client.S7CliCompletion CallBack = new S7Client.S7CliCompletion(CompletionProc);
public static void EndConnect()
{
try
{
foreach (var ip in Snap7Clients.Keys)
{
IfConnect[ip] = false;
Snap7Clients[ip].Disconnect();
}
temp.Enabled = false; //是否执行System.Timers.Timer.Elapsed事件;
}catch (Exception e)
{
return ;
}
}
private static System.Timers.Timer temp = new System.Timers.Timer();
//初始化所有的PLC连接
public static void InitAllClientSnap7()
{
try
{
DataView dv = dbo.ExceSQL("SELECT DISTINCT F_RemoteIP FROM T_Base_Device WHERE ( F_RemoteIP is not null)").Tables[0].DefaultView;
#region 将所有的 PLC 添加到 SnapyClients 中
for (int i = 0; i < dv.Count; i++)
{
InitClientSnap7(dv[i]["F_RemoteIP"].ToString());
}
#endregion
if (Snap7Clients.Count == 0)
return;
#region 设置定时器,定时去读取 PLC
temp.Elapsed += new System.Timers.ElapsedEventHandler(Async_Read); //到达时间的时候执行事件;
temp.Interval = 1000;
temp.AutoReset = true; //设置是执行一次(false)还是一直执行(true);
temp.Enabled = true; //是否执行System.Timers.Timer.Elapsed事件;
#endregion
}
catch (Exception e)
{
Snap7Error = "Snap7Client.InitClientSnap7:" + e.StackTrace + e.Message;
}
}
public static bool InitClientSnap7(string clientName)
{
if (IfConnect.ContainsKey(clientName) == false)
{
IfConnect.Add(clientName, false);
}
if (PlcIsAsyncDone.ContainsKey(clientName) == false)
{
PlcIsAsyncDone.Add(clientName, true);
}
if (IfConnect[clientName] == true)
{
return true;
}
if (Snap7Clients.ContainsKey(clientName) == true)
{
// 如果已存在客户端,则重新连接,连接成功,即可返回,否则需要进行 new client
if (Snap7Clients[clientName].Connect() == 0)
{
IfConnect[clientName] = true;
return true;
}
else
{
IfConnect[clientName] = false;
return false;
}
}
try
{
#region 为 S7Client 建立连接
// Connect to the PLC.
string[] group = clientName.Split(':');
if (group.Length != 3)
return false;
string remoteIP = group[0];
int rack = Convert.ToInt32(group[1]);
int slot = Convert.ToInt32(group[2]);
string[] group1 = remoteIP.Split('.');
string temp = "";
foreach(string t in group1)
{
temp += t;
}
S7Client myClient = new S7Client();
myClient.SetAsCallBack(CallBack, new IntPtr(Convert.ToInt32(temp)));
int result = myClient.ConnectTo(remoteIP, rack, slot);
if (result != 0)
{
return false;
}
#endregion
if (Snap7Clients.ContainsKey(clientName) == false)
{
Snap7Clients.Add(clientName, myClient);
}
IfConnect[clientName] = true;
#region 初始化每个设备的历史缓存
DataView dv = dbo.ExceSQL("SELECT F_DeviceIndex, F_DBWGetLength FROM T_Base_Device WHERE ( F_RemoteIP = '" + clientName +"' )").Tables[0].DefaultView;
for (int i = 0; i < dv.Count; i++)
{
DB2DeviceHisBuff.Add(dv[i]["F_DeviceIndex"].ToString(), new byte[Convert.ToInt32(Convert.ToDouble(dv[i]["F_DBWGetLength"]))]);
}
PLCReadBuff.Add(clientName, new byte[GetDB2Length(clientName)]);
#endregion
int[] chatnew;
chatnew = new int[1];
CWriteDarkCasketEventArgs e0 = new CWriteDarkCasketEventArgs("CClientSnap7.InitClientSnap7", "Connect", clientName, "连接 PLC 成功", chatnew);
OnWriteDarkCasket(e0);
return IfConnect[clientName];
}
catch (Exception e)
{
IfConnect[clientName] = false;
Snap7Error = "CClientSnap7.InitClientSnap7:" + e.StackTrace + e.Message;
return false;
}
}
//异步读或写完成后,会进入此方法
static void CompletionProc(IntPtr usrPtr, int opCode, int opResult)
{
string remoteIP = "";
if (opResult == 0) //异步读写成功
{
#region 确定是哪个 PLC 发起的回调函数
foreach (string ip in Snap7Clients.Keys)
{
string[] group = ip.Split(':')[0].Split('.');
string tt = "";
foreach (string t in group)
{
tt += t;
}
if (tt == usrPtr.ToString())
{
remoteIP = ip;
}
}
if (remoteIP == "") return;
#endregion
#region 异步读回调处理
if (opCode == 1)
{
try
{
foreach (string ip in Snap7Clients.Keys)
{
if (ip == remoteIP)
{
DataView dv = dbo.ExceSQL("SELECT F_DeviceIndex, F_DBW2Address, F_DBWGetLength FROM T_Base_Device WHERE(F_RemoteIP LIKE '" + remoteIP + "%') ORDER BY F_DeviceIndex ").Tables[0].DefaultView;
//DataView dv = dbo.ExceSQL("SELECT F_DBW2Address, F_DBWGetLength FROM T_Base_Device WHERE (F_RemoteIP = '"+ remoteIP + "')").Tables[0].DefaultView;
int length;
int start;
string device;
for (int i = 0; i < dv.Count; i++)
{
device = dv[i]["F_DeviceIndex"].ToString();
if (dv[i]["F_DBW2Address"] == DBNull.Value) continue;
start = Convert.ToInt32(dv[i]["F_DBW2Address"]);
length = Convert.ToInt32(Convert.ToDouble(dv[i]["F_DBWGetLength"]));
byte[] buff = new Byte[length];
Array.Copy(PLCReadBuff[remoteIP], start, buff, 0, length);
//if (DB2DeviceHisBuff.ContainsKey(device) == false)
//{
//}
bool flag = Enumerable.SequenceEqual(buff, DB2DeviceHisBuff[device]);
if (!flag)
{
Array.Copy(buff, DB2DeviceHisBuff[device], buff.Length);
CUpdateDBChangeEventArgs udbe = new CUpdateDBChangeEventArgs(Convert.ToInt32(device), null, buff);
CCommonSnap7Client.OnUpdateDB("Snap7Client.CCommonSnap7Client.OnDataChange", udbe);
int[] chatnew;
chatnew = new int[1];
CWriteDarkCasketEventArgs e0 = new CWriteDarkCasketEventArgs("Snap7Client.CCommonSnap7Client:", "Read", device.ToString(), "读取成功", chatnew);
CCommonSnap7Client.OnWriteDarkCasket(e0);
}
}
}
}
}
catch (Exception e)
{
}
finally
{
//AsyncDone = true;
}
}
#endregion
#region 异步写回调处理
else if (opCode == 2)
{
;
}
#endregion
else
{
//
}
}
else
{
// 异步读取失败
#region 写入黑匣子
#endregion
}
//lock (obj)
//{
PlcIsAsyncDone[remoteIP] = true;
//}
}
public static bool AsyncWriteAllItemValue(StringBuilder[] itemnames, StringBuilder[] itemvalues)
{
try
{
#region 找到要写入的设备所在的 PLC
string db1Address = itemnames[0].ToString().Split('.')[1].Split(',')[0] ;
string clientName = "";
DataView dv = dbo.ExceSQL("SELECT F_RemoteIP FROM T_Base_Device WHERE (F_DBW1Address = '"+ db1Address + "' )").Tables[0].DefaultView;
if (dv.Count <= 0) return false;
for (int i = 0; i < dv.Count; i++)
{
clientName = dv[0]["F_RemoteIP"].ToString();
}
#endregion
byte[] tttt = new byte[GetDB1Length(clientName)];
var values = new List<Tuple<Type, string>>();
var nodesToWrite = new List<String>();
for (int i = 0; i < itemnames.Length; i++)
{
// Values to write.
string item = itemnames[i].ToString();
String sValue = itemvalues[i].ToString();
// Leave current value if write value is empty.
if (sValue.Length == 0)
{
continue;
}
#region 将要写入的数据通过 S7 进行转换成 BYTE 数组
object[] para = new object[3];
para[0] = tttt;
para[1] = Convert.ToInt32(item.ToString().Split('.')[1].Split(',')[0]);
string funcName = "";
if (item.ToString().IndexOf(",b") >= 0)//无符号字节型0--255
{
funcName = "SetUSIntAt"; //SetByteAt
para[2] = Convert.ToByte(sValue);
}
else if (item.ToString().IndexOf(",i") >= 0)//short:有符号两个字节的单字-32768至32767
{
funcName = "SetIntAt";
para[2] = Convert.ToInt16(sValue);
}
else if (item.ToString().IndexOf(",w") >= 0)//ushort:无符号两个字节的单字0至65535
{
funcName = "SetUIntAt";
para[2] = Convert.ToUInt16(sValue);
}
else if (item.ToString().IndexOf(",di") >= 0)//int:有符号四个字节的双字-2147483648至2147483647
{
funcName = "SetDIntAt";
para[2] = Convert.ToInt32(sValue);
}
else if (item.ToString().IndexOf(",dw") >= 0)//uint:无符号四个字节的双字0至4294967295
{
funcName = "SetUDIntAt";
para[2] = Convert.ToUInt32(sValue);
}
else if (item.ToString().IndexOf(",dt") >= 0)//DateTime:日期和时间类型:05/31/2016 08:21:10.123 PM
{
}
Type t = typeof(S7);
string[] _args = { "XXX" };
object result = t.InvokeMember(funcName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, para);
#endregion
}
if (IfConnect[clientName] == true)
{
byte[] buffer = new byte[GetDB1Length(clientName)];
S7Client client = Snap7Clients[clientName];
int num = 0;
#region 和 AsRead 抢占资源,如果两秒中没有抢到则失败
while(PlcIsAsyncDone[clientName] == false)
{
System.Threading.Thread.Sleep(20);
num++;
if (num > 100)
return false;
}
#endregion
if (PlcIsAsyncDone[clientName] == true)
{
//lock (obj)
//{
int res = client.AsDBWrite(1, 0, tttt.Length, tttt);
if (res == 0)
{
PlcIsAsyncDone[clientName] = false;
}
else if (res == 0x00300000)
{
return false;
}
else
{
PlcIsAsyncDone[clientName] = true;
IfConnect[clientName] = false;
InitClientSnap7(clientName);
}
}
}
else
{
PlcIsAsyncDone[clientName] = true;
IfConnect[clientName] = false;
InitClientSnap7(clientName);
}
return true;
}
catch (Exception ex)
{
Snap7Error = "向Snap7数据存取服务器写数据时:" + ex.Message;
//_IfConnectSnap7Server = false;
return false;
}
}
public static void Async_Read(object sender, System.Timers.ElapsedEventArgs e)
{
temp.Enabled = false;
try
{
if (Snap7Clients.Count == 0) return;
foreach (string ip in Snap7Clients.Keys)
{
if (IfConnect[ip] == true)
{
byte[] buffer = new byte[GetDB2Length(ip)];
S7Client client = Snap7Clients[ip];
if (PlcIsAsyncDone[ip] == true)
{
//lock (obj)
//{
int result = client.AsDBRead(2, 0, PLCReadBuff[ip].Length, PLCReadBuff[ip]);
if (result == 0)
{
PlcIsAsyncDone[ip] = false;
}
else if (result == 0x00300000)
{
return;
}
else
{
PlcIsAsyncDone[ip] = true;
IfConnect[ip] = false;
InitClientSnap7(ip);
}
}
}
else
{
PlcIsAsyncDone[ip] = true;
IfConnect[ip] = false;
InitClientSnap7(ip);
}
}
}
catch (Exception)
{
int i = 0;
}
finally
{
//myTimer.Enabled = true;
}
temp.Enabled = true;
}
public static int GetDB2Length(string remoteIP)
{
try
{
sql.Remove(0, sql.Length);
sql.Append("SELECT MAX(F_DBW2Address) AS db_end, MIN(F_DBW2Address) AS db_start FROM T_Base_Device where F_RemoteIP = '" + remoteIP + "'");
DataView dv = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
sql.Remove(0, sql.Length);
sql.Append("SELECT F_DBWGetLength FROM T_Base_Device WHERE F_DBW2Address = " + dv[0]["db_end"]);
DataView dvt = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
int length = Convert.ToInt32(dvt[0]["F_DBWGetLength"]) + Convert.ToInt32(dv[0]["db_end"]) - Convert.ToInt32(dv[0]["db_start"]);
return length;
}
catch(Exception e)
{
return 0;
}
}
public static int GetDB1Length(string remoteIP)
{
try
{
sql.Remove(0, sql.Length);
sql.Append("SELECT MAX(F_DBW1Address) AS db_end, MIN(F_DBW1Address) AS db_start FROM T_Base_Device where F_RemoteIP = '" + remoteIP + "'");
DataView dv = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
sql.Remove(0, sql.Length);
sql.Append("SELECT F_DBWSendLength FROM T_Base_Device WHERE F_DBW1Address = " + dv[0]["db_end"]);
DataView dvt = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
int length = Convert.ToInt32(dvt[0]["F_DBWSendLength"]) + Convert.ToInt32(dv[0]["db_end"]) - Convert.ToInt32(dv[0]["db_start"]);
//DataView dv = dbo.ExceSQL("SELECT F_DBW1Address, F_DBWSendLength FROM T_Base_Device WHERE(F_RemoteIP LIKE '" + remoteIP + "%') ORDER BY F_DBW1Address desc").Tables[0].DefaultView;
return length;
}
catch (Exception e)
{
return 0;
}
}
}
}