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 socketFinss = new Dictionary(); //每个PLC通信时需要的 FINS 信息,用来从FINS包中提取数据,发送数据时添加FINS包装 public static Dictionary clientFinss = new Dictionary(); public static Dictionary connectTimes = new Dictionary();//socket的连接次数,连接成功时置0 public static Dictionary> buffer = new Dictionary>();//每个socket的buffer public static Dictionary SC_RGV_READ_DATA = new Dictionary(); //世仓穿梭板读取车状态:发送包(FINS连接成功时添加) static StringBuilder sql = new StringBuilder(); public static Dictionary lastReadMessage = new Dictionary();//上一次发生变化后,收到的信息 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 te = new List(); 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 bufftemp = new List(); //解析报文 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(); /// ///处理收到的消息——读PLC数据的应答处理 /// /// 消息数组 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(); } } /// ///处理收到的消息——写PLC数据的应答处理 /// /// 消息数组 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); } } } /// /// 20210405 世仓穿梭板协议类(可理解为 DB2) /// 创建者:zcy /// 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 GetAllShuttleLocation() { DataView dv = new DataView(); Dictionary coors = new Dictionary(); 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 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(); } } } }