You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Aucma.Scada/Aucma.Scada.Business/OutStoreTaskHandle.cs

588 lines
20 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
{
/// <summary>
/// 出库任务处理
/// </summary>
internal sealed class OutStoreTaskHandle
{
#region 单例实现
private static readonly Lazy<OutStoreTaskHandle> lazy = new Lazy<OutStoreTaskHandle>(() => 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 私有变量
/// <summary>
/// 字典存放PLC连接
/// </summary>
private Dictionary<string, IPlc> _plcDictionary = new Dictionary<string, IPlc>();
/// <summary>
/// 箱壳任务编号,PLC反馈后进行赋值
/// </summary>
private string shellTaskCode = string.Empty;
/// <summary>
/// 内胆任务编号,PLC反馈后进行赋值
/// </summary>
private string linerTaskCode = string.Empty;
/// <summary>
/// 已下传的任务信息
/// </summary>
private List<RealTaskInfo> shellTaskInfos = new List<RealTaskInfo>();
private List<RealTaskInfo> linerTaskInfos = new List<RealTaskInfo>();
#endregion
#region 委托事件
/// <summary>
/// 出库完成
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
public delegate void OutStoreFinsih(string storeCode, string taskCode);
public event OutStoreFinsih OutStoreFinsihEvent;
/// <summary>
/// 条码绑定以后更新mes计划
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
public delegate void UpdateMesPlanComplete(string taskCode);
public event UpdateMesPlanComplete UpdateMesPlanCompleteEvent;
/// <summary>
/// PLC应答
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
public delegate void OutStoreAnswer(string storeCode, string taskCode);
public event OutStoreAnswer OutStoreAnswerEvent;
#endregion
private OutStoreTaskHandle()
{
try
{
_plcDictionary = _pool.GetAll();
_taskInfoService = registerServices.GetService<IRealTaskInfoService>();
_codeBindingRecordServices = registerServices.GetService<ICodeBindingRecordServices>();
RealReadShellFinish();
RealReadLinerFinish();
//RealBindMaterialCode();
}
catch (Exception ex)
{
Console.WriteLine($"OutStoreTaskHandle异常{ex.Message}");
logHelper.Error("OutStoreTaskHandle异常", ex);
Console.ReadLine();
}
}
#region 箱壳出库任务下发处理
/// <summary>
/// 箱壳出库任务下发
/// </summary>
/// <param name="taskInfo"></param>
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;
}
/// <summary>
/// 读取箱壳出库应答
/// </summary>
private void ReadShellAnswer_OutStore(RealTaskInfo taskInfo)
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.shellStoreCode];
try
{
if (_plc != null)
{
DateTime startTime = DateTime.Now;
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);
// 检查是否超过15秒如果超过则跳出循环
if ((DateTime.Now - startTime).TotalSeconds >= 8)
{
isFlag = false; // 设置标志结束循环
}
} while (isFlag);
}
else
{
logHelper.Info($"PLC信息为空通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息");
}
}
catch (Exception ex)
{
logHelper.Error("读取箱壳出库应答字异常", ex);
}
}
/// <summary>
/// 读取箱壳出库完成
/// </summary>
private void ReadShellFinish_OutStore(RealTaskInfo taskInfo)
{
lock (string.Empty)
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.shellStoreCode];
shellTaskCode = taskInfo.taskCode;
try
{
if (_plc != null)
{
DateTime startTime = DateTime.Now;
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(500);
// 检查是否超过30秒如果超过则跳出循环
if ((DateTime.Now - startTime).TotalSeconds >= 20)
{
isFlag = false; // 设置标志结束循环
}
} while (isFlag);
}
else
{
logHelper.Info($"PLC信息为空通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息");
}
}
catch (Exception ex)
{
logHelper.Error("读取箱壳出库出库完成异常", ex);
}
}
}
#endregion
#region 内胆出库任务处理
/// <summary>
/// 内胆出库任务下发
/// </summary>
/// <param name="taskInfo"></param>
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;
}
/// <summary>
/// 读取内胆出库应答
/// </summary>
private void ReadLinerAnswer_OutStore(RealTaskInfo taskInfo)
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.linerStoreCode];
try
{
if (_plc != null)
{
DateTime startTime = DateTime.Now;
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);
// 检查是否超过30秒如果超过则跳出循环
if ((DateTime.Now - startTime).TotalSeconds >= 8)
{
isFlag = false; // 设置标志结束循环
}
} while (isFlag);
}
else
{
logHelper.Info($"PLC信息为空通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息");
}
}
catch (Exception ex)
{
logHelper.Error("读取内胆出库应答字异常", ex);
}
}
/// <summary>
/// 读取内胆出库完成
/// </summary>
private void ReadLinerFinish_OutStore(RealTaskInfo taskInfo)
{
lock (string.Empty)
{
try
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.linerStoreCode];
if (_plc != null)
{
DateTime startTime = DateTime.Now;
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);
// 检查是否超过30秒如果超过则跳出循环
if ((DateTime.Now - startTime).TotalSeconds >= 20)
{
isFlag = false; // 设置标志结束循环
}
} while (isFlag);
}
else
{
logHelper.Info($"PLC信息为空通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息");
}
}
catch (Exception ex)
{
logHelper.Error("读取内胆出库完成异常", ex);
}
}
}
#endregion
#region 出库完成
/// <summary>
/// 实时读取箱壳出库完成
/// </summary>
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);
};
});
}
/// <summary>
/// 实时读取内胆出库完成
/// </summary>
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);
};
});
}
/// <summary>
/// 实时绑定箱壳内胆
/// Delete By wenjy 2024-03-16 11:40:00 更改壳胆绑定逻辑,添加扫码器进行绑定
/// </summary>
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 私有方法
/// <summary>
/// 根据任务状态获取执行中的任务
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskStatus"></param>s
private List<RealTaskInfo> GetTaskInfoByTaskStatus(string storeCode, int taskStatus = 2)
{
List<RealTaskInfo> result = null;
try
{
result = _taskInfoService.GetTaskInfosByTaskStatus(new string[] { storeCode }, appConfig.outstoreTaskType, taskStatus);
}
catch (Exception ex)
{
logHelper.Error("根据任务状态获取执行中的任务异常", ex);
}
return result;
}
/// <summary>
/// 通过PLC获取货道信息
/// </summary>
/// <param name="spaceInfo"></param>
/// <returns></returns>
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
}
}