using Aucma.Scada.Model.domain; using HighWayIot.Config; using HighWayIot.Log4net; using HighWayIot.Plc; using HighWayIot.Repository.service; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Aucma.Scada.Business { /// /// 出库任务处理 /// internal sealed class OutStoreTaskHandle { #region 单例实现 private static readonly Lazy lazy = new Lazy(() => new OutStoreTaskHandle()); public static OutStoreTaskHandle Instance { get { return lazy.Value; } } #endregion #region 对象引用 private LogHelper logHelper = LogHelper.Instance; private AppConfig appConfig = AppConfig.Instance; private PlcConfig plcConfig = PlcConfig.Instance; private PlcPool _pool = PlcPool.Instance; private PlcSpaceConfig spaceConfig = PlcSpaceConfig.Instance; private RegisterServices registerServices = RegisterServices.Instance; private IRealTaskInfoService _taskInfoService; private ICodeBindingRecordServices _codeBindingRecordServices; #endregion #region 私有变量 /// /// 字典存放PLC连接 /// private Dictionary _plcDictionary = new Dictionary(); /// /// 箱壳任务编号,PLC反馈后进行赋值 /// private string shellTaskCode = string.Empty; /// /// 内胆任务编号,PLC反馈后进行赋值 /// private string linerTaskCode = string.Empty; /// /// 已下传的任务信息 /// private List shellTaskInfos = new List(); private List linerTaskInfos = new List(); #endregion #region 委托事件 /// /// 出库完成 /// /// /// public delegate void OutStoreFinsih(string storeCode, string taskCode); public event OutStoreFinsih OutStoreFinsihEvent; /// /// 条码绑定以后更新mes计划 /// /// /// public delegate void UpdateMesPlanComplete(string taskCode); public event UpdateMesPlanComplete UpdateMesPlanCompleteEvent; /// /// PLC应答 /// /// /// public delegate void OutStoreAnswer(string storeCode, string taskCode); public event OutStoreAnswer OutStoreAnswerEvent; #endregion private OutStoreTaskHandle() { try { _plcDictionary = _pool.GetAll(); _taskInfoService = registerServices.GetService(); _codeBindingRecordServices = registerServices.GetService(); RealReadShellFinish(); RealReadLinerFinish(); //RealBindMaterialCode(); }catch (Exception ex) { Console.WriteLine($"OutStoreTaskHandle异常:{ex.Message}"); logHelper.Error("OutStoreTaskHandle异常", ex); Console.ReadLine(); } } #region 箱壳出库任务下发处理 /// /// 箱壳出库任务下发 /// /// public int SendShellTask_OutStore(RealTaskInfo taskInfo) { int result = 0; try { IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; if (_plc != null) { if (_plc.readInt32ByAddress(plcConfig.out_shell_answer) == 1) { logHelper.Info("箱壳出库应答字为1,货道号:" + plcConfig.out_shell_spaceCode + ";写" + short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入货道号 _plc.writeInt32ByAddress(plcConfig.out_shell_spaceCode, short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入出库数量 // _plc.writeInt32ByAddress(plcConfig.out_shell_amount, taskInfo.planAmount); //写入完成后读取应答字进行复位 ReadShellAnswer_OutStore(taskInfo); result = 1; } else { result = 2; logHelper.Info("应答字为2,下发新任务plc未就绪"); } } else { logHelper.Info($"PLC信息为空,通过{taskInfo.storeCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("箱壳出库任务下发异常", ex); } return result; } /// /// 读取箱壳出库应答 /// private void ReadShellAnswer_OutStore(RealTaskInfo taskInfo) { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; try { Task.Run(() => { if (_plc != null) { do { //读取PLC应答字为2时,上位机清空写入的出库内容 if (_plc.readInt32ByAddress(plcConfig.out_shell_answer) == 2) { logHelper.Info("出库应答字为2,货道号:" + plcConfig.out_shell_spaceCode + ";复位写0"); //写入货道号 _plc.writeInt32ByAddress(plcConfig.out_shell_spaceCode, 0); //写入出库数量 _plc.writeInt32ByAddress(plcConfig.out_shell_amount, 0); isFlag = false; OutStoreAnswerEvent?.Invoke(appConfig.shellStoreCode, taskInfo.taskCode); } Thread.Sleep(500); } while (isFlag); } else { logHelper.Info($"PLC信息为空,通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息"); } }); } catch (Exception ex) { logHelper.Error("读取箱壳出库应答字异常", ex); } } /// /// 读取箱壳出库完成 /// private void ReadShellFinish_OutStore(RealTaskInfo taskInfo) { lock (string.Empty) { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; shellTaskCode = taskInfo.taskCode; try { if (_plc != null) { do { //读取PLC出库任务完成 if (_plc.readInt32ByAddress(plcConfig.out_shell_finish) == 1) { _plc.writeInt32ByAddress(plcConfig.out_shell_finish, 0); //string taskCode = _plc.readStringByAddress(plcConfig.out_shell_task, 10); OutStoreFinsihEvent?.Invoke(appConfig.shellStoreCode, taskInfo.taskCode); isFlag = false; } Thread.Sleep(1000); } while (isFlag); } else { logHelper.Info($"PLC信息为空,通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("读取箱壳出库出库完成异常", ex); } } } #endregion #region 内胆出库任务处理 /// /// 内胆出库任务下发 /// /// public int SendLinerTask_OutStore(RealTaskInfo taskInfo) { int result = 0; try { IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; if (_plc != null) { if (_plc.readInt32ByAddress(plcConfig.out_liner_answer) == 1) { logHelper.Info("内胆出库应答字为1,货道号:" + plcConfig.out_shell_spaceCode + ";写" + short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入货道号 _plc.writeInt32ByAddress(plcConfig.out_liner_spaceCode, short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入出库数量 _plc.writeInt32ByAddress(plcConfig.out_liner_amount, taskInfo.planAmount); //写入完成后读取应答字进行复位 ReadLinerAnswer_OutStore(taskInfo); result = 1; } else { result = 2; logHelper.Info("内胆应答字为2,下发新任务plc未就绪"); } } else { logHelper.Info($"PLC信息为空,通过{taskInfo.storeCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("内胆出库任务下发异常", ex); } return result; } /// /// 读取内胆出库应答 /// private void ReadLinerAnswer_OutStore(RealTaskInfo taskInfo) { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; try { Task.Run(() => { if (_plc != null) { do { //读取PLC应答字为2时,上位机清空写入的出库内容 if (_plc.readInt32ByAddress(plcConfig.out_liner_answer) == 2) { logHelper.Info("出库应答字为2,货道号:" + plcConfig.out_liner_spaceCode + ";复位写0"); //写入货道号 _plc.writeInt32ByAddress(plcConfig.out_liner_spaceCode, 0); //写入出库数量 _plc.writeInt32ByAddress(plcConfig.out_liner_amount, 0); isFlag = false; OutStoreAnswerEvent?.Invoke(appConfig.linerStoreCode, taskInfo.taskCode); } Thread.Sleep(500); } while (isFlag); } else { logHelper.Info($"PLC信息为空,通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息"); } }); } catch (Exception ex) { logHelper.Error("读取内胆出库应答字异常", ex); } } /// /// 读取内胆出库完成 /// private void ReadLinerFinish_OutStore(RealTaskInfo taskInfo) { lock (string.Empty) { try { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; if (_plc != null) { do { //读取PLC出库任务完成 if (_plc.readInt32ByAddress(plcConfig.out_liner_finish) == 1) { _plc.writeInt32ByAddress(plcConfig.out_liner_finish, 0); //string taskCode = _plc.readStringByAddress(plcConfig.out_liner_task, 10); OutStoreFinsihEvent?.Invoke(appConfig.linerStoreCode, taskInfo.taskCode); isFlag = false; //linerTaskInfos.Remove(taskInfo); } Thread.Sleep(1000); } while (isFlag); } else { logHelper.Info($"PLC信息为空,通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("读取内胆出库完成异常", ex); } } } #endregion #region 出库完成 /// /// 实时读取箱壳出库完成 /// private void RealReadShellFinish() { Task.Run(() => { while (true) { //var info = shellTaskInfos.Where(x => x.taskStatus != 3).ToList(); var info = GetTaskInfoByTaskStatus(appConfig.shellStoreCode); if(info != null) { for (int i = 0; i < info.Count; i++) { var item = info[i]; ReadShellFinish_OutStore(item); Console.WriteLine($"箱壳任务:{item.taskCode};物料:{item.materialCode};出库完成"); item.taskStatus = 3; shellTaskInfos.Add(item); } } Thread.Sleep(1000); }; }); } /// /// 实时读取内胆出库完成 /// private void RealReadLinerFinish() { Task.Run(() => { while (true) { //var info = linerTaskInfos.Where(x => x.taskStatus != 3).ToList(); var info = GetTaskInfoByTaskStatus(appConfig.linerStoreCode); if(info != null) { for (int i = 0; i < info.Count; i++) { var item = info[i]; ReadLinerFinish_OutStore(item); Console.WriteLine($"内胆任务:{item.taskCode};物料:{item.materialCode};出库完成"); // item.taskStatus = 3; // linerTaskInfos.Add(item); } } Thread.Sleep(1000); }; }); } /// /// 实时绑定箱壳内胆 /// Delete By wenjy 2024-03-16 11:40:00 更改壳胆绑定逻辑,添加扫码器进行绑定 /// private void RealBindMaterialCode() { Task.Run(() => { while (true) { try { var shellTasks = GetTaskInfoByTaskStatus(appConfig.shellStoreCode, 3); var linerTasks = GetTaskInfoByTaskStatus(appConfig.linerStoreCode, 3); if (shellTasks == null || linerTasks == null) continue; RealTaskInfo shellTask = null; RealTaskInfo linerTask = null; if (shellTasks.Count > 0) { shellTask = shellTasks.First(); } if (linerTasks.Count > 0) { linerTask = linerTasks.First(); } if (shellTask != null && linerTask != null) { Console.WriteLine($"绑定箱壳:{shellTask.materialCode};内胆:{linerTask.materialCode};条码"); _codeBindingRecordServices.BindingCode(shellTask.materialCode, linerTask.materialCode); // 更新mes完成计划数 UpdateMesPlanCompleteEvent?.Invoke(shellTask.planCode); _taskInfoService.DeleteTaskInfoById(shellTask.objId); _taskInfoService.DeleteTaskInfoById(linerTask.objId); } Thread.Sleep(2000); } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); } } }); } #endregion #region 私有方法 /// /// 根据任务状态获取执行中的任务 /// /// /// s private List GetTaskInfoByTaskStatus(string storeCode, int taskStatus = 2) { List result = null; try { result = _taskInfoService.GetTaskInfosByTaskStatus(new string[] { storeCode }, appConfig.outstoreTaskType, taskStatus); } catch (Exception ex) { logHelper.Error("根据任务状态获取执行中的任务异常", ex); } return result; } /// /// 通过PLC获取货道信息 /// /// /// public BaseSpaceInfo ReadSpaceInfoByPlc(BaseSpaceInfo spaceInfo) { var spaceAddress = spaceConfig.GetSpaceAddress(spaceInfo.storeCode, spaceInfo.spaceCode); IPlc _plc = _plcDictionary[spaceInfo.storeCode]; if (_plc != null) { spaceInfo.spaceStock = _plc.readInt32ByAddress(spaceAddress.onStore); //spaceInfo.onRouteAmount = _plc.readInt32ByAddress(spaceAddress.onRoute); // spaceInfo.spaceStatus = _plc.readInt32ByAddress(spaceAddress.spaceStatus); } return spaceInfo; } #endregion } }