using Aucma.Scada.Model.domain; using HighWayIot.Config; using HighWayIot.Log4net; using HighWayIot.Plc; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Aucma.Scada.Business { /// /// 入库任务处理 /// internal sealed class InStoreTaskHandle { #region 单例实现 private static readonly Lazy lazy = new Lazy(() => new InStoreTaskHandle()); public static InStoreTaskHandle 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; #endregion #region 私有变量 private Dictionary _plcDictionary = new Dictionary(); private Dictionary shellKeyValuePairs = new Dictionary(); private Dictionary linerKeyValuePairs = 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 InStoreFinsih(string storeCode, string taskCode); public event InStoreFinsih InStoreFinsihEvent; /// /// 入库应答,PLC收到下发的入库任务后进行应答 /// /// /// public delegate void InStoreAnswer(string storeCode, string taskCode); public event InStoreAnswer InStoreAnswerEvent; #endregion private InStoreTaskHandle() { _plcDictionary = _pool.GetAll(); RealReadPlcSpace(); } #region 箱壳入库任务下发处理 public bool SendShellTask_InStore(RealTaskInfo taskInfo) { bool result = false; try { IPlc _plc = _plcDictionary[taskInfo.storeCode]; if (_plc != null) { if (_plc.IsConnected) { //写入货道号 _plc.writeStringByAddress(plcConfig.in_shell_spaceCode, taskInfo.spaceCode); //写入应答字 _plc.writeInt32ByAddress(plcConfig.in_shell_answer, 1); //写入任务号 _plc.writeStringByAddress(plcConfig.in_shell_task, taskInfo.taskCode); //写入完成后读取应答字进行复位 ReadShellAnswer_InStore(taskInfo); result = true; } else { logHelper.Info($"仓库{taskInfo.storeCode};PLC未连接"); } } else { logHelper.Info($"PLC信息为空,通过{taskInfo.storeCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("箱壳入库任务下发异常", ex); } return result; } /// /// 读取箱壳入库应答 /// private void ReadShellAnswer_InStore(RealTaskInfo taskInfo) { lock (string.Empty) { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; try { Task.Run(() => { if (_plc != null) { if (_plc.IsConnected) { do { //读取PLC应答字为2时,上位机清空写入的入库内容 if (_plc.readInt32ByAddress(plcConfig.in_shell_answer) == 2) { //写入货道号 _plc.writeStringByAddress(plcConfig.in_shell_spaceCode, string.Empty); //写入应答字 _plc.writeInt32ByAddress(plcConfig.in_shell_answer, 0); //写入任务号 _plc.writeStringByAddress(plcConfig.in_shell_task, string.Empty); isFlag = false; WritePlc(taskInfo.storeCode, taskInfo.spaceCode, false); //ReadShellFinish_InStore(taskCode); InStoreAnswerEvent?.Invoke(appConfig.shellStoreCode, taskInfo.taskCode); shellTaskInfos.Add(taskInfo); } Thread.Sleep(1000); } while (isFlag); } else { logHelper.Info($"仓库{appConfig.shellStoreCode};PLC未连接"); } } else { logHelper.Info($"PLC信息为空,通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息"); } }); } catch (Exception ex) { logHelper.Error("读取箱壳入库应答字异常", ex); } } } #endregion #region 内胆入库任务处理 /// /// 内胆入库任务下发 /// /// public bool SendLinerTask_InStore(RealTaskInfo taskInfo) { bool result = false; try { IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; if (_plc != null) { if (_plc.IsConnected) { //写入货道号 _plc.writeStringByAddress(plcConfig.in_liner_spaceCode, taskInfo.spaceCode); //写入应答字 _plc.writeInt32ByAddress(plcConfig.in_liner_answer, 1); //写入任务号 _plc.writeStringByAddress(plcConfig.in_liner_task, taskInfo.taskCode); //写入完成后读取应答字进行复位 ReadLinerAnswer_InStore(taskInfo); result = true; } else { logHelper.Info($"仓库{taskInfo.storeCode};PLC未连接"); } } else { logHelper.Info($"PLC信息为空,通过{taskInfo.storeCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("内胆入库任务下发异常", ex); } return result; } /// /// 读取内胆入库应答 /// private void ReadLinerAnswer_InStore(RealTaskInfo taskInfo) { lock (string.Empty) { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; try { Task.Run(() => { if (_plc != null) { if (_plc.IsConnected) { do { //读取PLC应答字为2时,上位机清空写入的入库内容 if (_plc.readInt32ByAddress(plcConfig.in_liner_answer) == 2) { //写入货道号 _plc.writeStringByAddress(plcConfig.in_liner_spaceCode, string.Empty); //写入应答字 _plc.writeInt32ByAddress(plcConfig.in_liner_answer, 0); //写入任务号 _plc.writeStringByAddress(plcConfig.in_liner_task, string.Empty); isFlag = false; //ReadLinerFinish_InStore(taskCode); WritePlc(taskInfo.storeCode, taskInfo.spaceCode, false); InStoreAnswerEvent?.Invoke(appConfig.linerStoreCode, taskInfo.taskCode); linerTaskInfos.Add(taskInfo); } Thread.Sleep(1000); } while (isFlag); } else { logHelper.Info($"仓库{appConfig.linerStoreCode};PLC未连接"); } } else { logHelper.Info($"PLC信息为空,通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息"); } }); } catch (Exception ex) { logHelper.Error("读取内胆入库应答字异常", ex); } } } #endregion #region 读取PLC入库完成 Delete By Wenjy 2023-11-08 15:05:00,经讨论入库完成改为监测在途数量变化 /// /// 读取箱壳入库完成 /// /*private void ReadShellFinish_InStore(string taskCode) { lock (string.Empty) { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; shellTaskCode = taskCode; try { Task.Run(() => { if (_plc != null) { if (_plc.IsConnected) { do { //读取PLC入库任务完成 if (_plc.readInt32ByAddress(plcConfig.in_shell_finish) == 1) { _plc.writeInt32ByAddress(plcConfig.in_shell_finish, 0); //string taskCode = _plc.readStringByAddress(plcConfig.out_shell_task, 10); InStoreFinsihEvent?.Invoke(appConfig.shellStoreCode, taskCode); isFlag = false; } Thread.Sleep(1000); } while (isFlag); } else { logHelper.Info($"仓库{appConfig.shellStoreCode};PLC未连接"); } } else { logHelper.Info($"PLC信息为空,通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息"); } }); } catch (Exception ex) { logHelper.Error("读取箱壳入库完成异常", ex); } } }*/ /// /// 读取内胆入库完成 /// /*private void ReadLinerFinish_InStore(string taskCode) { lock (string.Empty) { try { Task.Run(() => { bool isFlag = true; IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; if (_plc != null) { if (_plc.IsConnected) { do { //读取PLC入库任务完成 if (_plc.readInt32ByAddress(plcConfig.in_liner_finish) == 1) { _plc.writeInt32ByAddress(plcConfig.in_liner_finish, 0); //string taskCode = _plc.readStringByAddress(plcConfig.in_liner_task, 10); InStoreFinsihEvent?.Invoke(appConfig.linerStoreCode, taskCode); isFlag = false; } Thread.Sleep(1000); } while (isFlag); } else { logHelper.Info($"仓库{appConfig.linerStoreCode};PLC未连接"); } } else { logHelper.Info($"PLC信息为空,通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息"); } }); } catch (Exception ex) { logHelper.Error("读取内胆入库完成异常", ex); } } }*/ #endregion #region 监测PLC在途数量变化,完成入库任务 private void RealReadPlcSpace() { Thread.Sleep(1000); Task.Run(() => { while (true) { RealReadShellPlcSpace(); Thread.Sleep(500); } }); Task.Run(() => { while (true) { RealReadLinerPlcSpace(); Thread.Sleep(500); } }); } /// /// 读取箱壳已下发任务的货道信息,读取后将货道编号及在途数量写入Dictionary进行比较,在途数减少则入库完成 /// private void RealReadShellPlcSpace() { if (shellTaskInfos != null) { List spaceCodes = shellTaskInfos.Select(x => x.spaceCode).Distinct().ToList(); for (int i = 0; i < spaceCodes.Count; i++) { string spaceCode = spaceCodes[i]; BaseSpaceInfo spaceInfo = new BaseSpaceInfo() { storeCode = appConfig.shellStoreCode, spaceCode = spaceCode }; spaceInfo = ReadSpaceInfoByPlc(spaceInfo); if (shellKeyValuePairs.ContainsKey(spaceInfo.spaceCode)) { shellKeyValuePairs.TryGetValue(spaceInfo.spaceCode, out int value); //判断前次读取的数据和当前数据,如果前次数据大于当前数据则代表入库完成,然后筛选任务中对应货道的首个任务进行完成 //如果前次数据不大于当前数据则更新字典中存放的数据 if (value > spaceInfo.onRouteAmount) { //筛选任务 var list = shellTaskInfos.Where(x => x.spaceCode == spaceInfo.spaceCode).ToList(); if (list.Count > 0) { RealTaskInfo taskInfo = list.OrderBy(x => x.createTime).First(); InStoreFinsihEvent?.Invoke(taskInfo.storeCode, taskInfo.taskCode); shellTaskInfos.Remove(taskInfo); } shellKeyValuePairs.Remove(spaceInfo.spaceCode); } else { shellKeyValuePairs[spaceInfo.spaceCode] = spaceInfo.onRouteAmount; } } else { shellKeyValuePairs.Add(spaceInfo.spaceCode, spaceInfo.onRouteAmount); } } } } /// /// 读取内胆已下发任务的货道信息,读取后将货道编号及在途数量写入Dictionary进行比较,在途数减少则入库完成 /// private void RealReadLinerPlcSpace() { if (linerTaskInfos != null) { List spaceCodes = linerTaskInfos.Select(x => x.spaceCode).Distinct().ToList(); for (int i = 0; i < spaceCodes.Count; i++) { string spaceCode = spaceCodes[i]; BaseSpaceInfo spaceInfo = new BaseSpaceInfo() { storeCode = appConfig.linerStoreCode, spaceCode = spaceCode }; spaceInfo = ReadSpaceInfoByPlc(spaceInfo); if (linerKeyValuePairs.ContainsKey(spaceInfo.spaceCode)) { linerKeyValuePairs.TryGetValue(spaceInfo.spaceCode, out int value); //判断前次读取的数据和当前数据,如果前次数据大于当前数据则代表入库完成,然后筛选任务中对应货道的首个任务进行完成 //如果前次数据不大于当前数据则更新字典中存放的数据 if (value > spaceInfo.onRouteAmount) { //筛选任务 var list = linerTaskInfos.Where(x => x.spaceCode == spaceInfo.spaceCode).ToList(); if (list.Count > 0) { RealTaskInfo taskInfo = list.OrderBy(x => x.createTime).First(); InStoreFinsihEvent?.Invoke(taskInfo.storeCode, taskInfo.taskCode); linerTaskInfos.Remove(taskInfo); } linerKeyValuePairs.Remove(spaceInfo.spaceCode); } else { linerKeyValuePairs[spaceInfo.spaceCode] = spaceInfo.onRouteAmount; } } else { linerKeyValuePairs.Add(spaceInfo.spaceCode, spaceInfo.onRouteAmount); } } } } #endregion /// /// 通过PLC获取货道信息 /// /// /// public BaseSpaceInfo ReadSpaceInfoByPlc(BaseSpaceInfo spaceInfo) { var spaceAddress = spaceConfig.GetSpaceAddress(spaceInfo.storeCode, spaceInfo.spaceCode); IPlc _plc = _plcDictionary[spaceInfo.storeCode]; if (_plc != null) { if (_plc.IsConnected) { spaceInfo.spaceStock = _plc.readInt32ByAddress(spaceAddress.onStore); spaceInfo.onRouteAmount = _plc.readInt32ByAddress(spaceAddress.onRoute); spaceInfo.spaceStatus = _plc.readInt32ByAddress(spaceAddress.spaceStatus); } } return spaceInfo; } /// /// 测试方法,联调时不用 /// /// /// /// public void WritePlc(string storeCode, string spaceCode, bool flag) { var spaceAddress = spaceConfig.GetSpaceAddress(storeCode, spaceCode); IPlc _plc = _plcDictionary[storeCode]; if (_plc != null) { if (_plc.IsConnected) { var spaceStock = _plc.readInt32ByAddress(spaceAddress.onStore); var onRouteAmount = _plc.readInt32ByAddress(spaceAddress.onRoute); if (flag) { _plc.writeInt32ByAddress(spaceAddress.onStore, spaceStock + 1); //_plc.writeInt32ByAddress(spaceAddress.onRoute, onRouteAmount - 1); } else { _plc.writeInt32ByAddress(spaceAddress.onRoute, onRouteAmount + 1); } } } } } }