using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using parkMonitor.LOG; using parkMonitor.entity; using parkMonitor.model; using System.Configuration; using System.Threading; using parkMonitor.server.uiLogServer; using parkMonitor.tools; using parkMonitor.Database2; using MySql.Data.MySqlClient; using parkMonitor.server.NumMachine; namespace parkMonitor.server.CoreThread { /// /// 核心对命令处理父类 /// public abstract class AbstractCmd { public static bool isClosing { get; set; } /// /// 设备总状态PLC地址 /// public int equipmentStatus_address { set; get; } /// /// 停车完成PLC地址 /// public int park_completed_address { set; get; } /// /// 停车入口X坐标 /// public int parkingEntX { set; get; } /// /// 停车入口Y坐标 /// public int parkingEntY { set; get; } /// /// 停车入口Z坐标 /// public int parkingEntZ { set; get; } /// /// 取车完成PLC地址 /// public int fetch_completed_address { set; get; } /// /// 轮距测量状态PLC地址 /// public int wheelbase_status_address { get; set; } /// /// 停车启动机械手PLC地址 /// public int parking_startRobot_address { get; set; } /// /// 取车启动机械手PLC地址 /// public int fetching_startRobot_address { get; set; } /// /// 前轮距PLC地址 /// public int frontWheelbase_address { get; set; } /// /// 后轮距PLC地址 /// public int rearWheelbase_address { get; set; } /// /// PLC句柄 /// public IEquipments PLC { set; get; } /// /// 队列线程句柄 /// public IEquipments queuingThread { set; get; } /// /// 数据库操作句柄 /// public DBOperation oper { set; get; } /// /// 号牌机线程句柄 /// public IEquipments NumMachine { set; get; } /// /// 车库中心 /// public CEntrance cEntrance { set; get; } public AbstractCmd() { parking_startRobot_address = EntityForCore.ins.parking_startRobot_address; fetching_startRobot_address = EntityForCore.ins.fetching_startRobot_address; equipmentStatus_address = EntityForCore.ins.equipmentStatus_address; park_completed_address = EntityForCore.ins.park_completed_address; parkingEntX = EntityForCore.ins.parkingEntX; parkingEntY = EntityForCore.ins.parkingEntY; parkingEntZ = EntityForCore.ins.parkingEntZ; //轮距 frontWheelbase_address = EntityForCore.ins.frontWheelbase_address; rearWheelbase_address = EntityForCore.ins.rearWheelbase_address; wheelbase_status_address = EntityForCore.ins.wheelbase_status_address; //取车完成 fetch_completed_address = EntityForCore.ins.fetch_completed_address; //获取PLC句柄 PLC = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC); //获取队列句柄 queuingThread = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.Queue); //获取号牌机线程句柄 NumMachine = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.NumMachine); //数据库 oper = new DBOperation(); //车位分配 cEntrance = new CEntrance(); Robot.robot1.parking_start_addr = parking_startRobot_address; Robot.robot1.fetching_start_addr = fetching_startRobot_address; //locationOper = new DBLocationOperator(); } public abstract void executeCmd(Command queueCmd); /// /// 等待机械手空闲资源 /// /// /// public bool WaitForRobotResource(int robotID) { PLCMessage PLCMsg = null; MyTimer mt = new MyTimer(); mt.StartTiming(); lock (Robot.robot1) { while (!isClosing) { PLCMsg = (PLCMessage)PLC.GetMessage(); bool occupied = true; if (PLCMsg != null) { if (robotID == 1) { try { Robot.robot1.parking_start_value = Convert.ToInt32(PLCMsg.originalPlcList[parking_startRobot_address].Value); Robot.robot1.fetching_start_value = Convert.ToInt32(PLCMsg.originalPlcList[fetching_startRobot_address].Value); //刷新机械手资源状态值 if (Robot.robot1.parking_start_value == 0 && Robot.robot1.fetching_start_value == 0 && !Robot.robot1.occupied) { occupied = false; } else { occupied = true; } } catch { } } } if (occupied) { Thread.Sleep(3000); } else { Robot.robot1.occupied = true; //UILogServer.ins.log("获得机械手资源"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "获得机械手资源"); break; } mt.EndTiming(); int activationCount = 0; if (mt.IsLonger(60, 1, false, out activationCount)) { if (activationCount == 1) { UILogServer.ins.info("无空闲机械手资源,继续等待"); } if (MyTimer.restart && !mt.rolledBack) { mt.rolledBack = true; Robot.robot1.occupied = false; UILogServer.ins.error("启动机械手资源超时,已启动回滚"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "启动机械手资源超时,已启动回滚"); return false; } Thread.Sleep(100); } } } return true; } /// /// /// 流程回滚函数 /// /// /// /// /// public void Rollback(Command queueCmd, int parkingSpaceID, bool robotAllocated, bool isParking, LaserMessage lm) { //命令回退 queueCmd.returnedCount += 1; queuingThread.SetMessage(queueCmd); //线程计数调整 if (robotAllocated) { Robot.robot1.occupied = false; } Robot.robot1.waitCount -= 1; //释放激光 if (lm != null) { lm.occupied = false; } if (parkingSpaceID == 0) { return; } //复位车辆状态;若已更新过车位则还需复位总车位数,车位状态 if (!queueCmd.manual) { if (isParking) { //释放已分配车位 if (!ParkingSpaceManager.ins.SetParkingSpace(parkingSpaceID, 0)) { EntityForCore.ins.globalStatus = false; Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "车位分配出现异常,需要重启"); return; } } else { //复原已释放的车位 if (!ParkingSpaceManager.ins.SetParkingSpace(parkingSpaceID, 1)) { EntityForCore.ins.globalStatus = false; Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "车位分配出现异常,需要重启"); return; } } } else { if (isParking) { oper.UpdateVehicleParkState(EntityForCore.remoteBQ, queueCmd.LicenseNum, 0); if (robotAllocated) { oper.UpdateParkingSpaceState(EntityForCore.remoteBQ, parkingSpaceID, 0); } } else { oper.UpdateVehicleParkState(EntityForCore.remoteBQ, queueCmd.LicenseNum, 1); if (robotAllocated) { oper.UpdateParkingSpaceState(EntityForCore.remoteBQ, parkingSpaceID, 1); } } } } } /// /// 停车命令处理类 /// public class StopCmd : AbstractCmd { /// /// 停车数据库事务 /// private void StopParkingSubmit() { } /// /// 命令中号牌与对应号牌机中当前号牌比对,确认车辆 /// private bool NumValidation(Command queueCmd, int countdown, float ratio) { List numList = ((NumberMachineMessage)NumMachine.GetMessage()).data; bool result = false; Task numberCheck = Task.Factory.StartNew(() => { int myCountdown = countdown, count = 0; while (myCountdown-- > 0) { foreach (NumberMachineNode node in numList) { if (queueCmd.ip.Equals(node.ip) && queueCmd.LicenseNum.Equals(node.LicenseNum)) { count += 1; } } Thread.Sleep(500); } if (count >= (int)(countdown * ratio)) { result = true; } else { result = false; } }); numberCheck.Wait(); return result; } /// /// 号牌复位 /// private void NumReset(Command queueCmd) { NumberMachineMessage numberMachineMessage = new NumberMachineMessage(); numberMachineMessage.aNode = new NumberMachineNode(); numberMachineMessage.aNode.ip = ""; numberMachineMessage.aNode.LicenseNum = queueCmd.LicenseNum; queuingThread.SetMessage(numberMachineMessage); } /// /// 车位资源 /// /// /// private Parking_Space WaitForParkingSpaceResource(Command queueCmd, out int count) { //中心点 cEntrance.parkingEntX = parkingEntX; cEntrance.parkingEntY = parkingEntY; cEntrance.parkingEntZ = parkingEntZ; Parking_Space ppp = new Parking_Space(); MyTimer mt = new MyTimer(); mt.StartTiming(); count = 0; while (!isClosing && ParkingSpaceManager.ins != null) { if (!queueCmd.manual) { ppp = ParkingSpaceManager.ins.MallocParkingSpace(cEntrance, queueCmd, false, out count);//自动 } else { ppp = ParkingSpaceManager.ins.MallocParkingSpace(cEntrance, queueCmd, false, out count);//手动 } if (ppp != null) { Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:" + queueCmd.LicenseNum + "已分配车位"); break; } Thread.Sleep(200); mt.EndTiming(); int activationCount = 0; if (mt.IsLonger(5, 1, false, out activationCount)) { if (activationCount == 1) { UILogServer.ins.info("停车流程:" + queueCmd.LicenseNum + "未获得车位"); } if (MyTimer.restart && !mt.rolledBack) { mt.rolledBack = true; UILogServer.ins.error(queueCmd.LicenseNum + "超时未获得车位,指令退回"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, queueCmd.LicenseNum + "超时未获得车位,指令退回"); return null; } Thread.Sleep(100); } } return ppp; } /// /// 等待激光数据 /// /// 传入的命令 /// 车辆是否已驶离 /// private Data WaitForLaserResource(Command queueCmd, bool disappeared, out LaserMessage lmRelease) { //激光数据 Data data = new Data(); bool jumpOut = false; int disconnectionCount = 0; int laserID = queueCmd.id / 6 + 1; PLCMessage PLCMsg = null; jumpOut = false; lmRelease = null; MyTimer mt = new MyTimer(); mt.StartTiming(); while (!isClosing) { PLCMsg = (PLCMessage)PLC.GetMessage(); if (PLCMsg != null) { foreach (LaserMessage lm in PLCMsg.laserMsgList) { if (lm.id == laserID && lm.data != null) { lock (lm) { //判断车辆检测结果, if (disappeared) { lm.abort_rescan = true; jumpOut = true; break; } //存储相应激光数据 if (lm.recorded && lm.licenseNum == queueCmd.LicenseNum) { data.angleA = lm.data.angleA; data.centerX = lm.data.centerX; data.centerY = lm.data.centerY; data.length = lm.data.length; data.width = lm.data.width; data.height = lm.data.height; jumpOut = true; lm.recorded = false; //lm.occupied = false; lmRelease = lm; lm.licenseNum = ""; break; } else if (lm.status == 5) { disconnectionCount += 1; if (disconnectionCount == 1) { UILogServer.ins.error("激光" + lm.id + "连接异常"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "激光" + lm.id + "连接异常"); } Thread.Sleep(10000); } } } Thread.Sleep(500); } if (jumpOut) { //UILogServer.ins.log("停车流程:" + queueCmd.LicenseNum + "激光数据已获得"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:" + queueCmd.LicenseNum + "激光数据已获得"); break; } } Thread.Sleep(1000); mt.EndTiming(); int activationCount = 0; if (mt.IsLonger(30, 1, false, out activationCount)) { if (activationCount == 1) { UILogServer.ins.info("停车流程:" + queueCmd.LicenseNum + "未获取激光数据,继续等待"); } if (MyTimer.restart && !mt.rolledBack) { mt.rolledBack = true; UILogServer.ins.error(queueCmd.LicenseNum + "超时未获取激光数据,指令退回"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, queueCmd.LicenseNum + "超时未获取激光数据,指令退回"); return null; } Thread.Sleep(100); } } return data; } /// /// 停车完成 /// private bool WaitForStoreCompletionSignal(Command queueCmd, int parkingSpaceID, ref bool robotError, int status) { string connectionStr = null; PLCMessage PLCMsg = null; MyTimer mt = new MyTimer(); mt.StartTiming(); while (!isClosing) { Thread.Sleep(1000); PLCMsg = (PLCMessage)PLC.GetMessage(); int storeStatus = Convert.ToInt32(PLCMsg.originalPlcList[park_completed_address].Value); //停车完成信号 if (storeStatus == status) { //UILogServer.ins.log("停车流程:" + queueCmd.LicenseNum + "已获得停车完成信号" + status); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:" + queueCmd.LicenseNum + "已获得停车完成信号" + status); break; } else if (1 == 2)//机械手异常,则退指令,写数据库归位,判断条件需之后补充 { robotError = true; queueCmd.returnedCount += 1; queuingThread.SetMessage(queueCmd); if (!queueCmd.manual) { oper.UpdateParkingSpaceState(EntityForCore.remoteBQ, parkingSpaceID, 0); } else { connectionStr = "SqlConnectionLocation"; oper.UpdateParkingSpaceState(EntityForCore.localBQ, parkingSpaceID, 0); } break; } mt.EndTiming(); int activationCount = 0; if (mt.IsLonger(120, 1, false, out activationCount)) { if (activationCount == 1) { UILogServer.ins.info("停车流程:" + queueCmd.LicenseNum + "未获得停车完成信号" + status + ",继续等待"); } if (MyTimer.restart && !mt.rolledBack) { mt.rolledBack = true; UILogServer.ins.error(queueCmd.LicenseNum + "等待停车完成信号" + status + "超时,流程回滚"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, queueCmd.LicenseNum + "等待停车完成信号" + status + "超时,流程回滚"); return false; } Thread.Sleep(100); } } return true; } /// /// 等待轮距信息 /// /// 前轮距 /// 后轮距 private bool WaitWheelbase(ref int frontWheelbase, ref int rearWheelbase) { PLCMessage PLCMsg = null; MyTimer mt = new MyTimer(); mt.StartTiming(); while (!isClosing) { PLCMsg = (PLCMessage)PLC.GetMessage(); int wheelbaseStatus = Convert.ToInt32(PLCMsg.originalPlcList[wheelbase_status_address].Value); //停车完成信号 if (wheelbaseStatus == 3) { frontWheelbase = Convert.ToInt32(PLCMsg.originalPlcList[frontWheelbase_address].Value); rearWheelbase = Convert.ToInt32(PLCMsg.originalPlcList[rearWheelbase_address].Value); //UILogServer.ins.log("轮距雷达完成状态已获取"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "轮距雷达完成状态已获取"); break; } Thread.Sleep(1000); mt.EndTiming(); int activationCount = 0; if (mt.IsLonger(60, 1, false, out activationCount)) { if (activationCount == 1) { UILogServer.ins.info("未获取轮距雷达完成状态,继续等待"); } if (MyTimer.restart && !mt.rolledBack) { mt.rolledBack = true; UILogServer.ins.error("超时未获取轮距雷达数据,流程回滚"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "超时未获取轮距雷达数据,流程回滚"); return false; } Thread.Sleep(100); } } return true; } /// /// 停车流程 /// /// public override void executeCmd(Command queueCmd) { //UILogServer.ins.info("停车流程:" + queueCmd.LicenseNum + "开始"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:" + queueCmd.LicenseNum + "开始"); string connectionStr = null; //数据库连接字符串 bool disappeared = false; //车辆检测结果 bool stopChecking = false; //是否停止检测 bool robotError = false; //机械手是否异常 int userID = 0; //用户ID //第一步,激光与车位: int status = 1;//停车 ControlMessage cm = new ControlMessage(); cm.status = status; //根据号牌机id启动对应激光 cm.laserID = queueCmd.id / 6 + 1; cm.LicenseNum = queueCmd.LicenseNum; PLC.SetMessage(cm); Log.WriteLog(LogType.NOT_DATABASE, "停车流程:车牌号为" + queueCmd.LicenseNum + "的车辆准备开启激光"); //UILogServer.ins.info("停车流程:车牌号为" + queueCmd.LicenseNum + "的车辆准备开启激光"); //车位分配数据库操作加锁,直到启动机械手 Parking_Space ppp = new Parking_Space(); ParkingBuffer pb = null; Data dataReal = new Data(); int garageID; //车库ID(Web发送) string realParkTime; //停车时间(可执行队列) LaserMessage lmToBeReleased; //激光 int freeSpaceCount = 0; //剩余空闲车位 dataReal = WaitForLaserResource(queueCmd, disappeared, out lmToBeReleased); //判断激光资源有效性,无效代表超时且已点击回滚按钮 if (dataReal == null) { Rollback(queueCmd, 0, false, true, lmToBeReleased); return; } //车位分配锁 lock (Parking_Space.spaceLock) { bool displayed = false; //等待获取缓冲位资源 //获取车位资源 ppp = WaitForParkingSpaceResource(queueCmd, out freeSpaceCount); //过期号牌判断 if (queueCmd.userID != "") { userID = Convert.ToInt32(queueCmd.userID); } garageID = queueCmd.garageID; realParkTime = queueCmd.TimeRecord; //定义号牌验证与机械手异常标志 //Task checkNum = Task.Factory.StartNew(() => //{ // DateTime startTime = DateTime.Now; // DateTime endTime = DateTime.Now; // TimeSpan t = startTime - endTime; // while (!stopChecking && t.TotalSeconds <= 600) // { // //号牌验证,异常则退回队列 // Func numValidationResult = new Func(NumValidation); // IAsyncResult result = numValidationResult.BeginInvoke(queueCmd, 10, 0.7f, null, null); // bool checkResult = numValidationResult.EndInvoke(result); // if (stopChecking) // { // return; // } // if (!checkResult) // { // UILogServer.ins.info("停车命令" + queueCmd.LicenseNum + " 与当前车辆不一致"); // disappeared = true; // return; // //未能停车,将车辆状态复位 // //oper.UpdateVehicleParkState(queueCmd.LicenseNum, 0); // } // endTime = DateTime.Now; // t = startTime - endTime; // } //}); //判断车位资源有效性,无效则回滚 if (ppp == null) { Rollback(queueCmd, 0, false, true, lmToBeReleased); return; } while (pb == null && !MyTimer.restart) { //pb = ParkingBufferManager.ins.MallocParkingBuffer(queueCmd.id); pb = new ParkingBuffer(ppp.parkingSpaceX, true); ParkingBufferManager.ins.SetParkingBuffer(ppp.parkingSpaceX, true); if (pb != null) { Log.WriteLog(LogType.NOT_DATABASE, LogFile.INFO, queueCmd.LicenseNum + "分配缓冲位:" + pb.bufferID); break; } else if (!displayed) { UILogServer.ins.error(queueCmd.LicenseNum + "缓冲位已满"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.WARNING, queueCmd.LicenseNum + "缓冲位分配失败"); displayed = true; } Thread.Sleep(2000); } if (pb == null) { UILogServer.ins.error("缓冲位分配失败,流程已回滚"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "缓冲位分配失败,流程已回滚"); Rollback(queueCmd, 0, false, true, lmToBeReleased); return; } //车位赋值与写数据库 if (!queueCmd.manual) { } else { //更新本地车位表车位状态 oper.UpdateParkingSpaceState(EntityForCore.localBQ, ppp.parkingSpaceID, 1); //更新车库表剩余车位数 //int freeSpaceCount = oper.getGarageFreeSpace(connectionStr, garageID); //freeSpaceCount = freeSpaceCount - 1; //oper.UpdateGarageFreeSpace(CoreThreadTest2.localBQ, freeSpaceCount, garageID); } //号牌失效,数据库回滚 if (disappeared) { NumReset(queueCmd); if (!queueCmd.manual) { oper.UpdateVehicleParkState(EntityForCore.remoteBQ, queueCmd.LicenseNum, 0); } else { oper.UpdateVehicleParkState(EntityForCore.localBQ, queueCmd.LicenseNum, 0); } return; } } //开始启动机械手,停止检测号牌 stopChecking = true; //UILogServer.ins.log("停车流程:" + queueCmd.LicenseNum + "停止号牌核对,准备启动机械手"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:" + queueCmd.LicenseNum + "停止号牌核对,准备启动机械手"); int robotID = 0; robotID = queueCmd.id / 6 + 1; int frontWheelbase = 0; int rearWheelbase = 0; //需要先遍历robot数组,根据id找到对应机械手 if (!WaitForRobotResource(robotID)) { Rollback(queueCmd, ppp.parkingSpaceID, false, true, lmToBeReleased); return; } //第二步,机械手: status = 2; cm.status = status; cm.RobotID = robotID;//启动对应机械手 //激光数据 cm.centerX = Convert.ToString(dataReal.centerX); cm.centerY = Convert.ToString(dataReal.centerY); cm.angleA = Convert.ToString(dataReal.angleA); cm.length = Convert.ToString(dataReal.length); cm.width = Convert.ToString(dataReal.width); cm.height = Convert.ToString(dataReal.height); //分配的车位数据 cm.parkingSpaceID = Convert.ToString(ppp.parkingSpaceID); //!!!之前把停车位X坐标当做缓冲位ID,现修改为被管理的缓冲位ID,之后PLC地址需调整!!! cm.parkingSpaceX = Convert.ToString(ppp.parkingSpaceX); //cm.parkingSpaceX = Convert.ToString(pb.bufferID); cm.parkingSpaceY = Convert.ToString(ppp.parkingSpaceY); cm.parkingSpaceZ = Convert.ToString(ppp.parkingSpaceZ); PLC.SetMessage(cm); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:抓车:" + queueCmd.LicenseNum + "\n车辆数据:" + cm.angleA + " ," + cm.centerX + " ," + cm.centerY + " ," + cm.length + " ," + cm.width + " ," + cm.height + " ," + cm.parkingSpaceID + " ," + cm.parkingSpaceX + " ," + cm.parkingSpaceY + " ," + cm.parkingSpaceZ); UILogServer.ins.info("停车流程:抓车:" + queueCmd.LicenseNum); if (!WaitWheelbase(ref frontWheelbase, ref rearWheelbase)) { Rollback(queueCmd, ppp.parkingSpaceID, true, true, lmToBeReleased); return; } if (!WaitForStoreCompletionSignal(queueCmd, ppp.parkingSpaceID, ref robotError, 1)) { Rollback(queueCmd, ppp.parkingSpaceID, true, true, lmToBeReleased); return; } //第三步,停车完成: status = 3; cm.status = status; PLC.SetMessage(cm); //机械手异常则回滚 if (!WaitForStoreCompletionSignal(queueCmd, ppp.parkingSpaceID, ref robotError, 0)) { Rollback(queueCmd, ppp.parkingSpaceID, true, true, lmToBeReleased); return; } //停车流程结束,将相应车牌复位,从号牌队列中出队 NumReset(queueCmd); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "停车流程:" + queueCmd.LicenseNum + "停车完成,状态复位"); UILogServer.ins.info("停车流程:" + queueCmd.LicenseNum + "停车完成,状态复位"); //释放机械手与激光 if (lmToBeReleased != null) { lmToBeReleased.occupied = false; } Robot.robot1.occupied = false; Robot.robot1.waitCount -= 1; //自动化测试用 //ManualParkingSimul.ins.Update(Int32.Parse(queueCmd.LicenseNum.Substring(2, 1))); //ParkingSimul.ins.Update(Int32.Parse(queueCmd.LicenseNum.Substring(2, 1))); //根据号牌查找车型 //int vehicleTypeID = oper.getVehicleTypeID(numberPlate); //判断测量数据是否准确 //bool isDataRight = oper.IsDataRight(vehicleTypeLength, vehicleTypeWidth, vehicleTypeHeight, vehicleTypeWheelbase, vehicleTypeID); //正常写入数据库 if (userID != 0) { lock (Parking_Space.RecordLock) { if (!queueCmd.manual) { //事务,写入停车记录, 更新车辆信息 int parkingRecordsID = 0; string insertRecordSql = ""; try { insertRecordSql = "insert into parkingrecords(userID,numberPlate,parkingSpaceID,garageID,parkingRecordsState,realParkTime) values('" + userID + "','" + queueCmd.LicenseNum + "','" + ppp.parkingSpaceID + "','" + garageID + "',3,'" + realParkTime + "')"; List strs = new List(); strs.Add(insertRecordSql); parkingRecordsID = DBOperation.InsertParkingRecords(EntityForCore.remoteBQ, strs); } catch (Exception ex) { Console.WriteLine(ex.Message + "插入停车记录表失败"); //数据库操作失败写日志 Log.WriteLog(LogType.DATABASE, "1", insertRecordSql); } string updateParkingSpaceStateSql = ""; string updateFreeSpaceSql = ""; string updateVehicleSql = ""; try { int freeSpace = ParkingSpaceManager.ins.GetFreeSpaceCount(); List strs = new List(); updateParkingSpaceStateSql = "update parkingspace set parkingSpaceState = 1 where parkingSpaceID = '" + ppp.parkingSpaceID + "'"; updateFreeSpaceSql = "update garage set garageFreeSpace = '" + freeSpace + "' where garageID = '" + garageID + "'"; updateVehicleSql = "update vehicle set vehiclepParkState = 1,scanEntryTime = '" + queueCmd.TimeRecord + "',parkingRecordsID = '" + parkingRecordsID + "',parkingSpaceID = '" + ppp.parkingSpaceID + "',vehicleTypeConfirm = 1,frontwheelbase = '" + frontWheelbase + "',rearwheelbase = '" + rearWheelbase + "' where numberPlate = '" + queueCmd.LicenseNum + "'"; strs.Add(updateParkingSpaceStateSql); strs.Add(updateFreeSpaceSql); strs.Add(updateVehicleSql); DBOperation.UpdateTransaction(EntityForCore.remoteBQ, strs); } catch (Exception ex) { Console.WriteLine(ex.Message + "停车事务处理失败"); //数据库操作失败写日志 Log.WriteLog(LogType.DATABASE, "0", updateParkingSpaceStateSql); Log.WriteLog(LogType.DATABASE, "0", updateFreeSpaceSql); Log.WriteLog(LogType.DATABASE, "0", updateVehicleSql); } } else { //事务,写入停车记录, 更新车辆信息 int parkingRecordsID = 0; string insertRecordSql = ""; try { insertRecordSql = "insert into parkingrecords(userID,numberPlate,parkingSpaceID,garageID,parkingRecordsState,realParkTime) values('" + userID + "','" + queueCmd.LicenseNum + "','" + ppp.parkingSpaceID + "','" + garageID + "',3,'" + realParkTime + "')"; List strs = new List(); strs.Add(insertRecordSql); parkingRecordsID = DBOperation.InsertParkingRecords(EntityForCore.localBQ, strs); if (parkingRecordsID == 0) { //数据库操作失败写日志 Log.WriteLog(LogType.DATABASE, "1", insertRecordSql); } } catch (Exception ex) { Console.WriteLine(ex.Message + "插入停车记录表失败"); } string updateParkingSpaceStateSql = ""; string updateFreeSpaceSql = ""; string updateVehicleSql = ""; try { int freeSpace = ParkingSpaceManager.ins.GetFreeSpaceCount(); List strs = new List(); updateParkingSpaceStateSql = "update parkingspace set parkingSpaceState = 1 where parkingSpaceID = '" + ppp.parkingSpaceID + "'"; updateFreeSpaceSql = "update garage set garageFreeSpace = '" + freeSpace + "' where garageID = '" + garageID + "'"; updateVehicleSql = "update vehicle set vehiclepParkState = 1,scanEntryTime = '" + queueCmd.TimeRecord + "',parkingRecordsID = '" + parkingRecordsID + "',parkingSpaceID = '" + ppp.parkingSpaceID + "',vehicleTypeConfirm = 1,frontwheelbase = '" + frontWheelbase + "',rearwheelbase = '" + rearWheelbase + "' where numberPlate = '" + queueCmd.LicenseNum + "'"; strs.Add(updateParkingSpaceStateSql); strs.Add(updateFreeSpaceSql); strs.Add(updateVehicleSql); object result = DBOperation.UpdateTransaction(EntityForCore.localBQ, strs); if (!(bool)result) { //数据库操作失败写日志 Log.WriteLog(LogType.DATABASE, "0", updateParkingSpaceStateSql); Log.WriteLog(LogType.DATABASE, "0", updateFreeSpaceSql); Log.WriteLog(LogType.DATABASE, "0", updateVehicleSql); } } catch (Exception ex) { Console.WriteLine(ex.Message + "停车事务处理失败"); } } } } //异常写入日志文件 else { LogFile logFile = LogFile.ERROR_NUMBERPLATE; Log.WriteLog(LogType.NOT_DATABASE, logFile, "号牌:" + queueCmd.LicenseNum); Log.WriteLog(LogType.NOT_DATABASE, logFile, "入库时间:" + realParkTime); Log.WriteLog(LogType.NOT_DATABASE, logFile, "车位id:" + ppp.parkingSpaceID); Log.WriteLog(LogType.NOT_DATABASE, logFile, "车位x:" + ppp.parkingSpaceX); Log.WriteLog(LogType.NOT_DATABASE, logFile, "车位y:" + ppp.parkingSpaceY); Log.WriteLog(LogType.NOT_DATABASE, logFile, "车位z:" + ppp.parkingSpaceZ); //异常情况处理有待讨论 } } } /// /// 取车命令处理类 /// public class FetchCmd : AbstractCmd { /// /// 等待取车完成信号 /// /// /// /// /// /// private bool waitForFetchCompletionSignal(Command queueCmd, int parkingSpaceID, ref bool robotError, int status) { string connectionStr = null; PLCMessage PLCMsg = null; MyTimer mt = new MyTimer(); mt.StartTiming(); while (!isClosing) { Thread.Sleep(2000); PLCMsg = (PLCMessage)PLC.GetMessage(); int fetchingStatus = Convert.ToInt32(PLCMsg.originalPlcList[fetch_completed_address].Value); //取车完成信号 if (fetchingStatus == status) { //取车完成后或可归零 //UILogServer.ins.log("取车流程:" + queueCmd.LicenseNum + "获得取车完成信号" + status); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "取车流程:" + queueCmd.LicenseNum + "获得取车完成信号" + status); break; } else if (1 == 2)//机械手异常,则退指令,写数据库归位,判断条件需之后补充 { robotError = true; queueCmd.returnedCount += 1; queuingThread.SetMessage(queueCmd); if (!queueCmd.manual) { oper.UpdateParkingSpaceState(EntityForCore.remoteBQ, parkingSpaceID, 0); } else { oper.UpdateParkingSpaceState(EntityForCore.localBQ, parkingSpaceID, 0); } break; } mt.EndTiming(); int activationCount = 0; if (mt.IsLonger(120, 1, false, out activationCount)) { if (activationCount == 1) { UILogServer.ins.info("取车流程:" + queueCmd.LicenseNum + "未获得取车完成信号" + status + ",继续等待"); } if (MyTimer.restart && !mt.rolledBack) { mt.rolledBack = true; UILogServer.ins.error(queueCmd.LicenseNum + "等待取车完成信号" + status + "超时,流程回滚"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, queueCmd.LicenseNum + "等待取车完成信号" + status + "超时,流程回滚"); return false; } Thread.Sleep(100); } } return true; } public override void executeCmd(Command queueCmd) { //UILogServer.ins.info("取车流程:" + queueCmd.LicenseNum + "开始"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "取车流程:" + queueCmd.LicenseNum + "开始"); string connectionStr = null; //数据库连接字符串 Vehicle vehiclelist = null; //待取车辆信息 ControlMessage cm = null; Parking_Space ps = null; //车位信息 int frontwheelbase; //前轮距 int rearwheelbase; //后轮距 int garageID; //车库ID bool robotError = false; //机械手是否异常 //获取车辆表中车辆相关信息 if (queueCmd.manual) { //vehiclelist = oper.GetLocalVehicle(connectionStr, queueCmd.LicenseNum, queueCmd.garageID); } else { vehiclelist = oper.GetVehicle(EntityForCore.remoteBQ, queueCmd.LicenseNum); } if (vehiclelist == null) { //无法获取车辆信息,流程中止 EntityForCore.ins.globalStatus = false; int count = 0; while (!MyTimer.restart) { count++; if (count == 1) { UILogServer.ins.error("无法获取车辆信息"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "无法从数据库获取车辆信息,流程中止"); } Thread.Sleep(5000); } Rollback(queueCmd, 0, false, false, null); return; } int parkingSpaceID = vehiclelist.parkingSpaceID; garageID = vehiclelist.garageID; frontwheelbase = vehiclelist.frontwheelbase; rearwheelbase = vehiclelist.rearwheelbase; queueCmd.parkingRecordsID = vehiclelist.parkingRecordsID; if (!ParkingSpaceManager.ins.parkingSpaceStatusMap.TryGetValue(parkingSpaceID, out ps) || ps == null) { EntityForCore.ins.globalStatus = false; int count = 0; while (!MyTimer.restart) { count++; if (count == 1) { UILogServer.ins.error("车位分配出现异常!!!"); Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "车位分配出现异常!!!"); } Thread.Sleep(5000); } Rollback(queueCmd, parkingSpaceID, false, false, null); return; } cm = new ControlMessage(); //启动机械手 int robotID = 0; robotID = parkingSpaceID / 50 + 1; if (!WaitForRobotResource(robotID)) { Rollback(queueCmd, parkingSpaceID, false, false, null); return; } //取车 int status = 4; cm.status = status; //先手动赋值 cm.RobotID = 1; //1号机械手 cm.fetchPosition = 1; //放置地址 cm.parkingSpaceID = Convert.ToString(ps.parkingSpaceID); cm.parkingSpaceX = Convert.ToString(ps.parkingSpaceX); cm.parkingSpaceY = Convert.ToString(ps.parkingSpaceY); cm.parkingSpaceZ = Convert.ToString(ps.parkingSpaceZ); cm.frontWheelbase = frontwheelbase; cm.rearWheelbase = rearwheelbase; PLC.SetMessage(cm); Log.WriteLog(LogType.NOT_DATABASE, LogFile.LOG, "取车流程:" + queueCmd.LicenseNum + "取车"); UILogServer.ins.info("取车流程:" + queueCmd.LicenseNum + "取车"); //等待PLC取车完成信号 if (!waitForFetchCompletionSignal(queueCmd, ps.parkingSpaceID, ref robotError, 1)) { Rollback(queueCmd, ps.parkingSpaceID, true, false, null); return; } //取车完成 status = 5; ControlMessage cm2 = new ControlMessage(); cm2.status = status; //先手动赋值 cm2.RobotID = 1; //机械手复位 PLC.SetMessage(cm2); if (!waitForFetchCompletionSignal(queueCmd, ps.parkingSpaceID, ref robotError, 0)) { Rollback(queueCmd, ps.parkingSpaceID, true, false, null); return; } //释放机械手 Robot.robot1.occupied = false; Robot.robot1.waitCount -= 1; //释放缓冲位与车位,缓冲位ID暂用车位X代替 if (ParkingSpaceManager.ins == null || !ParkingSpaceManager.ins.SetParkingSpace(ps.parkingSpaceID, 0) || ParkingBufferManager.ins == null || !ParkingBufferManager.ins.ReleaseParkingBuffer(ps.parkingSpaceX)) { Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "车位异常,请检查"); UILogServer.ins.error("车位异常,请检查"); } Log.WriteLog(LogType.NOT_DATABASE, "取车流程:号牌:" + queueCmd.LicenseNum + "取车完成"); UILogServer.ins.info("取车流程:号牌:" + queueCmd.LicenseNum + "取车完成"); //自动化测试用 //ManualParkingSimul.ins.Update(Int32.Parse(queueCmd.LicenseNum.Substring(2, 1))); //ParkingSimul.ins.Update(Int32.Parse(queueCmd.LicenseNum.Substring(2, 1))); int freeSpaceCount = ParkingSpaceManager.ins.GetFreeSpaceCount(); //数据库更新 lock (Parking_Space.RecordLock) { lock (Parking_Space.spaceLock) { if (!queueCmd.manual) { string updateParkingSpaceStateSql = ""; string updateFreeSpaceSql = ""; string updateVehicleStateSql = ""; string updateParkingRecordsSql = ""; //取车事务 try { List strs = new List(); updateParkingSpaceStateSql = "update parkingspace set parkingSpaceState = 1 where parkingSpaceID = '" + ps.parkingSpaceID + "'"; updateFreeSpaceSql = "update garage set garageFreeSpace = '" + freeSpaceCount + "' where garageID = '" + garageID + "'"; updateVehicleStateSql = "update vehicle set vehiclepParkState = 0 where numberPlate = '" + queueCmd.LicenseNum + "'"; updateParkingRecordsSql = "update parkingrecords set parkingRecordsState = 6,realGetTime = '" + queueCmd.TimeRecord + "'where parkingRecordsID = '" + queueCmd.parkingRecordsID + "'"; strs.Add(updateParkingSpaceStateSql); strs.Add(updateFreeSpaceSql); strs.Add(updateVehicleStateSql); strs.Add(updateParkingRecordsSql); object result = DBOperation.UpdateTransaction(EntityForCore.remoteBQ, strs); if (!(bool)result) { //写日志记录sql,以待之后处理 Log.WriteLog(LogType.DATABASE, "0", updateParkingSpaceStateSql); Log.WriteLog(LogType.DATABASE, "0", updateFreeSpaceSql); Log.WriteLog(LogType.DATABASE, "0", updateVehicleStateSql); Log.WriteLog(LogType.DATABASE, "0", updateParkingRecordsSql); } } catch (Exception ex) { Console.WriteLine(ex.Message + "取车事务处理失败"); } } else { string updateParkingSpaceStateSql = ""; string updateFreeSpaceSql = ""; string updateVehicleStateSql = ""; string updateParkingRecordsSql = ""; //取车事务 try { List strs = new List(); updateParkingSpaceStateSql = "update parkingspace set parkingSpaceState = 0 where parkingSpaceID = '" + ps.parkingSpaceID + "'"; updateFreeSpaceSql = "update garage set garageFreeSpace = '" + freeSpaceCount + "' where garageID = '" + garageID + "'"; updateVehicleStateSql = "update vehicle set vehiclepParkState = 0 where numberPlate = '" + queueCmd.LicenseNum + "'"; updateParkingRecordsSql = "update parkingrecords set parkingRecordsState = 6,realGetTime = '" + queueCmd.TimeRecord + "'where parkingRecordsID = '" + queueCmd.parkingRecordsID + "'"; strs.Add(updateParkingSpaceStateSql); strs.Add(updateFreeSpaceSql); strs.Add(updateVehicleStateSql); strs.Add(updateParkingRecordsSql); DBOperation.UpdateTransaction(EntityForCore.localBQ, strs); } catch (Exception ex) { Console.WriteLine(ex.Message + "取车事务处理失败"); //写日志记录sql,以待之后处理 Log.WriteLog(LogType.DATABASE, "0", updateParkingSpaceStateSql); Log.WriteLog(LogType.DATABASE, "0", updateFreeSpaceSql); Log.WriteLog(LogType.DATABASE, "0", updateVehicleStateSql); Log.WriteLog(LogType.DATABASE, "0", updateParkingRecordsSql); } } } Thread.Sleep(1000); } } } /// /// 异常命令处理类 /// public class ExceptionCmd : AbstractCmd { public override void executeCmd(Command queueCmd) { if (queueCmd.commandType == 'e') { //int userId = Convert.ToInt32(queueCmd.userID); ////过期用户指令 //oper.InsertToMessageQueue(DBConnection.remoteConf, userId, "停车异常,请联系管理员!", 2); ////未能停车,将车辆状态复位 //oper.UpdateVehicleParkState(DBConnection.remoteConf, queueCmd.LicenseNum, 0); //Log.WriteLog(LogType.NOT_DATABASE, LogFile.ERROR, "过期用户指令,车牌号:" + queueCmd.LicenseNum); //UILogServer.ins.error("过期用户指令,车牌号:" + queueCmd.LicenseNum); ////continue; } } } /// /// 简单命令工厂 /// public class SimpleCMDFactory { //DBOperation oper = new DBOperation(); public AbstractCmd createCmd(Command queueCmd) { AbstractCmd abstractCmd = null; if (queueCmd.commandType == 's') { abstractCmd = new StopCmd(); } if (queueCmd.commandType == 'f') { abstractCmd = new FetchCmd(); } if (queueCmd.commandType == 'e') { abstractCmd = new ExceptionCmd(); } return abstractCmd; } } }