using Aucma.Scada.Model.domain; using HighWayIot.Common; 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 { /// /// 入库任务处理 /// public 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; private JsonChange jsonChange = JsonChange.Instance; /// /// 实时任务 /// private IRealTaskInfoService _taskInfoService; private RegisterServices registerServices = RegisterServices.Instance; /// /// 货道信息 /// private IBaseSpaceInfoService _spaceInfoService; #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 Task RefreshShellStock(); public event RefreshShellStock RefreshShellStockEvent; /// /// 内胆实时库存刷新 /// /// public delegate Task RefreshLinerStock(); public event RefreshLinerStock RefreshLinerStockEvent; /// /// 入库完成 /// /// /// 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; public delegate void BareBoardHandle(string storeCode, bool isFlag = true); public event BareBoardHandle BareBoardHandleEvent; /// /// 库容告警 /// public delegate void SpaceCapacityAlarm(string storeCode, string spaceName); public event SpaceCapacityAlarm SpaceCapacityAlarmEvent; #endregion private InStoreTaskHandle() { _taskInfoService = registerServices.GetService(); _spaceInfoService = registerServices.GetService(); _plcDictionary = _pool.GetAll(); // RealReadFinish(); RealUpdateSpaceInfoByPlc(); ShellBareBoardHandle(); LinerBareBoardHandle(); } /// /// 实时读取plc更新数据库货道数量及在途 /// private void RealUpdateSpaceInfoByPlc() { Task.Run(() => { Thread.Sleep(2000); while (true) { List spaceList = _spaceInfoService.GetSpaceInfosByStoreCode(appConfig.shellStoreCode, appConfig.linerStoreCode); if (spaceList != null && spaceList.Count > 0) { List ShellAlarmSpaceName = new List(); List LinerAlarmSpaceName = new List(); foreach (BaseSpaceInfo spaceInfo in spaceList) { int Stock = spaceInfo.spaceStock; int OnAmount = spaceInfo.onRouteAmount; ReadSpaceInfoByPlc(spaceInfo); // 更新库存 if (Stock != spaceInfo.spaceStock || OnAmount != spaceInfo.onRouteAmount) { _spaceInfoService.UpdateSpaceInfo(spaceInfo); RefreshShellStockEvent?.Invoke(); RefreshLinerStockEvent?.Invoke(); } if ((spaceInfo.spaceCapacity - spaceInfo.spaceStock) <= 5) { if (spaceInfo.storeCode == appConfig.shellStoreCode) { ShellAlarmSpaceName.Add(spaceInfo.spaceName); } else { LinerAlarmSpaceName.Add(spaceInfo.spaceName); } } } string str = string.Empty; if (ShellAlarmSpaceName.Count > 0) { str +=$"箱壳库货道:{jsonChange.ModeToJson(ShellAlarmSpaceName)};"; } if (LinerAlarmSpaceName.Count > 0) { str += $"内胆库货道:{jsonChange.ModeToJson(LinerAlarmSpaceName)};"; } if(!string.IsNullOrEmpty(str)) { SpaceCapacityAlarmEvent?.Invoke(appConfig.shellStoreCode, str); } } Thread.Sleep(3000); } }); } #region 重新扫码时再次清除货道号,防止串货道任务 /// /// 重新扫码时再次清除货道号 /// /// /// public bool ClearSpaceCode(string storeCode) { bool result = false; try { IPlc _plc = null; _plcDictionary = _pool.GetAll(); if (storeCode == appConfig.shellStoreCode) { _plc = _plcDictionary[appConfig.shellStoreCode]; if (_plc != null) { result = _plc.writeInt32ByAddress(plcConfig.in_shell_spaceCode, 0); _plc.writeInt32ByAddress(plcConfig.in_shell_bare_board, 0); } } else if (storeCode == appConfig.linerStoreCode) { _plc = _plcDictionary[appConfig.linerStoreCode]; if (_plc != null) { result = _plc.writeInt32ByAddress(plcConfig.in_liner_spaceCode, 0); _plc.writeInt32ByAddress(plcConfig.in_liner_bare_board, 0); } } } catch (Exception ex) { logHelper.Error("读取箱壳应答字异常:" + ex.Message.ToString()); } return result; } #endregion #region 箱壳入库任务下发处理 public int SendShellTask_InStore(RealTaskInfo taskInfo) { int result = 0; try { _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[taskInfo.storeCode]; if (_plc != null) { if (_plc.readInt32ByAddress(plcConfig.in_shell_answer) == 1) { Console.WriteLine(plcConfig.in_shell_answer + " 应答字读 1"); logHelper.Info("箱壳入库应答字为1,货道号:" + plcConfig.in_shell_spaceCode + ";写" + short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入货道号 _plc.writeInt32ByAddress(plcConfig.in_shell_spaceCode, short.Parse(taskInfo.spaceCode.Substring(5, 1))); Console.WriteLine(plcConfig.in_shell_spaceCode + " 货道号写 " + short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入完成后读取应答字进行复位 ReadShellAnswer_InStore(taskInfo); result = 1; } else { result = 2; logHelper.PlcLog("应答字为2,下发新任务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; _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; try { if (_plc != null) { DateTime startTime = DateTime.Now; do { //读取PLC应答字为2时,上位机清空写入的入库内容 if (_plc.readInt32ByAddress(plcConfig.in_shell_answer) == 2) { Console.WriteLine(plcConfig.in_shell_answer + " 应答字读 2"); logHelper.PlcLog("箱壳入库应答字为2,货道号:" + plcConfig.in_shell_spaceCode + ";复位写0"); //写入货道号 _plc.writeInt32ByAddress(plcConfig.in_shell_spaceCode, 0); Console.WriteLine(plcConfig.in_shell_spaceCode + " 货道号写 0"); //写入应答字 // _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 0); _plc.writeInt32ByAddress(plcConfig.in_shell_bare_board, 0); isFlag = false; InStoreAnswerEvent?.Invoke(appConfig.shellStoreCode, taskInfo.taskCode); // shellTaskInfos.Add(taskInfo); } Thread.Sleep(500); // 检查是否超过15秒,如果超过则跳出循环 if ((DateTime.Now - startTime).TotalSeconds >= 10) { isFlag = false; // 设置标志结束循环 } } while (isFlag); } else { logHelper.Info($"PLC信息为空,通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("读取箱壳入库应答字异常", ex); } } } #endregion #region 内胆入库任务处理 /// /// 内胆入库任务下发 /// /// public int SendLinerTask_InStore(RealTaskInfo taskInfo) { int result = 0; try { _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; if (_plc != null) { if (_plc.readInt32ByAddress(plcConfig.in_liner_answer) == 1) { logHelper.PlcLog("内胆入库应答字为1,货道号:" + plcConfig.in_liner_spaceCode + ";写" + short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入货道号 _plc.writeInt32ByAddress(plcConfig.in_liner_spaceCode, short.Parse(taskInfo.spaceCode.Substring(5, 1))); //写入应答字 // _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 1); //写入任务号 // _plc.writeStringByAddress(plcConfig.in_foam_task, taskInfo.taskCode); //写入完成后读取应答字进行复位 ReadLinerAnswer_InStore(taskInfo); result = 1; } else { result = 2; logHelper.PlcLog("内胆应答字为2,下发新任务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; _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; try { DateTime startTime = DateTime.Now; if (_plc != null) { do { //读取PLC应答字为2时,上位机清空写入的入库内容 if (_plc.readInt32ByAddress(plcConfig.in_liner_answer) == 2) { logHelper.PlcLog("内胆入库应答字为2,货道号:" + plcConfig.in_liner_spaceCode + ";复位写0"); //写入货道号 _plc.writeInt32ByAddress(plcConfig.in_liner_spaceCode, 0); //写入应答字 // _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 0); _plc.writeInt32ByAddress(plcConfig.in_liner_bare_board, 0); isFlag = false; InStoreAnswerEvent?.Invoke(appConfig.linerStoreCode, taskInfo.taskCode); //ReadLinerFinish_InStore(taskCode); // WritePlc(taskInfo.storeCode, taskInfo.spaceCode, false); // linerTaskInfos.Add(taskInfo); } Thread.Sleep(500); // 检查是否超过30秒,如果超过则跳出循环 if ((DateTime.Now - startTime).TotalSeconds >= 10) { isFlag = false; // 设置标志结束循环 } } while (isFlag); } else { logHelper.Info($"PLC信息为空,通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息"); } } catch (Exception ex) { logHelper.Error("读取内胆入库应答字异常", ex); } } } #endregion #region 空板入库处理 private void ShellBareBoardHandle() { try { _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[appConfig.shellStoreCode]; Task.Run(() => { if (_plc != null) { int i = 0; while (true) { int isFlag = _plc.readInt32ByAddress(plcConfig.in_shell_bare_board); if (isFlag == 1) { i++; if (i == 35) { _plc.writeInt32ByAddress(plcConfig.in_shell_bare_board, 0); BareBoardHandleEvent?.Invoke(appConfig.shellStoreCode, false); } } else if (isFlag == 2) { _plc.writeInt32ByAddress(plcConfig.in_shell_bare_board, 0); BareBoardHandleEvent?.Invoke(appConfig.shellStoreCode); Thread.Sleep(1000); } else if (isFlag == 0) { i = 0; } Thread.Sleep(500); } } }); } catch (Exception ex) { logHelper.Error($"ShellBareBoardHandle异常:{ex.Message}"); } } private void LinerBareBoardHandle() { try { _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[appConfig.linerStoreCode]; Task.Run(() => { if (_plc != null) { int i = 0; while (true) { int isFlag = _plc.readInt32ByAddress(plcConfig.in_liner_bare_board); if (isFlag == 1) { i++; if (i == 30) { _plc.writeInt32ByAddress(plcConfig.in_liner_bare_board, 0); BareBoardHandleEvent?.Invoke(appConfig.linerStoreCode, false); } } else if (isFlag == 2) { _plc.writeInt32ByAddress(plcConfig.in_liner_bare_board, 0); BareBoardHandleEvent?.Invoke(appConfig.linerStoreCode); Thread.Sleep(1000); } else if (isFlag == 0) { i = 0; } Thread.Sleep(500); } } }); } catch (Exception ex) { logHelper.Error($"LinerBareBoardHandle异常:{ex.Message}"); } } #endregion /// /// 通过PLC获取货道信息 /// /// /// public BaseSpaceInfo ReadSpaceInfoByPlc(BaseSpaceInfo spaceInfo) { try { var spaceAddress = spaceConfig.GetSpaceAddress(spaceInfo.storeCode, spaceInfo.spaceCode); _plcDictionary = _pool.GetAll(); IPlc _plc = _plcDictionary[spaceInfo.storeCode]; // int i = _plc.readInt32ByAddress(plcConfig.in_shell_spaceCode); if (_plc != null) { spaceInfo.spaceStock = _plc.readInt32ByAddress(spaceAddress.onStore); spaceInfo.onRouteAmount = _plc.readInt32ByAddress(spaceAddress.onRoute); // spaceInfo.spaceStatus = _plc.readInt32ByAddress(spaceAddress.spaceStatus); } return spaceInfo; } catch (Exception ex) { logHelper.Error(ex.Message.ToString()); return spaceInfo; } } } }