using HH.WCS.Mobox3.DoubleCoin.device; using HH.WCS.Mobox3.DoubleCoin.dispatch; using HH.WCS.Mobox3.DoubleCoin.models; using HH.WCS.Mobox3.DoubleCoin.process; using HH.WCS.Mobox3.DoubleCoin.util; using HH.WCS.Mobox3.DoubleCoin.wms; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using static HH.WCS.Mobox3.DoubleCoin.api.ApiModel; namespace HH.WCS.Mobox3.DoubleCoin.core { internal class WCSCore { public static ReturnResult OperateAgvTaskStatus(AgvTaskState model) { var result = new ReturnResult(); try { if (model.state == 1023 || model.state == 1025) { //无任务号请求(交管,交通管理-开门关门,无任务号) if(!DeviceProcess.OpenOrCloseDoor(model.lock_no, model.state)) { result.ResultCode = 2; result.ResultMsg = $"TCP通讯写入失败,安全门编号{model.lock_no},状态{model.state}"; LogHelper.Info(result.ResultMsg, "API"); return result; } } else if (model.state == 1012) { Task task5 = Task.Run(() => { PostScanCode(model.task_no, model.forklift_no);//反馈扫码结果 }); } else if (model.state == 1004)//称重货位起点终点更改(余料回库和拆盘回库) { Task task6 = Task.Run(() => { UpdateStartEnd(model.forklift_no); }); } else if (model.state == 1103) { Task task7 = Task.Run(() => { CheckWeightDevice(model.forklift_no); }); } else { var TN_Task = WCSHelper.GetTask(model.task_no);//根据当前model编号查询任务 if (TN_Task != null) { if (model.state <= 8) { //有任务状态请求 switch (model.state) { case 1: WCSHelper.Begin(TN_Task, model.forklift_no);//已推送的任务的状态改成执行 Task task4 = Task.Run(() => { OpenScanCode(model.task_no, model.forklift_no);//开启扫码 }); break; case 3: WCSHelper.UpdateStatus(TN_Task, "开始取货");//任务状态改成开始取货 break; case 4: WCSHelper.UpdateStatus(TN_Task, "取货完成");//任务状态改成取货完成 TaskProcess.OperateStatus(TN_Task, 4);//起点容器货位解绑,解锁起点 Task task3 = Task.Run(() => { EmptyInStackArea(TN_Task); }); Task task1 = Task.Run(() => { returnS7Ok(TN_Task); }); break; case 5: WCSHelper.UpdateStatus(TN_Task, "开始卸货");//任务状态改成开始卸货 break; case 6: WCSHelper.UpdateStatus(TN_Task, "卸货完成");//任务状态改成卸货完成 TaskProcess.OperateStatus(TN_Task, 6);//终点容器货位绑定,解锁终点 Task task2 = Task.Run(() => { if (TN_Task.S_TYPE == "空托出库入线") { var ip = Settings.ProductionLines.FirstOrDefault(a => a.PointIn == TN_Task.S_END_LOC).ProductionLine_IP; if (!Settings.S7TestMoni) { S7Helper.WriteBytes(ip, 10, 2, new byte[] { 0, 11, 1 }); } } }); Task task29 = Task.Run(() => { if (TN_Task.S_TYPE == "余料下线入库") { SpecHelper.UpdateSurplusDetail(TN_Task.S_CODE); } }); Task task30 = Task.Run(() => { if (TN_Task.S_TYPE.Contains("回炉")) { SpecHelper.UpdateRemeltDetail(TN_Task.S_CODE); } }); Task task31 = Task.Run(() => { if (TN_Task.S_TYPE == "满托出库上线") { SpecHelper.UpdateComponentDetail(TN_Task.S_CODE); } }); Task task12 = Task.Run(() => { if (TN_Task.S_TYPE == "PDA满托下线入库" || TN_Task.S_TYPE == "PLC满托下线入库") { SpecHelper.UpdateComponentDetail(TN_Task.S_CODE); } }); Task task19 = Task.Run(() => { if (TN_Task.S_END_AREA == Settings.Areas[1]) { SpecHelper.UpdateInventoryM_RuKu(TN_Task.S_CNTR_CODE); } else { LogHelper.Info($"更新WMS库存明细的入库时间跳过,TN_Task.S_END_AREA: {TN_Task.S_END_AREA }不等于 Settings.Areas[1]:{Settings.Areas[1]}"); } }); break; case 2: WCSHelper.End(TN_Task);//任务状态改成结束 break; case 7: Task task10 = Task.Run(() => { if (TN_Task.S_END_AREA == Settings.Areas[1])//终点是满托缓存库区 { TaskProcess.OperateStatus(TN_Task, 7);//异常处理 } else if(TN_Task.S_START_AREA == Settings.Areas[1])//起点是满托缓存库区 { if (!WCSHelper.CheckActionRecordExist(TN_Task.S_CODE, 4))//未取货完成 { WCSHelper.Fail(TN_Task);//任务状态改成错误 } else { WCSHelper.End(TN_Task);//任务状态改成结束 LocationHelper.BindingLoc(TN_Task.S_END_LOC, TN_Task.S_CNTR_CODE.Split(',').ToList());// 绑定终点容器货位 } LocationHelper.UnLockLoc(TN_Task.S_END_LOC); LocationHelper.UnLockLoc(TN_Task.S_START_LOC);//解锁起点终点 } else { if (!WCSHelper.CheckActionRecordExist(TN_Task.S_CODE, 4))//未取货完成 { WCSHelper.Fail(TN_Task);//任务状态改成错误 var db = new SqlHelper().GetInstance(); var cginfo = db.Queryable().First(a => a.S_CNTR_CODE == TN_Task.S_CNTR_CODE); if (cginfo != null) { db.Deleteable().Where(it => it.S_ID == cginfo.S_ID || it.RFID == TN_Task.S_CNTR_CODE).ExecuteCommand(); } else { db.Deleteable().Where(it => it.RFID == TN_Task.S_CNTR_CODE).ExecuteCommand(); } } else { WCSHelper.End(TN_Task);//任务状态改成结束 LocationHelper.BindingLoc(TN_Task.S_END_LOC, TN_Task.S_CNTR_CODE.Split(',').ToList()); } LocationHelper.UnLockLoc(TN_Task.S_END_LOC); LocationHelper.UnLockLoc(TN_Task.S_START_LOC);//解锁起点终点 } }); break; case 8: var res = NDCApi.CancelOrder(TN_Task.S_CODE); if (res != null && (res.err_code == 50002 || res.err_code == 0)) { LogHelper.Info($"异常和取消操作 请求结果成功{res}"); } else { LogHelper.Info($"异常和取消操作 请求结果失败{res}"); } break; } WCSHelper.AddActionRecord(model.task_no, model.state, model.forklift_no, model.ext_data); //调用第三方接口(如果有)TaskProcess.ReportStatus,添加任务动作关系表 } else { //安全请求等 TaskProcess.OperateReq(model.task_no, model.state, model.forklift_no, model.ext_data); } } else { result.ResultCode = 1; result.ResultMsg = $"根据Model.No未找到对应的任务,{model.task_no}"; LogHelper.Info(result.ResultMsg,"API"); return result; } } result.ResultCode = 0; result.ResultMsg = "success"; LogHelper.Info(result.ResultMsg, "API"); return result; } catch(Exception ex) { result.ResultCode = -1; result.ResultMsg = $"发生了异常:+{ex.Message}"; LogHelper.Info(result.ResultMsg, "Error"); return result; } } /// /// 校验称重设备 /// /// private static void CheckWeightDevice(string forklift_no) { try { var db = new SqlHelper().GetInstance(); var task = db.Queryable().First(a => a.S_EQ_NO == forklift_no && a.N_B_STATE == 2); if (task == null) { LogHelper.Info($"未找到任务号信息,对应车号:{forklift_no}"); return; } var device = Settings.WeightDevices[0]; if (device == null) { LogHelper.Info($"未在配置文件里找到称重设备信息"); return; } var readRes = S7Helper.ReadBytes(device.WeightDevice_IP, 20, 6, 2); LogHelper.Info($"称重设备DB20第6位2Byte,读取结果:{BitConverter.ToString(readRes)}"); if (readRes.Length==2 && readRes[1] == 1) { var res2 = NDCApi.ChangeOrderParam(task.S_CODE, 6, "1");//添加新命令 if (res2.err_code != 0)//添加新命令 { LogHelper.Info($"更改参数命令失败,参数6改成1"); return; } else { LogHelper.Info($"更改参数命令成功,参数6改成1"); } } else { LogHelper.Info($"称重设备读取结果不为1,无法参数6改成1:{BitConverter.ToString(readRes)}"); } } catch(Exception ex) { LogHelper.Info($"发生了异常:{ex.Message}"); } } private async static void UpdateStartEnd(string forklift_no) { try { var db = new SqlHelper().GetInstance(); var task = db.Queryable().First(a => a.S_EQ_NO == forklift_no && a.N_B_STATE ==2); if (task == null) { LogHelper.Info($"未找到任务号信息,对应车号:{forklift_no}"); return; } var startLoc = db.Queryable().First(a => a.S_CODE == Settings.WeightDevices[0].Point); if (startLoc == null) { LogHelper.Info($"未找到任务号的起点信息,对应任务号:{task.S_CODE}"); return; } var device = Settings.WeightDevices[0]; if (device == null) { LogHelper.Info($"未在配置文件里找到称重设备信息"); return; } if( S7Helper.WriteBytes(device.WeightDevice_IP, 10, 4, new byte[] { 0x01 })) { LogHelper.Info($"称重设备DB10写入偏移量4为1成功"); await Task.Delay(500); // 延迟 0.5 秒,让它称重 var normal = S7Helper.ReadBytes(device.WeightDevice_IP, 20, 9, 1); if (normal.Length == 1 && normal[0] != 1 && normal[0] != 0) { LogHelper.Info($"称重设备DB20读取9,结果是:{normal[0]},结果不为1或0,视为设备异常"); return; } var readRes = S7Helper.ReadBytes(device.WeightDevice_IP, 20, 26, 2); LogHelper.Info($"称重设备读取结果DB20读取26位2位:{BitConverter.ToString(readRes)}"); if (readRes.Length == 2) { var cginfo = db.Queryable().First(a => a.S_CNTR_CODE == task.S_CNTR_CODE); if (cginfo == null) { LogHelper.Info($"未找到容器货品信息,该容器{task.S_CNTR_CODE}"); return; } var targetQty = BitConverter.ToInt16(readRes, 0); if (targetQty <= 0) { LogHelper.Info($"称重小于等于0,称重{targetQty}"); return; } var endloc = db.Queryable().First(a => a.S_AREA_CODE == (cginfo.N_ITEM_STATE == 2 ? Settings.Areas[8] : Settings.Areas[1]) && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.N_CURRENT_NUM == 0); using (var trans = db.Ado.UseTran()) { if (cginfo.S_Separate_ID != null && cginfo.S_Separate_ID.Length > 0) { var target = db.Queryable().First(a => a.S_Separate_ID == cginfo.S_Separate_ID && a.S_CNTR_CODE != cginfo.S_CNTR_CODE); if (target.N_ITEM_STATE == 2) { target.F_QTY = cginfo.F_QTY - targetQty; if(db.Updateable(target).UpdateColumns(it => new { it.F_QTY }).ExecuteCommand() <= 0) { LogHelper.Info($"更新被拆的新容器的物料重量失败,任务号:{task.S_CODE},起点{task.S_START_LOC},终点{task.S_END_LOC}"); trans.RollbackTran(); return; } } } cginfo.F_QTY = targetQty; if(db.Updateable(cginfo).UpdateColumns(it => new { it.F_QTY }).ExecuteCommand() <= 0) { LogHelper.Info($"更新当前容器的物料重量失败,任务号:{task.S_CODE},起点{task.S_START_LOC},终点{task.S_END_LOC}"); trans.RollbackTran(); return; } Task task31 = Task.Run(() => { if (task.S_TYPE == "余料下线入库") { SpecHelper.UpdateSurplusDetail(task.S_CODE, targetQty); } }); task.S_START_LOC = startLoc.S_CODE; task.S_START_AREA = startLoc.S_AREA_CODE; task.S_END_LOC = endloc.S_CODE; task.S_END_AREA = endloc.S_AREA_CODE; if (db.Updateable(task).UpdateColumns(it => new { it.S_START_LOC, it.S_END_LOC, it.S_START_AREA, it.S_END_AREA }).ExecuteCommand() > 0) { LogHelper.Info($"起点终点参数更新成功,任务号:{task.S_CODE},起点{task.S_START_LOC},终点{task.S_END_LOC}"); } else { LogHelper.Info($"起点终点参数更新失败,任务号:{task.S_CODE},起点{task.S_START_LOC},终点{task.S_END_LOC}"); trans.RollbackTran(); return; } var res2 = NDCApi.ChangeOrderParam(task.S_CODE, 1, startLoc.S_AGV_SITE); if (res2 == null || res2.err_code != 0)//起点 { LogHelper.Info($"更改参数命令失败,参数1改成起点{startLoc.S_AGV_SITE}"); trans.RollbackTran(); return; } else { LogHelper.Info($"更改参数命令成功,参数1改成起点{startLoc.S_AGV_SITE}"); } res2 = NDCApi.ChangeOrderParam(task.S_CODE, 2, endloc.S_AGV_SITE);//终点变起点 if (res2 == null || res2.err_code != 0)//终点变起点 { LogHelper.Info($"更改参数命令失败,参数2改成终点{ endloc.S_AGV_SITE}"); trans.RollbackTran(); return; } else { LogHelper.Info($"更改参数命令成功,参数2改成终点{endloc.S_AGV_SITE}"); } res2 = NDCApi.ChangeOrderParam(task.S_CODE, 6, "2");//添加新命令 if (res2.err_code != 0)//添加新命令 { LogHelper.Info($"更改参数命令失败,参数6改成2"); trans.RollbackTran(); return; } else { LogHelper.Info($"更改参数命令成功,参数6改成2"); } res2 = NDCApi.ChangeOrderParam(task.S_CODE, 6, "1");//添加新命令 if (res2.err_code != 0)//添加新命令 { LogHelper.Info($"更改参数命令失败,参数6改成1"); trans.RollbackTran(); return; } else { LogHelper.Info($"更改参数命令成功,参数6改成1"); } trans.CommitTran(); return; } } else { LogHelper.Info($"称重设备读取结果,不等于2个Byte"); } } else { LogHelper.Info($"称重设备DB10写入偏移量4为1失败"); } } catch(Exception ex) { LogHelper.Info($"发生了异常:{ex.Message}"); } } /// /// 反馈扫码结果 /// /// /// private static void PostScanCode(string task_no, string forklift_no) { try { var dic = new List(); var agv = Settings.AgvScanDevices.FirstOrDefault(a => a.AgvCode == forklift_no); if (agv == null) { LogHelper.Info($"在配置表中未找到该AGV:{forklift_no}的信息"); return; } if (!TcpServer.saoMa.ContainsKey(agv.ScanAddress)) { TcpServer.saoMa.Add(agv.ScanAddress,3); } var res = NDCApi.ChangeOrderParam(task_no, 6, TcpServer.saoMa[agv.ScanAddress].ToString());//添加新命令 if (res != null && (res.err_code == 0 || res.err_code == 50009)) { //推送成功 LogHelper.Info($"NDC反馈扫码结果成功,扫码结果:{TcpServer.saoMa[agv.ScanAddress].ToString()}"); } else { LogHelper.Info($"NDC反馈扫码结果失败,扫码结果:{TcpServer.saoMa[agv.ScanAddress].ToString()}"); } TcpServer.saoMa[agv.ScanAddress] = 3; TcpServer.isCheck[agv.ScanAddress] = false; } catch (Exception ex) { LogHelper.Info($"发生了异常:{ex.Message}"); } } /// /// 任务分发,根据调度类型发给不同的调度系统 /// internal static void Dispatch() { //查询任务 //获取所有等待的任务 var list = WCSHelper.GetWaitingTaskList(); LogHelper.Info("等待任务信息" + JsonConvert.SerializeObject(list), "API"); if (list.Count > 0) { list.ForEach(task => { //使用自定义任务推送 TaskProcess.SendTask(task);//调度NDC或杭奥或国自设备 //TaskProcess.SendGZTask(task);///调度国自设备 }); } else { LogHelper.Info("暂无任务"); } } /// /// 回复S7取货完成关闭信号 /// /// public static void returnS7Ok(TN_Task tN_Task) { if (tN_Task.S_TYPE == "满托下线入库") { var ProductionLine = Settings.ProductionLines.FirstOrDefault(a => a.PointOut == tN_Task.S_START_LOC); try { if (ProductionLine ==null) { LogHelper.Info($"产线出口{tN_Task.S_START_LOC},配置文件未找到对应的PointOut值"); return; } if (!Settings.S7TestMoni) { if (S7Helper.WriteBytes(ProductionLine.ProductionLine_IP, 10, 2, new byte[] { 0, 21, 1 })) { LogHelper.Info($"产线{ProductionLine.ProductionLine_IP}写入DB10的偏移2为0, 21, 1, 取货完成,成功"); } else { LogHelper.Info($"产线{ProductionLine.ProductionLine_IP}写入DB10的偏移2为0, 21, 1, 取货完成,失败"); } } } catch (Exception ex) { LogHelper.Info($"与产线{ProductionLine.ProductionLine_IP}的S7 TCP通讯失败,发生了异常:{ex.Message}", "Error"); } } } /// /// 空托下线堆叠 /// /// public static void EmptyInStackArea(TN_Task tN_Task) { if (tN_Task.S_TYPE == "满托出库上线") { var result = new SimpleResult(); var db = new SqlHelper().GetInstance(); try { var startLocLists = db.Queryable().Where(a => a.S_AREA_CODE == Settings.Areas[6] && a.N_CURRENT_NUM >0 && a.N_LOCK_STATE==0 && a.S_LOCK_STATE == "无").ToList(); if (startLocLists.Count == 0) { LogHelper.Info($"人工托盘区暂无已绑定的空托,需要满足:货位数量大于0,未锁定的,属于库区{Settings.Areas[6]}的货位"); return; } foreach (var item in startLocLists) { //查询符合的未锁定已启用指定货区的当前数量合计后最接近容量的货位,终点 var endLoc = db.Queryable(). Where(a => a.N_CURRENT_NUM + item.N_CURRENT_NUM <= a.N_CAPACITY && a.S_AREA_CODE == Settings.Areas[3] && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y"). OrderBy(a => a.N_CURRENT_NUM + item.N_CURRENT_NUM - a.N_CAPACITY, OrderByType.Desc).First(); if (endLoc == null) { LogHelper.Info($"未找到合适的终点,需要满足:属于{Settings.Areas[3]}的未锁定的容量充足的货位"); continue; } var locCnt = db.Queryable().First(a=>a.S_LOC_CODE == item.S_CODE); if (locCnt == null) { LogHelper.Info($"货位{item.S_CODE}未绑定容器"); continue; } //创建空托下线堆叠任务 if (WCSHelper.CreateTask(item.S_CODE, endLoc.S_CODE, "空托下线堆叠", 3, locCnt.S_CNTR_CODE))//创建搬送任务,起点终点容器 { LocationHelper.LockLoc(item.S_CODE, 2);//起点出库锁, LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 LogHelper.Info($"生成空托下线堆叠任务成功,容器号{locCnt.S_CNTR_CODE},起点{item.S_CODE},终点{endLoc.S_CODE}"); } else { LogHelper.Info($"生成空托下线堆叠任务失败,容器号{locCnt.S_CNTR_CODE},起点{item.S_CODE},终点{endLoc.S_CODE}"); continue; } } } catch (Exception ex) { LogHelper.Info($"发生了异常:{ex.Message}", "Error"); } } } /// /// 开启/关闭/读卡器扫码 /// /// public static void OpenScanCode(string taskNo, string forklift_no) { try { var dic = new List(); var agv = Settings.AgvScanDevices.FirstOrDefault(a=>a.AgvCode == forklift_no); if (agv == null) { LogHelper.Info($"在配置表中未找到该AGV:{forklift_no}的信息"); return; } if (!TcpServer.isCheck.ContainsKey(agv.ScanAddress)) { TcpServer.isCheck.Add(agv.ScanAddress, false); } string code = ""; if (Settings.IsOpenScanCode) { code = "4"; TcpServer.isCheck[agv.ScanAddress] = true; } else { code = "0"; TcpServer.isCheck[agv.ScanAddress] = false; } var res = NDCApi.ChangeOrderParam(taskNo,3, code);//添加新命令 if (res != null && (res.err_code == 0 || res.err_code == 50009)) { //推送成功 LogHelper.Info($"NDC推送读卡器扫码参数变更成功,读卡器扫码是否开启:{Settings.IsOpenScanCode}"); } else { LogHelper.Info($"NDC推送读卡器扫码参数变更失败,读卡器扫码是否开启:{Settings.IsOpenScanCode}"); } } catch(Exception ex) { } } } }