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

563 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.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
{
/// <summary>
/// 入库任务处理
/// </summary>
public 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;
private RegisterServices registerServices = RegisterServices.Instance;
private JsonChange json = JsonChange.Instance;
/// <summary>
/// 货道信息
/// </summary>
private IBaseSpaceInfoService _spaceInfoService;
/// <summary>
/// 已下传的任务信息
/// </summary>
private List<RealTaskInfo> foamRearTaskInfos;
/// <summary>
/// 实时任务
/// </summary>
private IRealTaskInfoService _taskInfoService;
#endregion
#region 私有变量
private static Dictionary<string, IPlc> _plcDictionary = new Dictionary<string, IPlc>();
private Dictionary<string, int> foamRearKeyValuePairs = new Dictionary<string, int>();
/// <summary>
/// 泡后任务编号,PLC反馈后进行赋值
/// </summary>
private string foamTaskCode = string.Empty;
#endregion
#region 委托事件
/// <summary>
/// 实时库存刷新
/// </summary>
/// <param name="message"></param>
public delegate void RefreshFoamStock();
public event RefreshFoamStock RefreshFoamStockEvent;
/// <summary>
/// 入库应答PLC收到下发的入库任务后进行应答
/// </summary>
/// <param name="storeCode"></param>
/// <param name="taskCode"></param>
public delegate void InStoreAnswer(string storeCode, string taskCode);
public event InStoreAnswer InStoreAnswerEvent;
/// <summary>
/// 入库完成
/// </summary>
/// <param name="taskCode"></param>
public delegate void InStoreFinsih(string taskCode);
public event InStoreFinsih InStoreFinsihEvent;
/// <summary>
/// 在途清0完成货道任务
/// </summary>
/// <param name="taskCode"></param>
public delegate void InStoreFinsihBySpaceCode(string spaceCode);
public event InStoreFinsihBySpaceCode InStoreFinsihBySpaceCodeEvent;
#endregion
private InStoreTaskHandle()
{
_taskInfoService = registerServices.GetService<IRealTaskInfoService>();
_spaceInfoService = registerServices.GetService<IBaseSpaceInfoService>();
_plcDictionary = _pool.GetAll();
// 程序启动查询数据库
foamRearTaskInfos = _taskInfoService.GetTaskInfosForInstore(appConfig.foamStoreCode, appConfig.instoreTaskType, 2);
foamRearTaskInfos = new List<RealTaskInfo>();
RealReadPlcSpace();
SendHeart();
RealUpdateSpaceInfoByPlc();
// RealReadFinish(); change-入库完成信号改回监测在途数
// test();
}
/// <summary>
/// 实时读取plc更新数据库货道数量及在途
/// </summary>
private void RealUpdateSpaceInfoByPlc()
{
Task.Run(() =>
{
Thread.Sleep(2000);
while (true)
{
List<BaseSpaceInfo> spaceList = _spaceInfoService.GetSpaceInfosByStoreCode(appConfig.foamStoreCode);
if (spaceList != null && spaceList.Count > 0)
{
foreach (BaseSpaceInfo spaceInfo in spaceList)
{
int Stock = spaceInfo.spaceStock;
int OnAmount = spaceInfo.onRouteAmount;
ReadSpaceInfoByPlc(spaceInfo);
if (spaceInfo.onRouteAmount == 0)
{
//自动完成该货道的所有入库任务
InStoreFinsihBySpaceCodeEvent?.Invoke(spaceInfo.spaceCode);
//该货道没有入库任务了,重置货道出库标识,可以再次出库
spaceInfo.outStoreFlag = 1;
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
RefreshFoamStockEvent?.Invoke();
// 删除多余入库任务
}
if (spaceInfo.spaceStock == 0 && spaceInfo.onRouteAmount == 0)
{
// 清空型号供新型号使用
spaceInfo.materialType = null;
spaceInfo.typeNameA = null;
//重置货道,可以再次入库
spaceInfo.inStoreFlag = 1;
spaceInfo.outStoreFlag = 1;
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
RefreshFoamStockEvent?.Invoke();
}
// 更新库存
if (Stock != spaceInfo.spaceStock || OnAmount != spaceInfo.onRouteAmount)
{
_spaceInfoService.UpdateSpaceInfo(spaceInfo);
RefreshFoamStockEvent?.Invoke();
}
}
}
Thread.Sleep(3000);
}
});
}
/// <summary>
/// 心跳
/// </summary>
private void SendHeart()
{
Task.Run(() =>
{
try
{
Thread.Sleep(3000);
while (true)
{
Console.Write(_plcDictionary.Count);
_plcDictionary = _pool.GetAll();
if (_plcDictionary.Count == 0)
{
Thread.Sleep(5000);
continue;
}
IPlc _plc = _plcDictionary[appConfig.foamStoreCode];
if (_plc != null)
{
_plc.writeInt32ByAddress("D7020", 1);
Thread.Sleep(1000);
_plc.writeInt32ByAddress("D7020", 0);
Thread.Sleep(1000);
}
}
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
}
});
}
#region 判断入库是否完成 delete20240224-入库完成信号改回监测在途数
/// <summary>
/// 实时读取入库完成信号
/// </summary>
private void RealReadFinish()
{
Task.Run(() =>
{
Thread.Sleep(2000);
while (true)
{
if (_plcDictionary.Count > 0)
{
IPlc _plc = _plcDictionary[appConfig.foamStoreCode];
if (_plc != null)
{
List<RealTaskInfo> taskList = _taskInfoService.GetTaskInfosForInstore(appConfig.foamStoreCode, appConfig.instoreTaskType, 2);
if (taskList != null && taskList.Count > 0)
{
foreach (RealTaskInfo taskInfo in taskList)
{
SpaceAddress spaceAddress = spaceConfig.GetSpaceAddress(appConfig.foamStoreCode, taskInfo.spaceCode);
JudgeIsFinish(taskInfo, _plc, spaceAddress);
}
}
}
else
{
logHelper.Info($"PLC信息为空或连接失败通过{appConfig.foamStoreCode}未获取到该仓库对应的PLC信息");
}
}
Thread.Sleep(1000);
};
});
}
/// <summary>
/// 判断该任务对应的货道是否有完成信号
/// </summary>
/// <param name="taskInfo"></param>
/// <returns></returns>
public void JudgeIsFinish(RealTaskInfo taskInfo, IPlc _plc, SpaceAddress spaceAddress)
{
// 测试方法模拟plc正式启用删除
// _plc.writeInt32ByAddress(spaceAddress.inStoreFinish, 1);
//读取入库完成反馈信号
if (_plc.readInt32ByAddress(spaceAddress.inStoreFinish) == 1)
{
_plc.writeInt32ByAddress(spaceAddress.inStoreFinish, 0);
InStoreFinsihEvent(taskInfo.taskCode);
}
}
#endregion
#region 监测PLC在途数量变化完成入库任务
private void RealReadPlcSpace()
{
Thread.Sleep(5000);
Task.Run(() =>
{
while (true)
{
RealReadShellPlcSpace();
Thread.Sleep(500);
}
});
}
/// <summary>
/// 读取箱壳已下发任务的货道信息读取后将货道编号及在途数量写入Dictionary进行比较在途数减少则入库完成
/// </summary>
private void RealReadShellPlcSpace()
{
if (foamRearTaskInfos != null && foamRearTaskInfos.Count > 0)
{
List<string> spaceCodes = foamRearTaskInfos.Select(x => x.spaceCode).Distinct().ToList();
for (int i = 0; i < spaceCodes.Count; i++)
{
string spaceCode = spaceCodes[i];
BaseSpaceInfo spaceInfo = new BaseSpaceInfo() { storeCode = appConfig.foamStoreCode, spaceCode = spaceCode };
spaceInfo = ReadSpaceInfoByPlc(spaceInfo);
if (foamRearKeyValuePairs.ContainsKey(spaceInfo.spaceCode))
{
foamRearKeyValuePairs.TryGetValue(spaceInfo.spaceCode, out int value);
//判断前次读取的数据和当前数据,如果前次数据大于当前数据则代表入库完成,然后筛选任务中对应货道的首个任务进行完成
//如果前次数据不大于当前数据则更新字典中存放的数据
if (value > spaceInfo.onRouteAmount)
{
//筛选任务
var list = foamRearTaskInfos.Where(x => x.spaceCode == spaceInfo.spaceCode).ToList();
if (list.Count > 0)
{
RealTaskInfo taskInfo = list.OrderBy(x => x.createTime).First();
InStoreFinsihEvent?.Invoke(taskInfo.taskCode);
foamRearTaskInfos.Remove(taskInfo);
}
foamRearKeyValuePairs.Remove(spaceInfo.spaceCode);
}
else
{
foamRearKeyValuePairs[spaceInfo.spaceCode] = spaceInfo.onRouteAmount;
}
}
else
{
foamRearKeyValuePairs.Add(spaceInfo.spaceCode, spaceInfo.onRouteAmount);
}
}
}
}
#endregion
#region 泡后入库任务下发处理
public int SendFoamTask_InStore(RealTaskInfo taskInfo)
{
int result = 0;
try
{
IPlc _plc = _plcDictionary[taskInfo.storeCode];
if (_plc != null)
{
if (_plc.readInt32ByAddress(plcConfig.in_foam_answer) == 1)
{
logHelper.Info("泡后入库应答字为1货道号:" + plcConfig.in_foam_spaceCode + ";写" + short.Parse(taskInfo.spaceCode.Substring(5, 1)));
//写入货道号
_plc.writeInt32ByAddress(plcConfig.in_foam_spaceCode, short.Parse(taskInfo.spaceCode.Substring(5, 1)));
//写入应答字
// _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 1);
//写入任务号
// _plc.writeStringByAddress(plcConfig.in_foam_task, taskInfo.taskCode);
//写入完成后读取应答字进行复位
ReadAnswer_InStore(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 ReadAnswer_InStore(RealTaskInfo taskInfo)
{
lock (string.Empty)
{
bool isFlag = true;
IPlc _plc = _plcDictionary[appConfig.foamStoreCode];
try
{
Task.Run(() =>
{
if (_plc != null)
{
do
{
// 测试方法模拟plc正式启用删除
// _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 2);
//读取PLC应答字为2时上位机清空写入的入库内容
if (_plc.readInt32ByAddress(plcConfig.in_foam_answer) == 2)
{
logHelper.PlcLog("入库应答字为2货道号:" + plcConfig.in_foam_spaceCode + ";复位写0");
//写入货道号
_plc.writeInt32ByAddress(plcConfig.in_foam_spaceCode, 0);
//写入应答字
// _plc.writeInt32ByAddress(plcConfig.in_foam_answer, 0);
isFlag = false;
foamRearTaskInfos.Add(taskInfo);
InStoreAnswerEvent?.Invoke(appConfig.foamStoreCode, taskInfo.taskCode);
}
Thread.Sleep(500);
} while (isFlag);
}
else
{
logHelper.Info($"PLC信息为空通过{appConfig.foamStoreCode}未获取到该仓库对应的PLC信息");
}
});
}
catch (Exception ex)
{
logHelper.Error("读取泡后入库应答字异常", ex);
}
}
}
#endregion
/// <summary>
/// 0正常清除plc报警信息1-扫码失败2-库满,未匹配到可用货道
/// </summary>
/// <param name="flag"></param>
#region 泡后库plc报警信息
public void SendPlcWarnInfo(short flag)
{
try
{
IPlc _plc = _plcDictionary[appConfig.foamStoreCode];
if (_plc != null)
{
_plc.writeInt32ByAddress("D7018", flag);
}
}
catch (Exception ex)
{
logHelper.Error(ex.Message.ToString());
}
}
#endregion
/// <summary>
/// 通过PLC获取货道信息
/// </summary>
/// <param name="spaceInfo"></param>
/// <returns></returns>
public BaseSpaceInfo ReadSpaceInfoByPlc(BaseSpaceInfo spaceInfo)
{
var spaceAddress = spaceConfig.GetSpaceAddress(spaceInfo.storeCode, spaceInfo.spaceCode);
_plcDictionary = _pool.GetAll();
if (_plcDictionary.Count > 0)
{
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;
}
#region 2023-01-04delete 入库逻辑修改,删除引用方法
/// <summary>
/// 读取泡后入库完成
/// </summary>
//private void ReadShellFinish_InStore(string taskCode)
//{
// lock (string.Empty)
// {
// bool isFlag = true;
// IPlc _plc = _plcDictionary[appConfig.foamStoreCode];
// foamTaskCode = taskCode;
// try
// {
// Task.Run(() =>
// {
// if (_plc != null)
// {
//
// do
// {
// //读取PLC入库任务完成
// if (_plc.readInt32ByAddress(plcConfig.in_foam_finish) == 1)
// {
// _plc.writeInt32ByAddress(plcConfig.in_foam_finish, 0);
// //string taskCode = _plc.readStringByAddress(plcConfig.out_foam_task, 10);
// InStoreFinsihEvent?.Invoke(taskCode);
// isFlag = false;
// }
// Thread.Sleep(1000);
// } while (isFlag);
//
// }
// else
// {
// logHelper.Info($"PLC信息为空通过{appConfig.foamStoreCode}未获取到该仓库对应的PLC信息");
// }
// });
// }
// catch (Exception ex)
// {
// logHelper.Error("读取泡后入库完成异常", ex);
// }
// }
//}
#endregion
}
}