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.
1692 lines
67 KiB
1692 lines
67 KiB
using CommonLib;
|
|
using DBFactory;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Net.NetworkInformation;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace FINSTCPIP
|
|
{
|
|
|
|
|
|
public class ClientCommunication
|
|
{
|
|
public static event CWriteDarkCasketEventHandler WriteDarkCasket;
|
|
|
|
|
|
public static event RefreshMonitorEventHandler RefreshMonitor;
|
|
public static void OnRefreshMonitor(RefreshMonitorEventArgs e)
|
|
{
|
|
if (RefreshMonitor != null)
|
|
{
|
|
RefreshMonitor(e);
|
|
}
|
|
}
|
|
static string _finsError;
|
|
public static string FINSError
|
|
{
|
|
get { return _finsError; }
|
|
set
|
|
{
|
|
_finsError = value;
|
|
RefreshMonitorEventArgs rea = new RefreshMonitorEventArgs("tsStatus", string.Format("FINSTCPIP.ClientCommunication:{0}", _finsError));
|
|
|
|
OnRefreshMonitor(rea);
|
|
}
|
|
}
|
|
|
|
public const int MODBUS = 1; //Modbus协议
|
|
public const int FINS = 2; //FINS协议
|
|
|
|
//和plc通讯的socket,包含了接包、发包、
|
|
public static Dictionary<string, TcpSocket> socketFinss = new Dictionary<string, TcpSocket>();
|
|
|
|
//每个PLC通信时需要的 FINS 信息,用来从FINS包中提取数据,发送数据时添加FINS包装
|
|
public static Dictionary<string, FINSParse> clientFinss = new Dictionary<string, FINSParse>();
|
|
|
|
public static Dictionary<string, int> connectTimes = new Dictionary<string, int>();//socket的连接次数,连接成功时置0
|
|
|
|
public static Dictionary<string, List<byte>> buffer = new Dictionary<string, List<byte>>();//每个socket的buffer
|
|
|
|
public static Dictionary<string, byte[]> SC_RGV_READ_DATA = new Dictionary<string, byte[]>(); //世仓穿梭板读取车状态:发送包(FINS连接成功时添加)
|
|
|
|
static StringBuilder sql = new StringBuilder();
|
|
|
|
public static Dictionary<string, SHICANGReadData> lastReadMessage = new Dictionary<string, SHICANGReadData>();//上一次发生变化后,收到的信息
|
|
public static DBOperator dbo = CClientTCPIP.dbo;
|
|
public static DBOperator dboM = CClientTCPIP.dboM;
|
|
|
|
static Model.MDevice devinfo;
|
|
|
|
public static void InitAllClientTCPIP()
|
|
{
|
|
DataView dv = new DataView(); DataView dvs = new DataView();
|
|
string ip = string.Empty;
|
|
int port = 9600;
|
|
try
|
|
{
|
|
#region 从数据库中读取需要充电的电量
|
|
dv = dbo.ExceSQL("SELECT F_bettey_low FROM T_base_rgvInfo ").Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
SHICANGProtocol.NeedToBettey = Convert.ToInt32(dv[0]["F_bettey_low"]);
|
|
}
|
|
#endregion
|
|
|
|
//V_RGVInfo不包含禁用的穿梭车
|
|
dvs = dbo.ExceSQL("SELECT F_DeviceIndex, F_RemoteIP,F_RemotePort FROM V_RGVINFO ").Tables[0].DefaultView;
|
|
for (int i = 0; i < dvs.Count; i++)
|
|
{
|
|
ip = dvs[i]["F_RemoteIP"].ToString();
|
|
port = Convert.ToInt32(dvs[i]["F_RemotePort"]);
|
|
|
|
//前10次连接间隔10秒(timer),之后60秒连接一次
|
|
if (connectTimes.ContainsKey(ip) == true)
|
|
{
|
|
if (connectTimes[ip] > 10)
|
|
{
|
|
int rgv = Convert.ToInt32(dvs[i]["F_DeviceIndex"]);
|
|
|
|
#region 和数据库中记录的时间小于一分钟
|
|
sql.Clear();
|
|
sql.Append("select F_Time from V_RGVINFO where F_DeviceIndex =").Append(rgv);
|
|
dv = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
DateTime appdt = DateTime.Now.AddSeconds(-10); ;
|
|
DateTime.TryParse(dv[0]["F_Time"].ToString(), out appdt);
|
|
if ((appdt.AddSeconds(60) > DateTime.Now))
|
|
{
|
|
//数据库中记录的时间小于当前一分钟
|
|
//UpdateTime(rgv);
|
|
continue;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
UpdateTime(rgv);
|
|
//continue;
|
|
}
|
|
}
|
|
if (FINSTCPIP.SHICANGProtocol.ShuttleConnected(ip) == false)
|
|
{
|
|
Task.Run(async () =>
|
|
{
|
|
await ClientCommunication.Open(ip, port, FINS);
|
|
});
|
|
System.Threading.Thread.Sleep(200);
|
|
}
|
|
//if (clientFinss.ContainsKey(ip) == false)
|
|
//{
|
|
// Task.Run(async () =>
|
|
// {
|
|
// await ClientCommunication.Open(ip, port, FINS);
|
|
// });
|
|
// System.Threading.Thread.Sleep(50);
|
|
//}
|
|
//else if (clientFinss[ip]._ifIniting == false)
|
|
//{
|
|
|
|
// Task.Run(async () =>
|
|
// {
|
|
// await ClientCommunication.Open(ip, port, FINS);
|
|
// });
|
|
// System.Threading.Thread.Sleep(50);
|
|
//}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
FINSError = e.StackTrace + e.Message;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public static void CloseAllClient()
|
|
{
|
|
foreach(var ip in socketFinss.Keys)
|
|
{
|
|
if (clientFinss[ip]._socketConnected == true)
|
|
{
|
|
clientFinss[ip]._socketConnected = false;
|
|
clientFinss[ip]._finsConnected = false;
|
|
clientFinss[ip]._ifIniting = false;
|
|
|
|
socketFinss[ip].Close(); //只要关闭socket连接即可,无需再关闭fins连接
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private const int DelayTime = 500;
|
|
public static readonly Object thisLock = new Object();
|
|
public static async Task Open(string ip, int port, int protocol = MODBUS)
|
|
{
|
|
await Task.Run(() =>
|
|
{
|
|
|
|
if (clientFinss.ContainsKey(ip) == true)
|
|
{
|
|
if (clientFinss[ip]._ifIniting == true)
|
|
{
|
|
//有其他线程正在进行初始化连接
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//没有其他线程正在初始化,本线程准备进入初始化
|
|
}
|
|
|
|
if (clientFinss[ip]._socketConnected == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//新添加的
|
|
if (clientFinss[ip]._finsConnected == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
FINSParse fp = new FINSParse();
|
|
//本线程进入初始化工作
|
|
fp._ifIniting = true;
|
|
clientFinss.Add(ip, fp);
|
|
List<byte> te = new List<byte>();
|
|
buffer.Add(ip, te );
|
|
}
|
|
|
|
clientFinss[ip]._ifIniting = true;
|
|
|
|
if (connectTimes.ContainsKey(ip) == false)
|
|
{
|
|
connectTimes.Add(ip, 0);
|
|
}
|
|
//else
|
|
//{
|
|
// connectTimes[ip] += 1;
|
|
//}
|
|
|
|
int shuttle = CClientTCPIP.GetAGVServer(ip);
|
|
|
|
int[] chatnew;
|
|
chatnew = new int[1];
|
|
|
|
#region 判断网络是否正常
|
|
ClientCommunication.connectTimes[ip] += 1;
|
|
Ping ping = new Ping();
|
|
try
|
|
{
|
|
if (ping.Send(ip).Status != 0)
|
|
{
|
|
ClientCommunication.clientFinss[ip]._ifIniting = false;
|
|
FINSError = shuttle + ":" + ip + " 网络故障或未开机。";
|
|
return;
|
|
}
|
|
|
|
}catch
|
|
{
|
|
ClientCommunication.clientFinss[ip]._ifIniting = false;
|
|
FINSError = shuttle + ":" + ip +" 网络故障或未开机。";
|
|
}
|
|
#endregion
|
|
|
|
TcpSocket tcpsocket = new TcpSocket(ip, port, shuttle);
|
|
AddTCPSocketEvent(tcpsocket, clientFinss[ip], protocol);
|
|
|
|
if (socketFinss.ContainsKey(ip) == false)
|
|
{
|
|
socketFinss.Add(ip, tcpsocket);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
socketFinss[ip].Close();
|
|
}
|
|
catch
|
|
{
|
|
FINSError = shuttle + ":" + ip + " 断开连接失败。";
|
|
}
|
|
socketFinss[ip] = null;
|
|
socketFinss[ip] = tcpsocket;
|
|
}
|
|
|
|
CWriteDarkCasketEventArgs ee = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Open", ip, "建立socket连接", chatnew);
|
|
OnWriteDarkCasket(ee);
|
|
if (TcpSocket.thisLock.ContainsKey(ip) == false)
|
|
{
|
|
TcpSocket.thisLock.Add(ip, new object());
|
|
}
|
|
tcpsocket.Open();
|
|
|
|
|
|
Task.Run(async () =>
|
|
{
|
|
|
|
byte[] header = new byte[4];
|
|
byte[] length = new byte[4];
|
|
|
|
List<byte> bufftemp = new List<byte>();
|
|
//解析报文
|
|
while (true)
|
|
{
|
|
bufftemp.Clear();
|
|
|
|
lock (TcpSocket.thisLock[ip])
|
|
{
|
|
if (buffer[ip].Count >= 4)
|
|
{
|
|
bufftemp.AddRange(buffer[ip]);
|
|
buffer[ip].Clear();
|
|
}
|
|
|
|
}
|
|
if (bufftemp.Count == 0)
|
|
{
|
|
await Task.Delay(DelayTime);
|
|
continue;
|
|
}
|
|
|
|
bufftemp.CopyTo(0, header, 0, 4);
|
|
if (clientFinss[ip].IsHeader(header) == true)
|
|
{
|
|
//获得Length的值
|
|
bufftemp.CopyTo(4, length, 0, 4);
|
|
if (BitConverter.IsLittleEndian)
|
|
Array.Reverse(length);
|
|
int len = BitConverter.ToInt16(length, 0);
|
|
|
|
if (len == FINSParse.SHAKEHAND_RECV_LENGTH)
|
|
{//握手回复
|
|
//string err = string.Empty;
|
|
#region 握手失败
|
|
if (clientFinss[ip].IsConnectRight(bufftemp) == false)
|
|
{
|
|
CWriteDarkCasketEventArgs eee = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Open", shuttle.ToString(), "FINS连接失败,断开Socket", chatnew);
|
|
OnWriteDarkCasket(eee);
|
|
bufftemp.Clear();
|
|
|
|
clientFinss[ip]._socketConnected = false;
|
|
clientFinss[ip]._finsConnected = false;
|
|
|
|
socketFinss[ip].Close();
|
|
|
|
#region FINS 连接错误
|
|
FINSError = ip + " " + clientFinss[ip].CommLayerError;
|
|
#endregion
|
|
|
|
return;
|
|
}
|
|
#endregion
|
|
|
|
//握手成功
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Open", shuttle.ToString(), "FINS连接成功", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
bufftemp.Clear();
|
|
|
|
clientFinss[ip]._finsConnected = true;
|
|
|
|
SC_RGV_READ_DATA[ip] = ClientCommunication.clientFinss[ip].GetInfo_DMRead(2100, 30);
|
|
|
|
#region LYJL 读D2025的值
|
|
//socketFinss[ip].Send(clientFinss[ip].GetInfo_DMRead(2025, 1), null);
|
|
#endregion
|
|
|
|
|
|
}
|
|
else if (len >= FINSParse.FRAM_NODATA_RECV_LENGTH)
|
|
{//读写回复
|
|
if (clientFinss[ip].IsRecvRight(bufftemp) == false)
|
|
{
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Open", shuttle.ToString(), "接收数据错误", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
bufftemp.Clear();
|
|
FINSError = ip + " " + clientFinss[ip].CommLayerError;
|
|
|
|
await Task.Delay(DelayTime);
|
|
continue;
|
|
}
|
|
|
|
if (len > FINSParse.FRAM_NODATA_RECV_LENGTH)
|
|
{//得到数据
|
|
byte[] data = new byte[len-22]; //保存原始数据
|
|
bufftemp.CopyTo(30, data, 0, data.Length);
|
|
|
|
ushort [] newData = CClientTCPIP.ConvertByteToUInt16(data, true); //处理后的数据
|
|
|
|
if (newData.Length == 30)
|
|
{
|
|
SHICANGReadData temp = new SHICANGReadData();
|
|
temp.D2100 = newData[0];
|
|
temp.D2101 = newData[1];
|
|
temp.D2102 = newData[2];
|
|
temp.D2121 = newData[21];
|
|
temp.D2122 = newData[22];
|
|
temp.D2123 = newData[23];
|
|
temp.D2129 = newData[29];
|
|
|
|
lock (thisLock)
|
|
{
|
|
DisposeReceivedReadMessage(shuttle, temp);
|
|
}
|
|
}
|
|
else if (newData.Length == 1)
|
|
{
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(shuttle);
|
|
devinfo.XCoor = newData[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DisposeReceivedWriteMessage(shuttle);
|
|
}
|
|
bufftemp.Clear();
|
|
}
|
|
else
|
|
{
|
|
bufftemp.Clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bufftemp.Clear();
|
|
FINSError = ip + " " + clientFinss[ip].CommLayerError;
|
|
}
|
|
await Task.Delay(DelayTime);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
private static void AddTCPSocketEvent(TcpSocket tcpsocket, FINSParse fp,int protocol)
|
|
{
|
|
int[] chatnew;
|
|
chatnew = new int[1];
|
|
|
|
string ip = tcpsocket.IP;
|
|
|
|
tcpsocket.OpenSuccess += () =>
|
|
{
|
|
//Logging.Invoke("连接成功\n", 0);
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "OpenSuccess", ip, "Socket连接成功", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
tcpsocket.Receive();
|
|
connectTimes[ip] = 0;
|
|
fp._ifIniting = false;
|
|
|
|
fp._socketConnected = true;
|
|
//此处只是socket连接成功,fins连接状态不知道
|
|
|
|
#region FINS协议, socket 连接成功,先发送 FINS 的连接请求
|
|
byte[] conndata = clientFinss[ip].GetConnectInfo();
|
|
if (protocol == FINS && fp._finsConnected == false)
|
|
{
|
|
tcpsocket.Send(conndata, null);
|
|
CWriteDarkCasketEventArgs eee = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "OpenSuccess", ip, "建立FINS连接", chatnew);
|
|
OnWriteDarkCasket(eee);
|
|
}
|
|
else
|
|
{
|
|
CWriteDarkCasketEventArgs eee = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "OpenSuccess", ip, "FINS连接状态已存在", chatnew);
|
|
OnWriteDarkCasket(eee);
|
|
FINSError = ip + "FINS连接状态已存在";
|
|
}
|
|
#endregion
|
|
};
|
|
tcpsocket.OpenFail += async (ex) =>
|
|
{
|
|
connectTimes[ip] += 1;
|
|
fp._ifIniting = false;
|
|
fp._socketConnected = false;
|
|
fp._finsConnected = false;
|
|
|
|
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "OpenFail", ip, "连接失败", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
await Task.Delay(100);
|
|
|
|
//连接失败,通过timer重新连接
|
|
|
|
|
|
//return;
|
|
};
|
|
tcpsocket.Disconnect += async (ex) =>
|
|
{
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Disconnect", ip, "连接断开", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
|
|
connectTimes[ip] += 1;
|
|
|
|
if (connectTimes[ip] >= 3)
|
|
{
|
|
fp._ifIniting = false;
|
|
fp._socketConnected = false;
|
|
fp._finsConnected = false;
|
|
|
|
tcpsocket.Close();
|
|
await Task.Delay(100);
|
|
|
|
}
|
|
};
|
|
|
|
tcpsocket.ReceiveSuccess += (bytes) =>
|
|
{
|
|
//if (ip == "192.168.0.232")
|
|
{
|
|
lock (TcpSocket.thisLock[ip])
|
|
{
|
|
buffer[ip].AddRange(bytes);
|
|
}
|
|
}
|
|
|
|
};
|
|
tcpsocket.ReceiveFail += (ex) =>
|
|
{
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "ReceiveFail", ip, "接收失败", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
connectTimes[ip] += 1;
|
|
//SocketConnected[ip] = false;
|
|
};
|
|
tcpsocket.SendFail += async (ex) =>
|
|
{
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "SendFail", ip, "发送失败", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
connectTimes[ip] += 1;
|
|
await Task.Delay(100);
|
|
//if (connectTimes[ip] >= 3)
|
|
//{
|
|
// SocketConnected[ip] = false;
|
|
// FINSConnected[ip] = false;
|
|
// await Task.Delay(100);
|
|
|
|
// //socket.Open();
|
|
// //await Open(ip, port, protocol);
|
|
//}
|
|
};
|
|
tcpsocket.CloseSuccess += async () =>
|
|
{
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "CloseSuccess", ip, "断开连接成功", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
|
|
tcpsocket = null;
|
|
await Task.Delay(100);
|
|
|
|
};
|
|
tcpsocket.CloseFail += async (ex) =>
|
|
{
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "CloseFail", ip, "断开连接失败", chatnew);
|
|
OnWriteDarkCasket(e);
|
|
|
|
await Task.Delay(100);
|
|
//if (connectTimes[ip] >= 3)
|
|
//{
|
|
// SocketConnected[ip] = false;
|
|
// FINSConnected[ip] = false;
|
|
// await Task.Delay(100);
|
|
|
|
// //socket.Open();
|
|
// //await Open(ip, port, protocol);
|
|
//}
|
|
};
|
|
CClientTCPIP.SQLString(dbo, sql);
|
|
}
|
|
private static StringBuilder log = new StringBuilder();
|
|
//public static readonly Object thisLock = new Object();
|
|
/// <summary>
|
|
///处理收到的消息——读PLC数据的应答处理
|
|
/// </summary>
|
|
/// <param name="message">消息数组</param>
|
|
private static void DisposeReceivedReadMessage(int shuttle, SHICANGReadData message)
|
|
{
|
|
DataView dv = new DataView();
|
|
try
|
|
{
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(shuttle);
|
|
bool change = false; //车状态发生了变化
|
|
bool complete = false; //车的当前任务完成了
|
|
bool runing = false; //车的当前任务开始执行了
|
|
|
|
#region 状态未发生变化,只更新一下数据库的时间
|
|
if (lastReadMessage.ContainsKey(devinfo.RemoteIP) == true)
|
|
{
|
|
if (lastReadMessage[devinfo.RemoteIP].Equal(message) == false)
|
|
{
|
|
change = true;
|
|
|
|
//只有发生了变化时,才写入黑匣子
|
|
int[] ddd = new int[7] {message.D2100, message.D2101, message.D2102, message.D2121, message.D2122, message.D2123, message.D2129};
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Read", shuttle.ToString(), "读数据成功", ddd);
|
|
OnWriteDarkCasket(e);
|
|
|
|
//只有发生了变化时,才更新记录
|
|
lastReadMessage[devinfo.RemoteIP].Update(message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int[] ddd = new int[7] { message.D2100, message.D2101, message.D2102, message.D2121, message.D2122, message.D2123, message.D2129 };
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP.CConnectTCPIP", "Read", shuttle.ToString(), "读数据成功", ddd);
|
|
OnWriteDarkCasket(e);
|
|
|
|
//第一次,添加数据
|
|
lastReadMessage.Add(devinfo.RemoteIP, message);
|
|
|
|
}
|
|
#endregion
|
|
|
|
//发生变化则进行后续处理
|
|
byte[] err = new byte[32];
|
|
|
|
#region 根据车号,获取当前任务,当前位置
|
|
int fstatus = -1; int forder = -1; int fmonitorID = -1; string begintime = string.Empty;
|
|
//sql.Clear();
|
|
//sql.Append("select * from t_monitor_task where f_status <> 0 and f_deviceIndex =").Append(shuttle);
|
|
dv = dbo.ExceSQL(string.Format("select * from t_monitor_task where f_status <> 0 and f_deviceIndex ={0}", shuttle)).Tables[0].DefaultView;
|
|
if (dv.Count == 1)
|
|
{
|
|
fstatus = Convert.ToInt32(dv[0]["f_status"]);
|
|
forder = Convert.ToInt32(dv[0]["F_DeviceCommandIndex"]);
|
|
fmonitorID = Convert.ToInt32(dv[0]["F_MonitorIndex"]);
|
|
begintime = dv[0]["F_startTime"].ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region 更新内存中的车状态信息
|
|
{
|
|
#region D2100
|
|
//RunState,0-空闲,-1 非空闲
|
|
devinfo.RunState = (message.D2100 & 1) == 1 ? 0 : -1;
|
|
//AB面相叉车位, SplitByte_0 0-B面, 1-A面
|
|
devinfo.SplitByte_5 = (message.D2100 & 2) == 2 ? 1 : 0;
|
|
//有托盘位 HaveGoods 1-有货,0-无货
|
|
devinfo.SplitByte_0 = (message.D2100 & 4) == 4 ? 1 : 0;
|
|
//上/下/前/后/起升位 RunState 1-运行
|
|
if (((message.D2100 & 8) == 8) || ((message.D2100 & 16) == 16) ||
|
|
((message.D2100 & 32) == 32) || ((message.D2100 & 64) == 256))
|
|
{
|
|
devinfo.RunState = 1;
|
|
}
|
|
//存货位 , SplitByte_1 ,1-存货(时间很短,不一定能抓到)
|
|
devinfo.SplitByte_1 = (message.D2100 & 256) == 256 ? 1 : 0;
|
|
//取货位, SplitByte_2 , 1-取货(时间很短,不一定能抓到)
|
|
devinfo.SplitByte_2 = (message.D2100 & 512) == 512 ? 1 : 0;
|
|
//盘点位 ------
|
|
//模式位 , ControlMode, 0-叉车模式, 1-堆垛模式
|
|
devinfo.ControlMode = (message.D2100 & 16384) == 16384 ? 1 : 0;
|
|
//充电位 , SplitByte_3, 1-充电中
|
|
devinfo.SplitByte_3 = (message.D2100 & 32768) == 32768 ? 1 : 0;
|
|
if (devinfo.SplitByte_3 == 1)
|
|
devinfo.RunState = 0; //充电时,车状态标记为空闲,可以工作
|
|
#endregion
|
|
#region D2101
|
|
//A面障碍位,SplitByte_4 , 1-A面障碍, 0-A/B面均无障碍
|
|
if ((message.D2101 & 2) == 2)
|
|
{
|
|
devinfo.SplitByte_4 = 1;
|
|
}
|
|
else if (devinfo.SplitByte_4 == 1)
|
|
{
|
|
devinfo.SplitByte_4 = 0;
|
|
}
|
|
|
|
//B面障碍位 , SplitByte_4, 2-B面障碍, 0-A/B面均无障碍
|
|
if ((message.D2101 & 4) == 4)
|
|
{
|
|
devinfo.SplitByte_4 = 2;
|
|
}
|
|
else if (devinfo.SplitByte_4 == 2)
|
|
{
|
|
devinfo.SplitByte_4 = 0;
|
|
}
|
|
//在充电架上位 (无此状态)
|
|
//上电状态位 变化 RunState = 3 未上电状态
|
|
devinfo.RunState = (message.D2101 & 64) == 64 ? devinfo.RunState : 3;
|
|
//掉头结束位 变化 SplitByte_7
|
|
devinfo.SplitByte_7 = (message.D2101 & 128) == 128 ? 1 : 0;
|
|
//AA状态位(无此状态)
|
|
#endregion
|
|
}
|
|
//D2102 电池电量
|
|
devinfo.SplitByte = message.D2102;
|
|
|
|
//D2121,D2122 穿梭板 报警信息
|
|
err = GetError(message.D2121, message.D2122);
|
|
|
|
//D2123 禁止动作
|
|
devinfo.SplitByte_6 = message.D2123;
|
|
|
|
//D2129 执行完成的任务号
|
|
devinfo.TaskNo = message.D2129;
|
|
#endregion
|
|
|
|
#region 数据库中有已发送或执行中的任务,更新任务状态
|
|
//根据车的状态,找到了当前的唯一任务
|
|
if (fmonitorID != -1 && fmonitorID != 0 && devinfo.RunState < 2)
|
|
{
|
|
switch (forder)
|
|
{
|
|
case 1://存货/入
|
|
//任务完成的判断条件,车上报任务号,上报指令,且任务号和从数据库中获取的正在执行的任务号相同,且车空闲
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.TaskNo == fmonitorID && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (devinfo.RunState == 1 && fstatus == 1)
|
|
runing = true; //开始执务
|
|
break;
|
|
case 2://取货/出
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.TaskNo == fmonitorID && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (devinfo.RunState == 1 && fstatus == 1)
|
|
runing = true; //开始执行
|
|
break;
|
|
case 3://上堆垛机/切换成叉车模式
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.ControlMode == 0 && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (devinfo.RunState == 1 && fstatus == 1)
|
|
runing = true; //开始执行
|
|
break;
|
|
case 4://下堆垛机/切换成堆垛模式
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.ControlMode == 1 && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (devinfo.RunState == 1 && fstatus == 1)
|
|
runing = true; //开始执务
|
|
break;
|
|
case 5://回原点模式
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (devinfo.RunState == 1 && fstatus == 1)
|
|
runing = true; //开始执务
|
|
break;
|
|
case 7://去B边
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_7 == 1 && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_5 == 0 && devinfo.SplitByte_7 == 0 && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (fstatus == 1 && devinfo.RunState == 1)
|
|
runing = true; //开始执务
|
|
break;
|
|
case 12://去A边
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_7 == 1 && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_5 == 1 && devinfo.SplitByte_7 == 0 && devinfo.RunState == 0)
|
|
complete = true; //完成任务
|
|
else if (fstatus == 1 && devinfo.RunState == 1)
|
|
runing = true; //开始执务
|
|
break;
|
|
case 11://禁止穿梭板动作
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_6 == 1)
|
|
complete = true;
|
|
break;
|
|
case 13://允许穿梭板动作
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_6 == 0)
|
|
complete = true; //完成任务
|
|
break;
|
|
case 30://开始充电
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_3 == 1)
|
|
complete = true; //完成任务
|
|
break;
|
|
case 50://停止充电
|
|
if ((fstatus == 1 || fstatus == 2) && devinfo.SplitByte_3 == 0)
|
|
complete = true; //完成任务
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region 本线程处理的任务
|
|
//充满电了则停止充电(电池厂家优化了,不发停止充电)
|
|
if (devinfo.SplitByte == 100 && devinfo.SplitByte_3 == 1)
|
|
{
|
|
//SHICANGProtocol.Order_EndCharge(devinfo.RemoteIP);
|
|
}
|
|
|
|
//如果车的状态和数据库中记录的不一致,则更新数据库
|
|
//sql.Clear();
|
|
//sql.Append("select * from t_base_rgvInfo where f_rgvIndex = ").Append(shuttle);
|
|
dv = dbo.ExceSQL(string.Format("select * from t_base_rgvInfo where f_rgvIndex = {0}", shuttle)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
sql.Clear();
|
|
sql.Append("update t_base_rgvInfo set f_forkamount =0");
|
|
if (dv[0]["F_ControlMode"].ToString() != devinfo.ControlMode.ToString())
|
|
sql.Append(", F_ControlMode = ").Append(devinfo.ControlMode);
|
|
if (dv[0]["f_currentAB"].ToString() != devinfo.SplitByte_5.ToString())
|
|
sql.Append(", f_currentAB = ").Append(devinfo.SplitByte_5);
|
|
if (dv[0]["f_ForbidRGVMove"].ToString() != devinfo.SplitByte_6.ToString())
|
|
sql.Append(", f_ForbidRGVMove = ").Append(devinfo.SplitByte_6);
|
|
if (dv[0]["f_betteying"].ToString() != devinfo.SplitByte_3.ToString())
|
|
sql.Append(", f_betteying = ").Append(devinfo.SplitByte_3);
|
|
if (dv[0]["f_havegood"].ToString() != devinfo.SplitByte_0.ToString())
|
|
sql.Append(", f_havegood = ").Append(devinfo.SplitByte_0);
|
|
if (dv[0]["f_bettey_cur"].ToString() != devinfo.SplitByte.ToString())
|
|
sql.Append(", f_bettey_cur = ").Append(devinfo.SplitByte);
|
|
if (dv[0]["f_runstate"].ToString() != devinfo.RunState.ToString())
|
|
sql.Append(", f_runstate = ").Append(devinfo.RunState);
|
|
|
|
|
|
sql.Append(" where f_rgvindex= ").Append(shuttle);
|
|
sql.Append(" ");
|
|
sql.Append("update t_base_device set f_havegoods = ").Append(devinfo.SplitByte_0).Append(" where f_deviceIndex=").Append(shuttle);
|
|
dbo.ExceSQL(sql.ToString());
|
|
}
|
|
|
|
//更新车辆的时间
|
|
UpdateTime(shuttle, true);
|
|
|
|
if (message.D2121 + message.D2122 == 0)
|
|
{
|
|
//更新车状态
|
|
sql.Clear();
|
|
sql.Append("update t_base_device set F_ErrorCode = 0 where F_ErrorCode >= 30 and f_deviceindex = ").Append(shuttle);
|
|
sql.Append(" ");
|
|
sql.Append("update t_base_rgvInfo set f_error = 0 where f_RGVIndex = ").Append(shuttle);
|
|
dbo.ExceSQL(sql.ToString());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 主线程要处理的任务
|
|
#region 电量不足
|
|
if (/*devinfo.SplitByte < 70 ||*/ devinfo.SplitByte < SHICANGProtocol.NeedToBettey)
|
|
{
|
|
//正在充电中不生成充电任务
|
|
if (devinfo.SplitByte_3 == 0 && devinfo.RunState == 0)
|
|
{
|
|
CClientTCPIP.ActionError(shuttle, null, err);
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
#region 发生故障
|
|
if (message.D2121 + message.D2122 != 0)
|
|
{
|
|
devinfo.RunState = 2;
|
|
CClientTCPIP.ActionError(shuttle, null, err);
|
|
|
|
}
|
|
else
|
|
{
|
|
//将上一次的故障停止
|
|
StringBuilder dtime = new StringBuilder(DateTime.Now.ToString("u"));
|
|
dtime.Remove(dtime.Length - 1, 1);
|
|
string ddtime = dtime.ToString();
|
|
sql.Clear();
|
|
sql.Append("SELECT TOP 1 * FROM T_Base_Device_Error_Log where f_deviceindex = ").Append(shuttle).Append(" order by F_DateTime desc");
|
|
dv = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
if (string.IsNullOrEmpty(dv[0]["F_FixDateTime"].ToString()) == true)
|
|
{
|
|
sql.Clear();
|
|
sql.Append("UPDATE T_Base_Device_Error_Log SET F_FixDateTime ='").Append(dtime).Append("',F_End_DateTime='").Append(dtime).Append("' Where ID=").Append(dv[0]["ID"]);
|
|
dbo.ExceSQL(sql.ToString());
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
if (begintime != "-" && begintime != string.Empty && fmonitorID != -1)
|
|
{
|
|
if (Convert.ToDateTime(begintime.Substring(0, 19), System.Globalization.CultureInfo.CurrentCulture).AddMinutes(15) <= DateTime.Now)
|
|
{
|
|
|
|
//任务超过了10分钟,且还处于运行状态,发送回起点,把指令改为超时
|
|
if (devinfo.RunState ==1)
|
|
{
|
|
if (((message.D2100 & 8) == 8) || ((message.D2100 & 16) == 16))
|
|
{
|
|
sql.Clear();
|
|
sql.Append("update t_monitor_Task set f_status =999, f_errorCode='运行超时' where f_monitorIndex =").Append(fmonitorID);
|
|
|
|
sql.Append(" ");
|
|
|
|
sql.Append("update t_base_rgvInfo set f_error =51 where f_rgvIndex = ").Append(shuttle);
|
|
dbo.ExceSQL(sql.ToString());
|
|
|
|
//发现超时了,且不在充电位,发送回原点
|
|
if (FINSTCPIP.SHICANGProtocol.ShuttleInBetteyLane(shuttle) == false)
|
|
{
|
|
SHICANGProtocol.Order_ToOrigin(devinfo.RemoteIP);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region 通知主线程中,穿梭车状态发生了变化
|
|
|
|
|
|
if (complete)
|
|
{
|
|
//任务完成
|
|
CClientTCPIP.ActionChange(shuttle, fmonitorID, 2);
|
|
CClientTCPIP.DataSourceChange();
|
|
}
|
|
if (runing)
|
|
{
|
|
//开始执行
|
|
|
|
//sql.Remove(0, sql.Length);
|
|
//sql.Append("UPDATE T_Monitor_Task SET F_ErrorCode='', F_Status=2 WHERE F_MonitorIndex = ").Append(fmonitorID);
|
|
|
|
dbo.ExceSQL(string.Format("UPDATE T_Monitor_Task SET F_ErrorCode='', F_Status=2 WHERE F_MonitorIndex = {0}", fmonitorID));
|
|
}
|
|
#endregion
|
|
#endregion
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
int[] tem = new int[1];
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP:DisposeReceivedReadMessage", "Error", shuttle.ToString(), ex.StackTrace + ex.Message, tem);
|
|
OnWriteDarkCasket(e);
|
|
FINSError = shuttle + "读信息处理错误。" + ex.StackTrace + ex.Message;
|
|
|
|
//throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//checkTime,检查时间间隔。checkTime = true时,且时间小于10秒,则不更新时间
|
|
private static void UpdateTime(int shuttle, bool checkTime = false)
|
|
{
|
|
DateTime dt = DateTime.Now;
|
|
try
|
|
{
|
|
if (checkTime)
|
|
{
|
|
if (SHICANGProtocol.GetTime(shuttle).AddSeconds(5) > dt)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
sql.Clear();
|
|
sql.Append("update t_base_rgvInfo set f_time = '").Append(dt).Append("' where f_rgvIndex = ").Append(shuttle);
|
|
dbo.ExceSQL(sql.ToString());
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
int[] tem = new int[1];
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP:UpdateTime", "Error", shuttle.ToString(), ex.StackTrace + ex.Message, tem);
|
|
OnWriteDarkCasket(e);
|
|
FINSError = shuttle + "更新时间错误。" + ex.StackTrace + ex.Message;
|
|
}
|
|
}
|
|
|
|
private static 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;
|
|
}
|
|
private static byte[] GetError(UInt16 D2121, UInt16 D2122)
|
|
{
|
|
byte[] t21 = UInt16ToBit(D2121, true);
|
|
byte[] t22 = UInt16ToBit(D2122, true);
|
|
//StringBuilder err = new StringBuilder();
|
|
byte[] err = new byte[32];
|
|
|
|
for (int j = 0; j < err.Length; j++)
|
|
{
|
|
if (j < 16)
|
|
{
|
|
//报警信息已在数据库中保存,
|
|
err[j] = t21[j];
|
|
}
|
|
else
|
|
{
|
|
err[j] = t22[j - 16];
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
private static int GetOrderFromMonitorIndex(int monitorIndex)
|
|
{
|
|
DataView dv = new DataView();
|
|
int order = 0;
|
|
try
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select F_DeviceCommandIndex from t_monitor_task where F_monitorIndex = ").Append(monitorIndex);
|
|
dv = dbo.ExceSQL(string.Format("select F_DeviceCommandIndex from t_monitor_task where F_monitorIndex = {0}", monitorIndex)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
|
|
order = Convert.ToInt32(dv[0]["F_DeviceCommandIndex"]);
|
|
|
|
}
|
|
|
|
return order;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
//从数据库中,返回车辆正在执行或已发送的指令
|
|
private static int GetMonitorTaskIndex(int shuttle)
|
|
{
|
|
DataView dv = new DataView();
|
|
int monitorindex = 0;
|
|
try
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select F_ManTaskReserve,F_LockedState from t_base_device where f_deviceIndex = ").Append(shuttle);
|
|
dv = dbo.ExceSQL(string.Format("select F_ManTaskReserve, F_LockedState from t_base_device where f_deviceIndex = {0}", shuttle)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
//string manReserve = dv[0]["F_ManTaskReserve"].ToString();
|
|
//int fid = Convert.ToInt32(manReserve.Substring(1));
|
|
monitorindex = Convert.ToInt32(dv[0]["F_LockedState"]);
|
|
|
|
}
|
|
else
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select f_monitorIndex from t_monitor_task where f_status > 0 and f_deviceIndex = ").Append(shuttle);
|
|
dv = dbo.ExceSQL(string.Format("select f_monitorIndex from t_monitor_task where f_status > 0 and f_deviceIndex = ", shuttle)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
//string manReserve = dv[0]["F_ManTaskReserve"].ToString();
|
|
//int fid = Convert.ToInt32(manReserve.Substring(1));
|
|
monitorindex = Convert.ToInt32(dv[0]["f_monitorIndex"]);
|
|
|
|
}
|
|
}
|
|
return monitorindex;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
private static int GetManageTaskIndex(int rgvdev)
|
|
{
|
|
DataView dv = new DataView();
|
|
int fid = 0;
|
|
try
|
|
{
|
|
sql.Clear();
|
|
sql.Append("select F_ManTaskReserve,F_LockedState from t_base_device where f_deviceIndex = ").Append(rgvdev);
|
|
dv = dbo.ExceSQL(sql.ToString()).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
string manReserve = dv[0]["F_ManTaskReserve"].ToString();
|
|
if (manReserve != "0")
|
|
{
|
|
fid = Convert.ToInt32(manReserve.Substring(1));
|
|
}
|
|
|
|
//monitorindex = Convert.ToInt32(dv[0]["F_LockedState"]);
|
|
|
|
}
|
|
return fid;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
/// <summary>
|
|
///处理收到的消息——写PLC数据的应答处理
|
|
/// </summary>
|
|
/// <param name="message">消息数组</param>
|
|
private static void DisposeReceivedWriteMessage(int rgvdev)
|
|
{
|
|
DataView dv = new DataView();
|
|
try
|
|
{
|
|
|
|
int monitorindex = GetMonitorTaskIndex(rgvdev);
|
|
int order = GetOrderFromMonitorIndex(monitorindex);
|
|
if (monitorindex != 0)
|
|
{
|
|
|
|
//sql.Clear();
|
|
////RGV已接收任务 f_status = 2
|
|
//sql.Append("update t_monitor_Task set f_status = 2 where F_MonitorIndex = ").Append(monitorindex)
|
|
// .Append(" and f_deviceindex = ").Append(rgvdev);
|
|
dbo.ExceSQL(string.Format("update t_monitor_Task set f_status = 2 where F_MonitorIndex = {0} and f_deviceindex = {1}", monitorindex, rgvdev));
|
|
}
|
|
int[] tem = new int[1];
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP", "指令发送成功", "车号:" + rgvdev.ToString(), "任务号:" + monitorindex.ToString() + "命令字:" + order.ToString(), tem);
|
|
OnWriteDarkCasket(e);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
int[] tem = new int[1];
|
|
CWriteDarkCasketEventArgs e = new CWriteDarkCasketEventArgs("FINSTCPIP:DisposeReceivedWriteMessage", "Error", rgvdev.ToString(), ex.StackTrace, tem);
|
|
OnWriteDarkCasket(e);
|
|
FINSError = rgvdev + "接收写指令处理错误。" + ex.StackTrace + ex.Message;
|
|
//throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
private static byte[] UInt16ToBit(UInt16 src, bool bigEndian =false)
|
|
{
|
|
byte[] t = new byte[2];
|
|
if (bigEndian == true)
|
|
{
|
|
t[1] = (byte)((src >> 8) & 0xFF);
|
|
t[0] = (byte)(src & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
t[0] = (byte)((src >> 8) & 0xFF);
|
|
t[1] = (byte)(src & 0xFF);
|
|
}
|
|
|
|
|
|
BitArray BA = new BitArray(t);
|
|
byte[] result = new byte[BA.Length];
|
|
|
|
for (int i = 0 ; i < BA.Count; i++)
|
|
{
|
|
bool b = BA.Get(i);
|
|
if (b == true)
|
|
{
|
|
result[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
result[i] = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
public static void OnWriteDarkCasket(CWriteDarkCasketEventArgs e)
|
|
{
|
|
if (WriteDarkCasket != null)
|
|
{
|
|
WriteDarkCasket(null, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 20210405 世仓穿梭板协议类(可理解为 DB2)
|
|
/// 创建者:zcy
|
|
/// </summary>
|
|
public class SHICANGReadData
|
|
{
|
|
public ushort D2100;
|
|
public ushort D2101;
|
|
public ushort D2102;
|
|
public ushort D2121;
|
|
public ushort D2122;
|
|
public ushort D2123;
|
|
public ushort D2129;
|
|
|
|
//车的电量是模拟量,会有波动,此处忽略波动
|
|
public bool Equal(SHICANGReadData rd )
|
|
{
|
|
if (this.D2100 == rd.D2100 && this.D2101 == rd.D2101 &&
|
|
(this.D2102 == rd.D2102 || this.D2102 == (rd.D2102 + 1) || this.D2102 == (rd.D2102 - 1)) &&
|
|
this.D2121 == rd.D2121 && this.D2122 == rd.D2122 && this.D2123 == rd.D2123 && this.D2129 == rd.D2129)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void Update(SHICANGReadData rd)
|
|
{
|
|
this.D2100 = rd.D2100;
|
|
this.D2101 = rd.D2101;
|
|
this.D2102 = rd.D2102;
|
|
this.D2121 = rd.D2121;
|
|
this.D2122 = rd.D2122;
|
|
this.D2123 = rd.D2123;
|
|
this.D2129 = rd.D2129;
|
|
}
|
|
}
|
|
|
|
//世仓穿梭板的通用方法类,烟台万华项目整理,zcy
|
|
public static class SHICANGProtocol
|
|
{
|
|
public static StringBuilder sql = new StringBuilder();
|
|
public static DBOperator dbo = CClientTCPIP.dbo;
|
|
|
|
static Model.MDevice devinfo;
|
|
public static int NeedToBettey = 50;
|
|
|
|
private static void SendFINS(string ip, ushort startAddress , ushort length, byte[] _Sdata)
|
|
{
|
|
byte[] data = ClientCommunication.clientFinss[ip].GetInfo_DMWrite(startAddress, length, _Sdata);
|
|
ClientCommunication.socketFinss[ip].Send(data, null);
|
|
}
|
|
|
|
//穿梭板存货(入库) 不指定位置时location为0
|
|
public static void Order_SetGood(string ip, int taskindex ,int location = 0)
|
|
{
|
|
byte[] _Sdata = new byte[12];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 1; //自动作业码(入货/存货)
|
|
|
|
_Sdata[4] = 0;
|
|
_Sdata[5] = 0; //手动作业码
|
|
|
|
_Sdata[8] = Convert.ToByte((taskindex >> 8) & 255);
|
|
_Sdata[9] = Convert.ToByte(taskindex & 255); //调度任务号
|
|
|
|
_Sdata[10] = Convert.ToByte((location >> 8) & 255);
|
|
_Sdata[11] = Convert.ToByte(location & 255); //堆垛模式下存货区分
|
|
|
|
SendFINS(ip, 2001, 6, _Sdata);
|
|
return;
|
|
}
|
|
//穿梭板取货(出库),注:取货无法指定位置
|
|
public static void Order_GetGood(string ip, int taskindex)
|
|
{
|
|
byte[] _Sdata = new byte[10];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 2; //自动作业码(出货/取货)
|
|
|
|
_Sdata[4] = 0;
|
|
_Sdata[5] = 0; //手动作业码
|
|
|
|
_Sdata[8] = Convert.ToByte((taskindex >> 8) & 255);
|
|
_Sdata[9] = Convert.ToByte(taskindex & 255); //调度任务号
|
|
|
|
SendFINS(ip, 2001, 5, _Sdata);
|
|
return;
|
|
}
|
|
//开始充电,需要先将穿梭板送到充电位置,只有D2010=30
|
|
public static void Order_BeginCharge(string ip)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 30; //充电控制(30:开始充电, 50:停止充电)
|
|
|
|
SendFINS(ip, 2010, 1, _Sdata);
|
|
return;
|
|
}
|
|
//停止充电,只有D2010=50
|
|
public static void Order_EndCharge(string ip )
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 50; //充电控制(30:开始充电, 50:停止充电)
|
|
|
|
SendFINS(ip, 2010, 1, _Sdata);
|
|
|
|
return;
|
|
}
|
|
//复位,只有D2003=6
|
|
public static void Order_ResetShuttle(string ip)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 6; //6:清故障码
|
|
|
|
SendFINS(ip, 2003, 1, _Sdata);
|
|
return;
|
|
}
|
|
//回起点位,只有D2003=5
|
|
public static void Order_ToOrigin(string ip)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 5; //5:回起点
|
|
|
|
SendFINS(ip, 2003, 1, _Sdata);
|
|
return;
|
|
}
|
|
//禁止Shuttle动作,在换成叉车模式后,发送
|
|
public static void Order_ForbidShuttleMove(string ip)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 1; //1:禁止动作
|
|
|
|
SendFINS(ip, 2023, 1, _Sdata);
|
|
return;
|
|
}
|
|
//允许Shuttle动作,在发送Shuttle指令时
|
|
public static void Order_AllowShuttleMove(string ip)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 0; //0:允许动作
|
|
|
|
SendFINS(ip, 2023, 1, _Sdata);
|
|
return;
|
|
}
|
|
//LYJL 提示穿梭板在充电巷道中 (项目不同会有变化)
|
|
public static void Order_InBetteyLocatLane(int shuttle)
|
|
{
|
|
devinfo = Model.CGetInfo.GetDeviceInfo(shuttle);
|
|
int z = GetZ(shuttle); int order = 0;
|
|
if (z == 1) { order = 97; } //一巷道的两个充电位
|
|
if (z == 2) { order = 98; } //二巷道的两个充电位
|
|
if (z == 3) { order = 99; } //三巷道的两个充电位
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = (byte)order; //90+:在充电位的货架中,不同的充电架不一样
|
|
|
|
SendFINS(devinfo.RemoteIP, 2025, 1, _Sdata);
|
|
|
|
return;
|
|
}
|
|
// 提示穿梭板不在充电巷道中
|
|
public static void Order_NotInBetteyLocatLane(string ip)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = 0; //1:不在充电位的货架中
|
|
|
|
SendFINS(ip, 2025, 1, _Sdata);
|
|
return;
|
|
}
|
|
|
|
public const int TOASIDE = 12;//(掉头到A边)
|
|
public const int TOBSIDE = 7;//(掉头到B边)
|
|
public const int CHACHEMODE = 0; //叉车模式
|
|
public const int DUIDUOMODE = 1; //堆垛模式
|
|
|
|
//AB面变换,在堆垛机搬运后排坐标变化后调用,在一个通道中变换方向时调用
|
|
//只写D2001=7(掉头到B边),D2001=12(掉头到A边)
|
|
public static void Order_ChangeAB(string ip, int abside)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = (byte)abside;
|
|
|
|
SendFINS(ip, 2001, 1, _Sdata);
|
|
return;
|
|
}
|
|
//改变穿梭板模式,叉车模式/堆垛模式
|
|
public static void Order_ChangeMode(string ip, int mode)
|
|
{
|
|
byte[] _Sdata = new byte[2];
|
|
|
|
_Sdata[0] = 0;
|
|
_Sdata[1] = (byte)mode;
|
|
|
|
SendFINS(ip, 2000, 1, _Sdata);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//返回数据库中穿梭板的位置,和货位相同格式
|
|
public static string GetShuttleLocation(int device)
|
|
{
|
|
DataView dv = new DataView();
|
|
|
|
try
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select * from V_RGVINFO where F_DeviceIndex = ").Append(device);
|
|
dv = dbo.ExceSQL(string.Format("select * from V_RGVINFO where F_DeviceIndex = {0}", device)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
int z = Convert.ToInt32(dv[0]["F_rgvz"]);
|
|
int x = Convert.ToInt32(dv[0]["F_rgvx"]);
|
|
int y = Convert.ToInt32(dv[0]["F_rgvy"]);
|
|
int w = Convert.ToInt32(dv[0]["F_rgvw"]);
|
|
|
|
return ToLaneCoorZXYW(z, x, y, w);
|
|
}
|
|
return string.Empty;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
|
|
#region 坐标转换
|
|
public static int GetZ(int shuttle)
|
|
{
|
|
DataView dv = new DataView();
|
|
try
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select F_rgvz from V_RGVINFO where F_DeviceIndex = ").Append(shuttle);
|
|
dv = dbo.ExceSQL(string.Format("select F_rgvz from V_RGVINFO where F_DeviceIndex = {0}", shuttle)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
int z = Convert.ToInt32(dv[0]["F_rgvz"]);
|
|
|
|
return z;
|
|
}
|
|
return 0;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
|
|
private static string ToLaneCoorZXYW(int z, int x, int y, int w = 0)
|
|
{
|
|
string coor = string.Format("{0:D2}-{1:D2}-{2:D2}-{3:D2}", z, x, y, w);
|
|
return coor;
|
|
//return string.Empty;
|
|
}
|
|
public static string ToLaneCoorZXY(int z, int x, int y)
|
|
{
|
|
string coor = string.Format("{0:D2}-{1:D2}-{2:D2}", z, x, y);
|
|
return coor;
|
|
//return string.Empty;
|
|
}
|
|
|
|
//将三维或四维的货架坐标转换为三维的
|
|
public static string ToLaneCoorZXY(string coorzxyw)
|
|
{
|
|
char[] cc = new char[1] { '-' };
|
|
string[] sp = coorzxyw.Split(cc);
|
|
if (sp.Length < 3)
|
|
{
|
|
return string.Empty; //转换为货位坐标,如果小于三维,则肯定不是货位
|
|
}
|
|
string coorzxy = sp[0] + "-" + sp[1] + "-" + sp[2];
|
|
return coorzxy;
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region 车的位置
|
|
//获取所有穿梭板的四维坐标(包括不在线的穿梭板)
|
|
public static Dictionary<int, string> GetAllShuttleLocation()
|
|
{
|
|
DataView dv = new DataView();
|
|
Dictionary<int, string> coors = new Dictionary<int, string>();
|
|
try
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select * from T_Base_RGVInfo "); //此处应考虑下线的车,不能从视图V_RGVINFO中获取
|
|
dv = dbo.ExceSQL(string.Format("select * from T_Base_RGVInfo ")).Tables[0].DefaultView;
|
|
for (int i = 0; i < dv.Count; i++)
|
|
{
|
|
int rgv = Convert.ToInt32(dv[i]["F_rgvIndex"]);
|
|
int z = Convert.ToInt32(dv[i]["F_rgvz"]);
|
|
int x = Convert.ToInt32(dv[i]["F_rgvx"]);
|
|
int y = Convert.ToInt32(dv[i]["F_rgvy"]);
|
|
int w = Convert.ToInt32(dv[i]["F_rgvw"]);
|
|
coors.Add(rgv, ToLaneCoorZXYW(z, x, y, w));
|
|
}
|
|
|
|
return coors;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
|
|
//给一个货位坐标,返回在货位组内的穿梭板号,无穿梭板返回-1 (20211220 更新为四位的坐标)
|
|
public static int LaneCoorAlreadyHaveRGV(string coor)
|
|
{
|
|
if (IsCorrectCellCoor(coor) == false)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
bool checkzxy = false; //在充电位或换巷道的货位中,只检查三位坐标(当成了站台处理,站台只有三位坐标)
|
|
if (IsBetteyCoor(coor) == true || IsChangeLaneCell(coor) == true || coor.Length == 8)
|
|
{
|
|
checkzxy = true;
|
|
coor = ToLaneCoorZXY(coor);
|
|
}
|
|
|
|
string shuttleCell = string.Empty;
|
|
//所有车的三维坐标
|
|
Dictionary<int, string > coors = GetAllShuttleLocation();
|
|
foreach (int shuttle in coors.Keys)
|
|
{
|
|
if (checkzxy == true)
|
|
{
|
|
shuttleCell = ToLaneCoorZXY(coors[shuttle]);
|
|
}
|
|
else
|
|
{
|
|
shuttleCell = coors[shuttle];
|
|
}
|
|
|
|
if (shuttleCell == coor)
|
|
{
|
|
return shuttle;
|
|
}
|
|
}
|
|
|
|
|
|
return -1;
|
|
}
|
|
//穿梭板在充电位
|
|
public static bool ShuttleInBetteyLane(int device)
|
|
{
|
|
string rgvzxy = GetShuttleLocation(device);
|
|
return IsBetteyCoor(rgvzxy);
|
|
}
|
|
//穿梭板在换巷道的货位组内
|
|
public static bool ShuttleInChangeLane(int device)
|
|
{
|
|
string rgvzxy = GetShuttleLocation(device);
|
|
return IsChangeLaneCell(rgvzxy);
|
|
}
|
|
|
|
|
|
public static bool IsBetteyCoor(string coor)
|
|
{
|
|
DataView dv = new DataView();
|
|
try
|
|
{
|
|
string coorzxy = ToLaneCoorZXY(coor); //充电位只有三位坐标,只比较zxy即可
|
|
if (coorzxy == string.Empty)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//sql.Clear();
|
|
//sql.Append("select * from T_Base_Device where F_DeviceKindIndex = 9 and F_BindingDevice like '").Append(coorzxy).Append("%'");
|
|
dv = dbo.ExceSQL(string.Format("select * from T_Base_Device where F_DeviceKindIndex = 9 and F_BindingDevice like '{0}%'", coorzxy)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
//是换巷道货位
|
|
public static bool IsChangeLaneCell(string coor)
|
|
{
|
|
DataView dv = new DataView();
|
|
try
|
|
{
|
|
string coorzxy = ToLaneCoorZXY(coor); //只比较zxy即可
|
|
if (coorzxy == string.Empty)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//sql.Clear();
|
|
//sql.Append("select * from T_Base_Device where F_DeviceKindIndex = 13 and F_BindingDevice like '").Append(coorzxy).Append("%'");
|
|
|
|
dv = dbo.ExceSQL(string.Format("select * from T_Base_Device where F_DeviceKindIndex = 13 and F_BindingDevice like '{0}%'", coor)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
}
|
|
}
|
|
//穿梭板在正确的货位坐标中,在堆垛机上、或坐标是 0-0-0-0 表示不正确的货位坐标
|
|
private static bool IsCorrectCellCoor(string coor)
|
|
{
|
|
if (coor == string.Empty)
|
|
{
|
|
return false; //不是货位坐标
|
|
}
|
|
|
|
char[] cc = new char[1] { '-' };
|
|
string[] sp = coor.Split(cc);
|
|
|
|
if (sp.Length < 3)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Convert.ToInt32(sp[0]) == 0 || Convert.ToInt32(sp[0]) > 100)
|
|
{
|
|
return false; //排坐标不能是0,不能是堆垛机(堆垛机11001大于100)
|
|
}
|
|
if (Convert.ToInt32(sp[1]) == 0 || Convert.ToInt32(sp[2]) == 0)
|
|
{
|
|
return false; //列坐标不能是0,层坐标不能是0
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endregion
|
|
|
|
|
|
//穿梭板是否已连接
|
|
public static bool ShuttleConnected(string ip)
|
|
{
|
|
if (FINSTCPIP.ClientCommunication.clientFinss.ContainsKey(ip) == true)
|
|
{
|
|
if (FINSTCPIP.ClientCommunication.clientFinss[ip]._finsConnected == false)
|
|
{
|
|
// FINS 连接失败,
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//无 FINS 连接,
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//所有车的时间
|
|
public static DateTime GetTime(int shuttle)
|
|
{
|
|
DateTime dt = DateTime.MinValue;
|
|
DataView dv = new DataView();
|
|
try
|
|
{
|
|
//sql.Clear();
|
|
//sql.Append("select F_Time from T_Base_RGVInfo where F_RgvIndex =").Append(shuttle); //这行一直在报错,没有发现问题
|
|
dv = dbo.ExceSQL(string.Format("select F_Time from T_Base_RGVInfo where F_RgvIndex ={0}", shuttle)).Tables[0].DefaultView;
|
|
if (dv.Count > 0)
|
|
{
|
|
DateTime.TryParse(dv[0]["F_Time"].ToString(), out dt);
|
|
}
|
|
return dt;
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dv.Dispose();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|