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/InStoreTaskHandle.cs

731 lines
28 KiB
C#

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 InStoreTaskHandle
{
#region 单例实现
private static readonly Lazy<InStoreTaskHandle> lazy = new Lazy<InStoreTaskHandle>(() => 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;
/// <summary>
/// 货道信息
/// </summary>
private IBaseSpaceInfoService _spaceInfoService;
#endregion
#region 私有变量
private Dictionary<string, IPlc> _plcDictionary = new Dictionary<string, IPlc>();
private Dictionary<string, int> shellKeyValuePairs = new Dictionary<string, int>();
private Dictionary<string, int> linerKeyValuePairs = new Dictionary<string, int>();
/// <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 InStoreFinsih(string storeCode, string taskCode);
public event InStoreFinsih InStoreFinsihEvent;
/// <summary>
/// 入库应答PLC收到下发的入库任务后进行应答
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
public delegate void InStoreAnswer(string storeCode, string taskCode);
public event InStoreAnswer InStoreAnswerEvent;
#endregion
/// <summary>
/// 实时任务
/// </summary>
private IRealTaskInfoService _taskInfoService;
private RegisterServices registerServices = RegisterServices.Instance;
private InStoreTaskHandle()
{
_taskInfoService = registerServices.GetService<IRealTaskInfoService>();
_spaceInfoService = registerServices.GetService<IBaseSpaceInfoService>();
_plcDictionary = _pool.GetAll();
// RealReadFinish();
RealUpdateSpaceInfoByPlc();
}
/// <summary>
/// 实时读取plc更新数据库货道数量及在途
/// </summary>
private void RealUpdateSpaceInfoByPlc()
{
Task.Run(() =>
{
List<BaseSpaceInfo> spaceList = _spaceInfoService.GetSpaceInfosByStoreCode(appConfig.shellStoreCode, appConfig.linerStoreCode);
// List<SpaceAddress> spaceAddressList = spaceConfig.GetAllSpaceAddress(spaceList);
if (spaceList!=null && spaceList.Count>0)
{
Thread.Sleep(2000);
while (true)
{
foreach(BaseSpaceInfo spaceInfo in spaceList)
{
BaseSpaceInfo tempSpace = new BaseSpaceInfo();
tempSpace.storeCode = spaceInfo.storeCode;
tempSpace.spaceCode = spaceInfo.spaceCode;
ReadSpaceInfoByPlc(tempSpace);
// 更新库存
if(tempSpace.spaceStock!=spaceInfo.spaceStock || tempSpace.onRouteAmount != spaceInfo.onRouteAmount)
{
spaceInfo.spaceStock = tempSpace.spaceStock;
spaceInfo.onRouteAmount = tempSpace.onRouteAmount;
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
}
}
Thread.Sleep(3000);
}
}
});
}
#region 20240221取消入库完成信号 判断箱壳,内胆入库是否完成
/// <summary>
/// 实时读取箱壳,内胆入库完成信号
/// </summary>
private void RealReadFinish()
{
// 箱壳线程
Task.Run(() =>
{
try
{
while (true)
{
if (_plcDictionary.Count > 0)
{
IPlc _plc = _plcDictionary[appConfig.shellStoreCode];
if (_plc != null)
{
List<RealTaskInfo> taskList = _taskInfoService.GetTaskInfosForInstore(appConfig.shellStoreCode, appConfig.instoreTaskType, 2);
if (taskList != null && taskList.Count > 0)
{
foreach (RealTaskInfo taskInfo in taskList)
{
SpaceAddress spaceAddress = spaceConfig.GetSpaceAddress(appConfig.shellStoreCode, taskInfo.spaceCode);
JudgeIsFinish(taskInfo, _plc, spaceAddress, appConfig.shellStoreCode);
}
}
}
else
{
logHelper.Info($"PLC信息为空或连接失败通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息");
}
}
Thread.Sleep(1000);
};
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
}
});
//内胆线程
Task.Run(() =>
{
try
{
while (true)
{
if (_plcDictionary.Count > 0)
{
IPlc _plc = _plcDictionary[appConfig.linerStoreCode];
if (_plc != null)
{
// 修改这个方法
List<RealTaskInfo> taskList = _taskInfoService.GetTaskInfosForInstore(appConfig.linerStoreCode, appConfig.instoreTaskType, 2);
if (taskList != null && taskList.Count > 0)
{
foreach (RealTaskInfo taskInfo in taskList)
{
SpaceAddress spaceAddress = spaceConfig.GetSpaceAddress(appConfig.linerStoreCode, taskInfo.spaceCode);
JudgeIsFinish(taskInfo, _plc, spaceAddress, appConfig.linerStoreCode);
}
}
}
else
{
logHelper.Info($"PLC信息为空或连接失败通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息");
}
}
Thread.Sleep(1000);
};
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
}
});
}
/// <summary>
/// 判断该任务对应的货道是否有完成信号
/// </summary>
/// <param name="taskInfo"></param>
/// <returns></returns>
public void JudgeIsFinish(RealTaskInfo taskInfo, IPlc _plc, SpaceAddress spaceAddress,string storeCode)
{
//读取入库完成反馈信号
if (_plc.readInt32ByAddress(spaceAddress.inStoreFinish) == 1)
{
_plc.writeInt32ByAddress(spaceAddress.inStoreFinish, 0);
InStoreFinsihEvent?.Invoke(storeCode, taskInfo.taskCode);
}
}
#endregion
#region 箱壳入库任务下发处理
public int SendShellTask_InStore(RealTaskInfo taskInfo)
{
int result = 0;
try
{
IPlc _plc = _plcDictionary[taskInfo.storeCode];
if (_plc != null)
{
if (_plc.readInt32ByAddress(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)));
//写入完成后读取应答字进行复位
ReadShellAnswer_InStore(taskInfo);
//写入应答字
// _plc.writeInt32ByAddress(plcConfig.in_shell_answer, 1);
//写入任务号
// _plc.writeStringByAddress(plcConfig.in_shell_task, taskInfo.taskCode);
result = 1;
}
else
{
result = 2;
logHelper.PlcLog("应答字为2下发新任务plc未就绪");
}
}
else
{
logHelper.Info($"PLC信息为空通过{taskInfo.storeCode}未获取到该仓库对应的PLC信息");
}
}
catch (Exception ex)
{
logHelper.Error("箱壳入库任务下发异常", ex);
}
return result;
}
/// <summary>
/// 读取箱壳入库应答
/// </summary>
private void ReadShellAnswer_InStore(RealTaskInfo taskInfo)
{
lock (string.Empty)
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.shellStoreCode];
try
{
Task.Run(() =>
{
if (_plc != null)
{
do
{
//读取PLC应答字为2时上位机清空写入的入库内容
if (_plc.readInt32ByAddress(plcConfig.in_shell_answer) == 2)
{
logHelper.PlcLog("箱壳入库应答字为2货道号:" + plcConfig.in_shell_spaceCode + ";复位写0");
//写入货道号
_plc.writeInt32ByAddress(plcConfig.in_shell_spaceCode, 0);
//写入应答字
// _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 0);
isFlag = false;
InStoreAnswerEvent?.Invoke(appConfig.shellStoreCode, taskInfo.taskCode);
// shellTaskInfos.Add(taskInfo);
}
Thread.Sleep(500);
} 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_InStore(RealTaskInfo taskInfo)
{
int result = 0;
try
{
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;
}
/// <summary>
/// 读取内胆入库应答
/// </summary>
private void ReadLinerAnswer_InStore(RealTaskInfo taskInfo)
{
lock (string.Empty)
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.linerStoreCode];
try
{
Task.Run(() =>
{
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);
isFlag = false;
InStoreAnswerEvent?.Invoke(appConfig.linerStoreCode, taskInfo.taskCode);
//ReadLinerFinish_InStore(taskCode);
9 months ago
// WritePlc(taskInfo.storeCode, taskInfo.spaceCode, false);
InStoreAnswerEvent?.Invoke(appConfig.linerStoreCode, taskInfo.taskCode);
// linerTaskInfos.Add(taskInfo);
}
Thread.Sleep(1000);
} while (isFlag);
}
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经讨论入库完成改为监测在途数量变化
/// <summary>
/// 读取箱壳入库完成
/// </summary>
/*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)
{
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($"PLC信息为空通过{appConfig.shellStoreCode}未获取到该仓库对应的PLC信息");
}
});
}
catch (Exception ex)
{
logHelper.Error("读取箱壳入库完成异常", ex);
}
}
}*/
/// <summary>
/// 读取内胆入库完成
/// </summary>
/*private void ReadLinerFinish_InStore(string taskCode)
{
lock (string.Empty)
{
try
{
Task.Run(() =>
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.linerStoreCode];
if (_plc != null)
{
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($"PLC信息为空通过{appConfig.linerStoreCode}未获取到该仓库对应的PLC信息");
}
});
}
catch (Exception ex)
{
logHelper.Error("读取内胆入库完成异常", ex);
}
}
}*/
#endregion
#region 监测PLC在途数量变化完成入库任务 delete by liuwf 2024-01-06,入库完成改成根据每个货道完成信号完成任务
//private void RealReadPlcSpace()
//{
// Thread.Sleep(1000);
// Task.Run(() =>
// {
// while (true)
// {
// RealReadShellPlcSpace();
// Thread.Sleep(500);
// }
// });
// Task.Run(() =>
// {
// while (true)
// {
// RealReadLinerPlcSpace();
// Thread.Sleep(500);
// }
// });
//}
///// <summary>
///// 读取箱壳已下发任务的货道信息读取后将货道编号及在途数量写入Dictionary进行比较在途数减少则入库完成
///// </summary>
//private void RealReadShellPlcSpace()
//{
// if (shellTaskInfos != null)
// {
// List<string> 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);
// }
// }
// }
//}
///// <summary>
///// 读取内胆已下发任务的货道信息读取后将货道编号及在途数量写入Dictionary进行比较在途数减少则入库完成
///// </summary>
//private void RealReadLinerPlcSpace()
//{
// if (linerTaskInfos != null)
// {
// List<string> 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
/// <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;
}
/// <summary>
/// 测试方法,联调时不用
/// </summary>
/// <param name="storeCode"></param>
/// <param name="spaceCode"></param>
/// <param name="flag"></param>
public void WritePlc(string storeCode, string spaceCode, bool flag)
{
var spaceAddress = spaceConfig.GetSpaceAddress(storeCode, spaceCode);
IPlc _plc = _plcDictionary[storeCode];
if (_plc != null)
{
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);
}
}
}
}
}