首次提交:添加src文件夹代码
This commit is contained in:
190
Cowain.Bake.Main/Station/AlarmStation.cs
Normal file
190
Cowain.Bake.Main/Station/AlarmStation.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Opc.Ua;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity;
|
||||
using JSON = Newtonsoft.Json.JsonConvert;
|
||||
using static Cowain.Bake.Common.Models.MESModel;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class AlarmStation : IServerManager
|
||||
{
|
||||
readonly ConcurrentDictionary<string, bool[]> _alarmValues;
|
||||
public string Name { get; set; } = "";
|
||||
List<TAlarm> _allAlarms { get; set; } //ConcurrentBag //验证,如果还报线程问题,就用ConcurrentBag
|
||||
List<TAlarmContent> _allAlarmContent { get; set; }
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
List<AlertInfoModel> _arrayAlert = new List<AlertInfoModel>();
|
||||
private readonly Prism.Events.IEventAggregator _eventAggregator;
|
||||
readonly static object _objLock = new object();
|
||||
|
||||
public AlarmStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
_alarmValues = new ConcurrentDictionary<string, bool[]>();
|
||||
_eventAggregator = eventAggregator;
|
||||
Start();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_allAlarms = _unityContainer.Resolve<AlarmService>().GetAllInAlarms();
|
||||
_allAlarmContent = _unityContainer.Resolve<AlarmContentService>().GetAll();
|
||||
|
||||
foreach(var item in _allAlarms)
|
||||
{
|
||||
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(item);//2.界面刷新,发布事件(发送消息)
|
||||
}
|
||||
}
|
||||
|
||||
//报警可能是一个数组(TAlarmContent),也可能是一个点(TTagList)。
|
||||
public void AlarmInfo(DataValue data, Variable node)
|
||||
{
|
||||
if (1 == data.WrappedValue.TypeInfo.ValueRank) //数组
|
||||
{
|
||||
lock (_objLock)
|
||||
{
|
||||
AlarmArray(data, node); //会导致恢复后,一条报警信息会显示二次
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn("没有单个数据报警!");
|
||||
}
|
||||
}
|
||||
|
||||
public TAlarmContent GetAlarmContent(int nodeId, int offset)
|
||||
{
|
||||
return _allAlarmContent.Where(m => m.Offset == offset
|
||||
&& m.TagIds.Split(',').Any(x => x == nodeId.ToString())
|
||||
&& !string.IsNullOrEmpty(m.Desc)).FirstOrDefault();
|
||||
}
|
||||
|
||||
AlertInfoModel AssembleAlertModel(int code, string reset, string message)
|
||||
{
|
||||
return new AlertInfoModel()
|
||||
{
|
||||
AlertCode = code.ToString(),
|
||||
AlertReset = reset,
|
||||
AlertMessage = message,
|
||||
};
|
||||
}
|
||||
|
||||
//一个数组报警(订阅的是一个数组) --TAlarmContent
|
||||
private void AlarmArray(DataValue data, Variable node)
|
||||
{
|
||||
string key = "";
|
||||
_arrayAlert.Clear();
|
||||
bool[] value = data.WrappedValue.Value as bool[];
|
||||
if (data.WrappedValue.Value is bool[] v)
|
||||
{
|
||||
value = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn($"数组报警类型异常:{data.WrappedValue.Value.GetType().Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
//LogHelper.Instance.Warn($"数组报警:{JSON.SerializeObject(value)}");
|
||||
key = $"StationId:{node.StationId},Id:{node.Id}";
|
||||
|
||||
if (_alarmValues.TryGetValue(key, out bool[] oldValue)) //有
|
||||
{
|
||||
if (oldValue.Count() != value.Count())
|
||||
{
|
||||
LogHelper.Instance.Error($"报警老值与新值长度不匹配,key:{key},desc:{node.VarDesc}");
|
||||
return;
|
||||
}
|
||||
|
||||
var diffs = value.Zip(oldValue, (a, b) => a != b).Select((b, i) => new { Value = b, Index = i }).Where(x => x.Value);
|
||||
foreach (var item in diffs)
|
||||
{
|
||||
DealAlarmNode(node, item.Index, value[item.Index]);
|
||||
}
|
||||
}
|
||||
else //第一次进入
|
||||
{
|
||||
|
||||
for (int i = 0; i < value.Count(); ++i)
|
||||
{
|
||||
DealAlarmNode(node, i, value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_alarmValues[key] = value;
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
|
||||
{
|
||||
_unityContainer.Resolve<MESProcess>().MESEqptAlert(_arrayAlert);
|
||||
}
|
||||
}
|
||||
|
||||
void DealAlarmNode(Variable node, int offset, bool value)
|
||||
{
|
||||
TAlarmContent alarmContent = GetAlarmContent(node.Id, offset); //找到报警信息
|
||||
|
||||
if (alarmContent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//报警三种处理,1,入库,2.上传MOM,3.界面显示报警
|
||||
if (value)
|
||||
{
|
||||
AddAlarm(offset, node.StationId, alarmContent.Desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteAlarm(offset, node.StationId, alarmContent.Desc);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAlarm(int errCode, int stationId, string desc)
|
||||
{
|
||||
var alarm = _allAlarms.Find(x => x.StationId == stationId && x.Desc == desc);
|
||||
if (null == alarm)
|
||||
{
|
||||
TAlarm currentAlarm = new TAlarm()
|
||||
{
|
||||
StationId = stationId,
|
||||
Desc = desc,
|
||||
StartTime = DateTime.Now,
|
||||
Status = EAlarmStatus.Alert.GetDescription(),
|
||||
};
|
||||
|
||||
_allAlarms.Add(currentAlarm); //增加到内存
|
||||
_arrayAlert.Add(AssembleAlertModel(errCode, ((int)EAlarmStatus.Alert).ToString(), desc)); //上传到MES
|
||||
_unityContainer.Resolve<AlarmService>().Insert<TAlarm>(currentAlarm); //增加到DB
|
||||
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(currentAlarm);//.界面刷新,发布事件(发送消息)
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteAlarm(int errCode, int stationId, string desc)
|
||||
{
|
||||
TAlarm alarm = _allAlarms.Find(x => x.StationId == stationId
|
||||
&& x.Desc == desc);
|
||||
|
||||
if (null != alarm)
|
||||
{
|
||||
_allAlarms.Remove(alarm);
|
||||
_arrayAlert.Add(AssembleAlertModel(errCode, ((int)EAlarmStatus.Renew).ToString(), desc));
|
||||
_unityContainer.Resolve<AlarmService>().CancelAlarm(alarm);
|
||||
_eventAggregator.GetEvent<AlarmCancelEvent>().Publish(alarm);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
307
Cowain.Bake.Main/Station/BakingStation.cs
Normal file
307
Cowain.Bake.Main/Station/BakingStation.cs
Normal file
@@ -0,0 +1,307 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Main.Common;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Opc.Ua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Unity;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class BakingStation : IServerManager
|
||||
{
|
||||
public string Name { get; set; }
|
||||
readonly StoveProcessParam processParam = null;
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
readonly CmdFactories cmdFactories;
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
public BakingStation(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
processParam = _unityContainer.Resolve<StoveProcessParam>();
|
||||
cmdFactories = _unityContainer.Resolve<CmdFactories>();
|
||||
Start();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Global.AppExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(6 * 1000);
|
||||
|
||||
List<ExCavityInfoModel> details = _unityContainer.Resolve<CavityInfoService>().GetAllExInfo().Where(
|
||||
x => x.Type == (int)EStationType.Stove
|
||||
&& x.Enable == true
|
||||
&& x.CavityEnable == true).ToList();
|
||||
|
||||
//ProcessEndBaking(details);
|
||||
ProcessStartBaking(details);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.Error("BakingStation:Start:工艺参数,异常" + ex.ToString());
|
||||
_unityContainer.Resolve<LogService>().AddLog("BakingStation:Start:工艺参数,异常" + ex.Message, E_LogType.Debug.ToString());
|
||||
//throw;
|
||||
}
|
||||
|
||||
}
|
||||
}, cts.Token);
|
||||
}
|
||||
|
||||
void ProcessStartBaking(List<ExCavityInfoModel> stoveDetails)
|
||||
{
|
||||
List<bool> bakeFlag = new List<bool>();
|
||||
bool[] bakeEnable = new bool[Global.STOVE_MAX_LAYERS];
|
||||
List<ExCavityInfoModel> layers = null;
|
||||
var stoves = stoveDetails.GroupBy(p => new { p.StationId }).Select(s => s.FirstOrDefault()).ToList();
|
||||
|
||||
foreach (var stove in stoves) //烘烤以层为单位,所以以层为单位循环,这样简单
|
||||
{
|
||||
var conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stove.StationId);
|
||||
|
||||
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
|
||||
|
||||
if (null == plc || !plc.IsConnect)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//远程/本地模式 //0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
|
||||
if (!CommonFun.Instance.IsStoveQualified(plc, stove.StationId, 1, false))//工作当中就退出
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
layers = stoveDetails.Where(x => x.StationId == stove.StationId).OrderBy(x => x.Layer).ToList();//一炉子的夹具信息
|
||||
bakeFlag.Clear();
|
||||
//一层的夹具信息
|
||||
foreach (var detail in layers)
|
||||
{
|
||||
//bakeFlag = new bool[layers.Count]; //每一层有多少个可以烘烤的层
|
||||
if (0 == detail.PalletId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (0 != detail.PalletId && !detail.IsLoad) //有托盘,无信号
|
||||
{
|
||||
LogHelper.Instance.Error($"有夹具,却没有信号或者没有读到信号,machineId:{stove.StationId},layer:{stove.Layer}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (detail.PalletStatus != (int)EPalletStatus.Advisable
|
||||
&& detail.PalletStatus != (int)EPalletStatus.TestNG)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bakeEnable[detail.Layer] = true;
|
||||
//if (detail.LastFlag ?? false)
|
||||
//{
|
||||
// bakeFlag = Enumerable.Repeat(true, layers.Count).ToArray();
|
||||
// //break; //为了bakeEnable,所以不退出
|
||||
//}
|
||||
|
||||
bakeFlag.Add(true);
|
||||
//bakeFlag[detail.Layer - 1] = true;
|
||||
}
|
||||
|
||||
if (0 == bakeFlag.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//因为当每个夹具都放水的时候,可能存在一个要复烘,一个不需要,这个时候就有为false
|
||||
if (bakeFlag.Count != layers.Count // (bakeFlag.Contains(false))
|
||||
&& null == layers.Find(x => x.LastFlag == true)) //不是最后一盘
|
||||
{
|
||||
//复烘逻辑:1.有NG,2.没锁,3.无有其它盘
|
||||
var failPallet = layers.Where(x => x.PalletStatus == (int)EPalletStatus.TestNG).ToList();
|
||||
if (0 == failPallet.Count) //没有测试NG的
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (layers.Any(x => x.Lock)) //有锁,也就是还有回炉的夹具
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int countPallets = layers.Where(x => x.PalletId != 0 && x.IsLoad == true && x.PalletStatus != (int)EPalletStatus.BlankOver).Count();
|
||||
if (failPallet.Count != countPallets)//有其它状态盘,如烘烤完成,也不开始烘烤
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//复烘逻辑满足:1.有NG,2.没锁,3.无有其它状态盘
|
||||
}
|
||||
|
||||
//if (!IsCanBaking(plc, stove.StationId, stove.Layer))
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
|
||||
#region 下发工艺参数
|
||||
//清料时,可能为会空,
|
||||
ExCavityInfoModel palletProceParam = stoveDetails.Where(x => !string.IsNullOrEmpty(x.JobNum)
|
||||
&& x.PalletId != 0 && x.StationId == stove.StationId).FirstOrDefault();
|
||||
|
||||
if (!processParam.SendStoveProcessParam(plc, palletProceParam)) //成功了要改变夹具状态 EPalletStatus.
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//启动烤炉自动流程/下发工艺参数完成信号(开始烘烤)
|
||||
if (!cmdFactories.StartBaking(plc, stove.StationId, bakeEnable))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//去复位“烘烤完成”
|
||||
cmdFactories.ResetEndBaking(stove.StationId);
|
||||
|
||||
//托盘绑定烤箱位置
|
||||
List<int> ids = layers.Select(x => x.PalletId).ToList(); //修改夹具状态
|
||||
LogHelper.Instance.Info($"下发工艺参数成功!工站:{stove.Name},工单:{stove.JobNum},托盘号:{JsonSerializer.Serialize(ids)}");
|
||||
|
||||
int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateStartBakingInfo(
|
||||
layers.Where(x => x.PalletStatus == (int)EPalletStatus.Advisable
|
||||
|| x.PalletStatus == (int)EPalletStatus.TestNG).ToList()); //托盘绑定烤箱位置,状态,时间
|
||||
|
||||
if (updateResult <= 0)
|
||||
{
|
||||
LogHelper.Instance.Warn($"修改夹具{string.Join(",", ids)}状态失败!");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCanBaking(IPLCDevice plc, int mainCode, int layer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public void TrigEndBaking(DataValue data, Variable node)
|
||||
{
|
||||
if (!((bool)data.WrappedValue.Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<ExCavityInfoModel> stoveCavitys = _unityContainer.Resolve<CavityInfoService>().GetAllExInfo().Where(
|
||||
x => x.Type == (int)EStationType.Stove
|
||||
&& x.Enable == true
|
||||
&& x.CavityEnable == true
|
||||
&& x.StationId == node.StationId).ToList();
|
||||
|
||||
if (0 == stoveCavitys.Count)
|
||||
{
|
||||
LogHelper.Instance.Error($"{node.StationId}#炉没有可能的腔体,烘烤完成失效!");
|
||||
return;
|
||||
}
|
||||
|
||||
int[] ids = stoveCavitys.Where(x =>
|
||||
x.PalletStatus == (int)EPalletStatus.Bake
|
||||
&& x.PalletId != 0).Select(x => x.PalletId).ToArray(); //修改夹具状态,BlankOver清料时会有这状态
|
||||
|
||||
if (0 == ids.Count())
|
||||
{
|
||||
LogHelper.Instance.Error($"{node.StationId}#炉没有找到【烘烤中】的腔体,烘烤完成失效!");
|
||||
return;
|
||||
}
|
||||
|
||||
int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateBakingOverTime(ids);
|
||||
if (updateResult <= 0)
|
||||
{
|
||||
LogHelper.Instance.Warn($"修改夹具为烘烤完成,{string.Join(",", ids)}状态失败!");
|
||||
};
|
||||
}
|
||||
|
||||
//void ProcessEndBaking(List<ExCavityInfoModel> stoveDetails)
|
||||
//{
|
||||
// bool[] bakeFlag = new bool[Global.STOVE_LAYERS];
|
||||
// List<ExCavityInfoModel> layers = null;
|
||||
// var stoves = stoveDetails.GroupBy(p => new { p.StationId }).Select(s => s.FirstOrDefault()).ToList();
|
||||
|
||||
// foreach (var stove in stoves) //烘烤以炉子为单位,所以以炉子为单位循环,这样简单
|
||||
// {
|
||||
// Array.Clear(bakeFlag, 0, Global.STOVE_LAYERS);
|
||||
// var conf = _unityContainer.Resolve<DeviceConfigService>().GetConfig(stove.StationId);
|
||||
|
||||
// IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
|
||||
|
||||
// if (null == plc || !plc.IsConnect)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// //远程/本地模式 //0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
|
||||
// if (!CommonFun.Instance.IsStoveQualified(plc, stove.StationId, 1, false)) //工作当中就退出
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// //烘烤完成信号
|
||||
// var resultBool = plc.GetValue<bool>(EStoveSignal.BakingMark.ToString(), stove.StationId); //stove.Layer
|
||||
// if (!resultBool.IsSuccess || !resultBool.Content)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// layers = stoveDetails.Where(x => x.StationId == stove.StationId).OrderBy(x => x.Layer).ToList();//一个炉子的夹具信息
|
||||
// foreach (var detail in layers)
|
||||
// {
|
||||
// //只有在烘烤中的,才会有烘烤完成
|
||||
// if (detail.PalletStatus != (int)EPalletStatus.Bake //detail.PalletStatus != (int)EPalletStatus.Advisable
|
||||
// || 0 == detail.PalletId) //detail.PalletStatus != (int)EPalletStatus.Bake
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (detail.LastFlag ?? false)
|
||||
// {
|
||||
// bakeFlag = Enumerable.Repeat(true, Global.STOVE_LAYERS).ToArray();
|
||||
// break;
|
||||
// }
|
||||
|
||||
// bakeFlag[detail.Number - 1] = true;
|
||||
// }
|
||||
|
||||
// if (bakeFlag.Contains(true)) //有假表示有夹具。
|
||||
// {
|
||||
// int[] ids = layers.Where(x =>
|
||||
// x.PalletStatus == (int)EPalletStatus.Bake
|
||||
// && x.PalletId != 0).Select(x => x.PalletId).ToArray(); //修改夹具状态,BlankOver清料时会有这状态
|
||||
// int updateResult = _unityContainer.Resolve<PalletInfoService>().UpdateBakingOverTime(ids);
|
||||
// if (updateResult <= 0)
|
||||
// {
|
||||
// LogHelper.Instance.Warn($"修改夹具{string.Join(",", ids)}状态失败!");
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
// 在需要取消任务的时候,调用以下代码:
|
||||
cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
312
Cowain.Bake.Main/Station/DataCollectStation.cs
Normal file
312
Cowain.Bake.Main/Station/DataCollectStation.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Main.Common;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using HslCommunication;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Unity;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class DataCollectStation : IServerManager
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
readonly List<TDeviceConfig> stoveConfs = null;
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
readonly List<TStoveSctualPatrol> listStoveTemp = new List<TStoveSctualPatrol>();
|
||||
|
||||
private Dictionary<int, StoveDataModel> cacheStoveData { set; get; } = new Dictionary<int, StoveDataModel>();//如果只有一个保存炉子的真空值,数据容易不及时,且冲突
|
||||
//private Dictionary<int, int> cacheElectricEnergyData { set; get; } = new Dictionary<int, int>();
|
||||
private readonly Prism.Events.IEventAggregator _eventAggregator;
|
||||
public DataCollectStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
_eventAggregator = eventAggregator;
|
||||
stoveConfs = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EStationType.Stove.ToString());//
|
||||
Start();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
string tempCycle = _unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>()
|
||||
.GetValueByParaID(Cowain.Bake.Common.Enums.ESysSetup.DataCollectionCycle.ToString());
|
||||
int tempCycleValue = int.Parse(tempCycle);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(20 * 1000); //等待去读PLC的数据
|
||||
while (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(tempCycleValue * 1000);
|
||||
if (Global.AppExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CollectTemp();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CollectTemp()
|
||||
{
|
||||
bool isWork = false;
|
||||
float vacuum = 0;
|
||||
UInt16 workTime = 0;
|
||||
UInt16 totalWorkTime = 0;
|
||||
float[] temps = null;
|
||||
OperateResult<Int16[]> resultTemp;
|
||||
listStoveTemp.Clear();
|
||||
cacheStoveData.Clear();
|
||||
foreach (var conf in stoveConfs)
|
||||
{
|
||||
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>(conf.Name);
|
||||
|
||||
if (null == plc || !plc.IsConnect)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var stoves = (from v in plc.Storages
|
||||
group v by v.StationId
|
||||
into a
|
||||
orderby a.Key
|
||||
select a).ToList();
|
||||
|
||||
//每个炉子都循环
|
||||
foreach (var item in stoves) //一个PLC控制二台炉子(一台炉子)
|
||||
{
|
||||
//0 / 空闲 1 / 待机 2 / 停止 3 / 工作 4 / 保压
|
||||
var workStatus = plc.GetValue<Int16>(EStoveSignal.CavityStatus.ToString(), item.Key);
|
||||
if (!workStatus.IsSuccess || (int)EStoveWorkMode.Standby >= workStatus.Content) //系统状态寄存器
|
||||
{
|
||||
isWork = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isWork = true;
|
||||
}
|
||||
|
||||
if (item.Key == Global.DEW_STOVE_NUMBER) //IP:70
|
||||
{
|
||||
//露点温度
|
||||
var dewTemp = plc.GetValue<float>(EStoveSignal.DewTemperature.ToString(), item.Key);
|
||||
if (!dewTemp.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"读取露点温度失败!{dewTemp.Message}");
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetTempData("-0");
|
||||
}
|
||||
else
|
||||
{
|
||||
DealDewTemp(dewTemp.Content);
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetTempData(Math.Round(dewTemp.Content,2).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//真空值
|
||||
var result = plc.GetValue<int>(EStoveSignal.Vacuum.ToString(), item.Key);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"读取真空值失败!{result.Message}");
|
||||
continue;
|
||||
}
|
||||
vacuum = (float)(result.Content);
|
||||
|
||||
//工作时长
|
||||
var workTimeResult = plc.GetValue<UInt16>(EStoveSignal.WorkTime.ToString(), item.Key);
|
||||
var totalTimeResult = plc.GetValue<UInt16>(EStoveSignal.TotalWorkTime.ToString(), item.Key);
|
||||
if (!workTimeResult.IsSuccess
|
||||
|| !totalTimeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"读取工作时长失败!{workTimeResult.Message},{totalTimeResult.Message}");
|
||||
continue;
|
||||
}
|
||||
workTime = workTimeResult.Content;
|
||||
totalWorkTime = totalTimeResult.Content;
|
||||
|
||||
//获取一个炉子的温度节点
|
||||
var stoveTempNode = (from storage in plc.Storages
|
||||
from itemTemp in storage.VariableList
|
||||
where storage.StationId == item.Key
|
||||
&& itemTemp.TagType == (int)ETagType.Temperature //&& itemTemp.Number == layer
|
||||
select itemTemp).ToList();
|
||||
|
||||
foreach (var tempParam in stoveTempNode) //每一层的温度
|
||||
{
|
||||
int layer = tempParam.Number;
|
||||
int cavityId = _unityContainer.Resolve<CavityInfoService>().GetCavityId(item.Key, layer);
|
||||
TPalletInfo palletInfo = _unityContainer.Resolve<PalletInfoService>().GetPalletCode(cavityId);
|
||||
|
||||
if (null == palletInfo
|
||||
|| 0 == palletInfo.Id) //没有托盘
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (palletInfo.BakingBeginTime == null //没有烘烤开始时间的不用上传
|
||||
|| 0 == palletInfo.VirtualId) //没有绑定电芯
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//PID
|
||||
var resultPID = plc.GetValue<float[]>(EStoveSignal.PID.ToString() + layer, item.Key, layer);
|
||||
if (!resultPID.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("读取PID失败!");
|
||||
continue;
|
||||
}
|
||||
|
||||
//温度
|
||||
resultTemp = plc.GetValue<Int16[]>(tempParam.ParamName, item.Key, layer); //温度
|
||||
if (!resultTemp.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("读取温度失败!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resultTemp.Content.All(x => x == 0)
|
||||
|| resultPID.Content.All(x => x == 0))
|
||||
{
|
||||
//LogHelper.Instance.GetCurrentClassError("读取温度异常,全为0!");
|
||||
continue;
|
||||
}
|
||||
|
||||
temps = CommonFun.Instance.UShortToFloat(resultTemp.Content);
|
||||
|
||||
cacheStoveData[cavityId] = new StoveDataModel() //少了两个条件,1.VirtualId为0,2.工作状态
|
||||
{
|
||||
Temps = temps,
|
||||
Vacuum = vacuum,
|
||||
WorkTime = workTime,
|
||||
TotalWorkTime = totalWorkTime
|
||||
};
|
||||
|
||||
if (isWork) //add by lsm 20250926, 测试用
|
||||
{
|
||||
string tempData = MakeJsonTemperature(tempParam.VarDesc, temps);
|
||||
string pid = MakeJsonPid(EStoveSignal.PID.ToString(), resultPID.Content);
|
||||
listStoveTemp.Add(MakeTStoveSctualPatrol(palletInfo.VirtualId, cavityId, palletInfo.PalletCode, vacuum, tempData, pid));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//UploadProcessData(cacheStoveData); //1.上传Mom //太多,太卡,不上传
|
||||
_eventAggregator.GetEvent<StoveDataEvent>().Publish(cacheStoveData);//2.界面刷新,发布事件(发送消息)
|
||||
if (0 != listStoveTemp.Count)
|
||||
{
|
||||
_unityContainer.Resolve<StoveSctualPatrolService>().Insert(listStoveTemp);//批量插入数据
|
||||
}
|
||||
}
|
||||
|
||||
static bool? failDev;
|
||||
void DealDewTemp(float value)
|
||||
{
|
||||
float target = float.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DewTempAlarmTargetValue.ToString()));
|
||||
TAlarm alarm = new TAlarm()
|
||||
{
|
||||
StationId = (int)EAlarmStationId.DevTemp,
|
||||
Desc = "露点温度超标,请检查压缩空气!",
|
||||
StartTime = DateTime.Now,
|
||||
Status = EAlarmStatus.Alert.GetDescription(),
|
||||
};
|
||||
|
||||
if (value <= target) //正常
|
||||
{
|
||||
if (false != failDev)
|
||||
{
|
||||
failDev = false;
|
||||
_eventAggregator.GetEvent<AlarmCancelEvent>().Publish(alarm);
|
||||
}
|
||||
}
|
||||
else //异常
|
||||
{
|
||||
if (true != failDev)
|
||||
{
|
||||
failDev = true;
|
||||
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(alarm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//上转Mom
|
||||
public void UploadProcessData(Dictionary<int, StoveDataModel> datas)
|
||||
{
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
|
||||
{
|
||||
foreach (var item in datas)
|
||||
{
|
||||
string cavityName = _unityContainer.Resolve<MemoryDataProvider>().CavityInfo.Find(x => x.Id == item.Key).Name;
|
||||
_unityContainer.Resolve<MESProcess>().MESBakingParameter(item.Value.Vacuum, item.Value.Temps, cavityName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TStoveSctualPatrol MakeTStoveSctualPatrol(int palletVirtualId, int cavityId, string palletCode, float vacuum, string temperature,string pid)
|
||||
{
|
||||
return new TStoveSctualPatrol()
|
||||
{
|
||||
PalletVirtualId = palletVirtualId,
|
||||
CavityId = cavityId,
|
||||
PalletCode = palletCode,
|
||||
Vacuum = vacuum,
|
||||
Temperature = temperature,
|
||||
CreateTime = DateTime.Now,
|
||||
PID = pid
|
||||
};
|
||||
}
|
||||
|
||||
public string MakeJsonTemperature(string headName, float[] value)
|
||||
{
|
||||
headName = Regex.Replace(headName, @"\d", "");
|
||||
List<PallletTemp> listTemp = new List<PallletTemp>();
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
listTemp.Add(new PallletTemp()
|
||||
{
|
||||
HeadName = $"{headName}{i + 1}",
|
||||
Value = value[i]
|
||||
});
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(listTemp);
|
||||
}
|
||||
|
||||
public string MakeJsonPid(string headName, float[] value)
|
||||
{
|
||||
//headName = Regex.Replace(headName, @"\d", "");
|
||||
List<PallletTemp> listTemp = new List<PallletTemp>();
|
||||
for (int i = 1; i < value.Length; i++) //数组0不使用
|
||||
{
|
||||
listTemp.Add(new PallletTemp()
|
||||
{
|
||||
HeadName = $"{headName}{i}",
|
||||
Value = value[i]
|
||||
});
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(listTemp);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
// 在需要取消任务的时候,调用以下代码:
|
||||
cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
215
Cowain.Bake.Main/Station/LifeCycleStation.cs
Normal file
215
Cowain.Bake.Main/Station/LifeCycleStation.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using HslCommunication;
|
||||
using Newtonsoft.Json;
|
||||
using Opc.Ua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Unity;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class LifeCycleStation : IServerManager
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<TStation> _station = null;
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
public LifeCycleStation(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
_station = _unityContainer.Resolve<MemoryDataProvider>().AllStation;
|
||||
}
|
||||
|
||||
// 心跳
|
||||
public void LifeCycle(DataValue data, Variable node)
|
||||
{
|
||||
OperateResult writeResult = null;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
Int16 value = 0;
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
|
||||
{
|
||||
value = (System.Int16)data.WrappedValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn($"没有找到生命周期信号这个数据类型,节点名为{node.VarDesc}");
|
||||
}
|
||||
|
||||
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
|
||||
var plc = _unityContainer.Resolve<IPLCDevice>(config.Name);
|
||||
|
||||
writeResult = plc.Write<Int16>((string)d.WriteHeart, value); //回复为接收到的计数
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"LifeCycle-{node.StationId}-{value}-{(string)d.WriteHeart}:{writeResult.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
//向上位机请求任务,PLC请求命令:0=无意义;10=无托盘;20=有托盘
|
||||
public void ReqTask(DataValue data, Variable node)
|
||||
{
|
||||
//bool IsAccord = false; //是否符合取放盘
|
||||
try
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
Int16 value = 0;
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
|
||||
{
|
||||
value = (System.Int16)data.WrappedValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn($"没有找到请求任务信号这个数据类型,节点名为{node.VarDesc}");
|
||||
return;
|
||||
}
|
||||
|
||||
TStation station = _station.Where(p => p.Id == node.StationId).FirstOrDefault();
|
||||
LogHelper.Instance.Warn($"取放盘,值:{value},station:{node.StationId},层{node.Number}");
|
||||
|
||||
|
||||
//是否符合取放盘
|
||||
//if (_unityContainer.Resolve<CavityInfoService>().IsAccordReq(station, node.Number, (sbyte)value))
|
||||
{
|
||||
//IsAccord = true;
|
||||
//修改取放盘状态
|
||||
if (!_unityContainer.Resolve<CavityInfoService>().UpdateReqStatus(station, node.Number, (sbyte)value))
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError($"修改请求任务失败,StationId:{node.StationId},Number:{node.Number},value:{value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// LogHelper.Instance.GetCurrentClassError($"不符合取放盘,StationId:{node.StationId},Number:{node.Number},value:{value}");
|
||||
//}
|
||||
|
||||
//DealPalletRequest(value, node); //取消这个,不然上位机启动,会报异常
|
||||
|
||||
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
|
||||
var plc = _unityContainer.Resolve<IPLCDevice>(config.Name);
|
||||
var writeResult = plc.Write<int>((string)d.WriteRetCommand, value); //收到什么反馈什么。
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ReqTask-{(string)d.WriteRetCommand}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
value = (short)(value == 0 ? -1 : 1); //1=OK,2=重新上传,如果PLC请求命令是0,WCS返回-1
|
||||
writeResult = plc.Write<int>((string)d.WriteResult, value); //收到什么反馈什么。
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ReqTask-{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.Error($"请求解析出错:{node.Json},{node.TrigJson},{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void DealPalletRequest(int value, Variable node)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case (int)ECavityStatus.RequestPick:
|
||||
DealPick(node);
|
||||
break;
|
||||
case (int)ECavityStatus.RequestPlace:
|
||||
//DealPlace(station, json);
|
||||
break;
|
||||
case (int)ECavityStatus.None:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void DealPlace(TStation station, string json)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void DealPick(Variable node)
|
||||
{
|
||||
MethodInfo mi = null;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
|
||||
string service = d.ReflexService;
|
||||
string func = d.ReflexFunc;
|
||||
string param = d.Param; //方法的参数,如果是扫码,则是扫码的编号
|
||||
|
||||
if (string.IsNullOrEmpty(service))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LogHelper.Instance.Info($"请求取盘触发事件:{node.TrigJson}");
|
||||
var instnce = _unityContainer.Resolve<TrigStation>();
|
||||
Type type = Type.GetType(MyPath.SIGNAL_TRIGGER + service);
|
||||
mi = this.GetType().GetMethod(ReflexFun.TRIG_REPLY).MakeGenericMethod(new Type[] { type }); //回复信息;
|
||||
mi.Invoke(this, new object[]
|
||||
{
|
||||
func,
|
||||
1,
|
||||
param,
|
||||
node
|
||||
});
|
||||
}
|
||||
|
||||
public void TrigReply<T>(string func, int curValue, string param, Variable node)
|
||||
{
|
||||
//取得实例
|
||||
var instnce = _unityContainer.Resolve<T>(); //上下料实例
|
||||
Type t = instnce.GetType();
|
||||
|
||||
//取得方法
|
||||
MethodInfo mi = t.GetMethod(func);
|
||||
//调用方法
|
||||
mi.Invoke(instnce, new object[]
|
||||
{
|
||||
curValue,
|
||||
param,
|
||||
node
|
||||
});
|
||||
}
|
||||
|
||||
//心跳
|
||||
public void Alive(DataValue data, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
Int16 value = 0;
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
|
||||
{
|
||||
value = (System.Int16)data.WrappedValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn($"收到心跳解析出错,工站:{node.StationId},节点名为{node.VarDesc}");
|
||||
return;
|
||||
}
|
||||
|
||||
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
|
||||
var plc = _unityContainer.Resolve<IPLCDevice>(config.Name);
|
||||
var writeResult = plc.Write<int>(d.RetCommand, value); //收到什么反馈什么。
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"Alive-{d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
553
Cowain.Bake.Main/Station/LoadingStation.cs
Normal file
553
Cowain.Bake.Main/Station/LoadingStation.cs
Normal file
@@ -0,0 +1,553 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using Cowain.Bake.Main.Views;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Cowain.Bake.UI.CsvMap;
|
||||
using HslCommunication;
|
||||
using Newtonsoft.Json;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Unity;
|
||||
using static Cowain.Bake.Common.Models.MESModel;
|
||||
using JSON = Newtonsoft.Json.JsonConvert;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class LoadingStation : IServerManager
|
||||
{
|
||||
private int _batteryCodeLen = 0;
|
||||
public string Name { get; set; }
|
||||
IPLCDevice PLC { get; set; }
|
||||
readonly List<IScanCodeBase> _deviceScann = new List<IScanCodeBase>();
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
public LoadingStation(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
TDeviceConfig config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.Loading)[0];
|
||||
Name = config.Name;
|
||||
SetBatteryCodeLen();
|
||||
Start();
|
||||
}
|
||||
|
||||
public void SetBatteryCodeLen()
|
||||
{
|
||||
_batteryCodeLen = int.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.BatteryCodeLen.ToString()));
|
||||
}
|
||||
|
||||
bool IsConnectPLC()
|
||||
{
|
||||
if (null == PLC || !PLC.IsConnect)
|
||||
{
|
||||
LogHelper.Instance.Error($"PalletVirtualId:{PLC.Name},PLC为空!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var configScann = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.SCANNER).OrderBy(x => x.Id).Take((int)EScanCode.PalletScan2).ToList();
|
||||
foreach (var item in configScann)
|
||||
{
|
||||
IScanCodeBase device = _unityContainer.Resolve<IScanCodeBase>(item.Name);
|
||||
_deviceScann.Add(device);
|
||||
}
|
||||
|
||||
PLC = _unityContainer.Resolve<IPLCDevice>(Name); //上料PLC
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
}
|
||||
/*
|
||||
* 编译器自动在方法入口/出口加 lock(this),简单但锁粒度粗;
|
||||
* 高频调用或重入场景容易成瓶颈,只适合做原型或低并发工具类。
|
||||
*/
|
||||
//托盘满盘信号
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public void ExecuteFullPallet(int curValue, string param, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
LogHelper.Instance.Warn($"LoadingStation:ExecuteFullPallet:开始,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
|
||||
int result ;
|
||||
int batteryQty;
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("开始:" + node.VarDesc);
|
||||
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.Loading, int.Parse(param));
|
||||
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
|
||||
if (null == palletInfo) //如果当前夹具状态为"满夹具可取",就退出,上位机重启会重复触发!
|
||||
{
|
||||
LogHelper.Instance.Warn($"托盘满信号,上料平台无夹具,异常");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int)EPalletStatus.Advisable == palletInfo.PalletStatus) //如果当前夹具状态为"满夹具可取",就退出,上位机重启会重复触发!
|
||||
{
|
||||
//LogHelper.Instance.Warn($"托盘满信号,当前托盘为满夹具夹,异常");
|
||||
//return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0
|
||||
if (!IsConnectPLC()) return;
|
||||
|
||||
var resultBatterys = PLC.Read<int[]>((string)d.ReadVirtualIds); //可以改成直接读PLC
|
||||
var resultPalletVirtualId = PLC.Read<int>((string)d.ReadPalletVirtualId); //这是直接读PLC
|
||||
var lastFlag = PLC.Read<Int16>((string)d.ReadLastFlag).Content; //这是直接读PLC
|
||||
if (!resultBatterys.IsSuccess || !resultPalletVirtualId.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},没有读取电芯信息或托盘信息!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == resultPalletVirtualId.Content ||
|
||||
1 == resultPalletVirtualId.Content)
|
||||
{
|
||||
LogHelper.Instance.Error($"托盘满盘信号异常, 托盘虚拟码为【{resultPalletVirtualId.Content}】!", true);
|
||||
return;
|
||||
}
|
||||
|
||||
//批量更新电芯表
|
||||
batteryQty = _unityContainer.Resolve<BatteryInfoService>().InsertBatch(resultBatterys.Content, resultPalletVirtualId.Content); //add by lsm 20250219 要300耗秒以上
|
||||
|
||||
SavePalletInfo(resultPalletVirtualId.Content);
|
||||
|
||||
if (0 == batteryQty)
|
||||
{
|
||||
//HandyControl.Controls.MessageBox.Error("触发满盘时没有电芯数据!"); //启动上位机时,会触发这个东西。
|
||||
LogHelper.Instance.Error($"启动上位机时,上料:{resultPalletVirtualId.Content},电芯地址里没有电芯数据!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global.PALLET_TOTAL_BATTERYS != batteryQty)
|
||||
{
|
||||
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},{batteryQty},上料电芯是{Global.PALLET_TOTAL_BATTERYS}!", false);
|
||||
}
|
||||
|
||||
result = _unityContainer.Resolve<PalletInfoService>().LoadingUpdatePalletStatus(resultPalletVirtualId.Content, (int)EPalletStatus.Advisable, batteryQty, lastFlag == 1);
|
||||
if (0 == result)
|
||||
{
|
||||
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},修改托盘状态失败!");
|
||||
}
|
||||
|
||||
//writeResult = PLC.Write<bool>((string)d.WriteResult, true);//回复收到托盘1满盘信号
|
||||
//if (!writeResult.IsSuccess)
|
||||
//{
|
||||
// LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
|
||||
//}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($",{ex.Message}:{ex.StackTrace}");
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
//假电芯扫码 验证数据库OK
|
||||
public void ExecuteScanDummy(int curValue, string param, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
if (!IsConnectPLC()) return;
|
||||
int virtualId;
|
||||
OperateResult writeResult = null;
|
||||
EScanCode scanName = EScanCode.DummyScan; //(EScanCode)(int.Parse(param));
|
||||
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == scanName.ToString());
|
||||
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
|
||||
{
|
||||
IsSuccess = false,
|
||||
};
|
||||
|
||||
scanResult.IsSuccess = true;
|
||||
scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, 12);
|
||||
if (scanResult.IsSuccess)
|
||||
{
|
||||
virtualId = _unityContainer.Resolve<BatteryInfoService>().InsertBattery(scanResult.Content, (int)EBatteryStatus.ScanOver, (int)EDummyState.Have, "");
|
||||
writeResult = PLC.Write<int>((string)d.WriteVirtualId, virtualId); //假电芯虚拟码
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"写假电芯虚拟码失败,{(string)d.WriteVirtualId}:{writeResult.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16>((string)d.WriteResult, scanResult.IsSuccess ? (Int16)EResult.OK : (Int16)EResult.NG); //假电芯结果
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16>((string)d.WriteAsk, 1); //回复
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ExecuteScanDummy-{(string)d.WriteAsk}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
//托盘扫码
|
||||
public void ExecuteScanPallet(int curValue, string param, Variable node)
|
||||
{
|
||||
string msg = "";
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
_unityContainer.Resolve<LogService>().AddLog("LoadingStation:ExecuteScanPallet:托盘扫码开始", E_LogType.Info.ToString());
|
||||
string palletCode = "";
|
||||
int VID = 0;
|
||||
OperateResult writeResult = null;
|
||||
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
|
||||
{
|
||||
IsSuccess = false,
|
||||
};
|
||||
|
||||
|
||||
EScanCode scanName = (EScanCode)((int)EScanCode.PalletScan1 + int.Parse(param) - 1); //param这个就是扫码枪的编号
|
||||
|
||||
try
|
||||
{
|
||||
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == scanName.ToString());
|
||||
|
||||
while (!scanDevice.IsConnect)
|
||||
{
|
||||
msg = $"获取{scanName.GetDescription()}连接异常!";
|
||||
LogHelper.Instance.Error(msg);
|
||||
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
scanDevice.Connect();
|
||||
}
|
||||
|
||||
scanResult = scanDevice.ReadCode();
|
||||
////------------------------ //add by lsm
|
||||
//scanResult.IsSuccess = true;
|
||||
//scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, 6); // add by lsm测试用
|
||||
//------------------------
|
||||
palletCode = scanResult.Content;
|
||||
|
||||
//夹具扫码异常处理
|
||||
while (string.IsNullOrEmpty(palletCode))
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||
{
|
||||
PalletIdInputWindow f = new PalletIdInputWindow("托盘码输入框", "请输入托盘码", "确定输入托盘码?")
|
||||
{
|
||||
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen,
|
||||
};
|
||||
f.ShowDialog();
|
||||
palletCode = f.PalletId;
|
||||
}));
|
||||
}
|
||||
|
||||
//绑定托盘
|
||||
VID = _unityContainer.Resolve<PalletInfoService>().BindingPallet(palletCode, (int)EPalletStatus.Loading, (int)EStationType.Loading, int.Parse(param)); //防呆
|
||||
|
||||
if (0 == VID)
|
||||
{
|
||||
LogHelper.Instance.Debug($"===ProcBindPallet卡死,{palletCode},{int.Parse(param)},VID:{VID}");
|
||||
return; //此时会卡死上位机
|
||||
}
|
||||
|
||||
LogHelper.Instance.Debug($"===ProcBindPallet,{palletCode},{(int)EPalletStatus.Loading},{int.Parse(param)},VID:{VID}");
|
||||
|
||||
if (CurrentWeaterPallet())
|
||||
{
|
||||
Int16 DummyLocationX = Int16.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.DummyLocationX.ToString()));
|
||||
writeResult = PLC.Write<Int16>((string)d.WriteDummyX, DummyLocationX); //假电芯行号
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"假电芯行号:{(string)d.WriteDummyX}:{writeResult.Message},失败");
|
||||
}
|
||||
|
||||
Int16 DummyLocationY = Int16.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.DummyLocationY.ToString()));
|
||||
writeResult = PLC.Write<Int16>((string)d.WriteDummyY, DummyLocationY); //假电芯列号
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"假电芯列号:{(string)d.WriteDummyY}:{writeResult.Message},失败");
|
||||
}
|
||||
}
|
||||
writeResult = PLC.Write<int>((string)d.WritePattleVirtualId, VID); //托盘1托盘虚拟码
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WritePattleVirtualId}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16>((string)d.WriteResult, 1); //托盘1扫码结果
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16>((string)d.WriteAsk, 1); //回复
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ExecuteScanPallet-{(string)d.WriteAsk}:{writeResult.Message}");
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"ExecuteScanPallet:{ex},{scanResult.Content},{scanResult.Message}");
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据工单判断是否放水含量
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool CurrentWeaterPallet()
|
||||
{
|
||||
bool IsWaertPallet = false;
|
||||
var productionInformation = _unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo();
|
||||
|
||||
if (productionInformation.DummyRule == (int)DummyPlaceRule.DEFAULT_EVERY_STOVE_LAYER_PLACED_ONE)
|
||||
{
|
||||
if (SettingProvider.Instance.WaterPallet % 2 == 1)
|
||||
{
|
||||
IsWaertPallet = true;
|
||||
}
|
||||
SettingProvider.Instance.WaterPallet++;
|
||||
}
|
||||
else if (productionInformation.DummyRule == (int)DummyPlaceRule.EVERY_PALLET_PLACED_ONE)
|
||||
{
|
||||
IsWaertPallet = true;
|
||||
}
|
||||
|
||||
return IsWaertPallet;
|
||||
|
||||
}
|
||||
|
||||
//电芯扫码
|
||||
public async Task ExecutScanBattery(int curValue, string param, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
if (!IsConnectPLC()) return;
|
||||
|
||||
int scannIndex = 0;
|
||||
OperateResult writeResult = null;
|
||||
int mesIndex = 0;
|
||||
int index = 1; //1..4,第0个索引不用
|
||||
string[] codeBatterys = new string[Global.ONCE_SCAN_BATTERY + 1];
|
||||
Int16[] result = new Int16[Global.ONCE_SCAN_BATTERY + 1];
|
||||
Int16[] ask = new Int16[Global.ONCE_SCAN_BATTERY + 1];
|
||||
int[] batteryVirtualIds = new int[Global.ONCE_SCAN_BATTERY + 1];
|
||||
result = Enumerable.Repeat<Int16>(3, Global.ONCE_SCAN_BATTERY + 1).ToArray();
|
||||
Array.Clear(ask, 0, Global.ONCE_SCAN_BATTERY + 1); //3:无电芯
|
||||
Array.Clear(batteryVirtualIds, 0, Global.ONCE_SCAN_BATTERY + 1);
|
||||
List<OperateResult<string>> scannList = new List<OperateResult<string>>();
|
||||
List<MESReturnCmdModel> mesResultList = new List<MESReturnCmdModel>();
|
||||
List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
|
||||
List<Task<MESReturnCmdModel>> mesResultTasks = new List<Task<MESReturnCmdModel>>();
|
||||
int mesEnable = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString()));
|
||||
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式,1为正式模式
|
||||
|
||||
Array.Clear(codeBatterys, 0, Global.ONCE_SCAN_BATTERY + 1); //几个条码一起保存
|
||||
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
|
||||
{
|
||||
IsSuccess = false,
|
||||
};
|
||||
|
||||
if (mesEnable == (int)EMOMEnable.Enable
|
||||
&& (int)EProductionMode.Debug == debugMode)
|
||||
{
|
||||
LogHelper.Instance.Error($"MOM【在线模式】,设备模式却是【调试模式】,模式不匹配,请修改!", true);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
index = 1;
|
||||
for (EScanCode s = EScanCode.LoadingBatteryScan1; s <= EScanCode.LoadingBatteryScan8; s++, index++)
|
||||
{
|
||||
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ask[(int)s] = 1;
|
||||
|
||||
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
|
||||
|
||||
if (!scanDevice.IsConnect)
|
||||
{
|
||||
string msg = $"获取{s.GetDescription()}失败,请检测线路!";
|
||||
LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
|
||||
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
scanDevice.Connect();
|
||||
--s; //再次获取
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((int)EProductionMode.Debug == debugMode) //调试模式
|
||||
{
|
||||
scanResult.IsSuccess = true;
|
||||
scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, _batteryCodeLen);
|
||||
scannList.Add(scanResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
//scanResult = scanDevice.ReadCode();
|
||||
scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)EProductionMode.Normal == debugMode)
|
||||
{
|
||||
await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
|
||||
foreach (var task in scannTasks)
|
||||
{
|
||||
scannList.Add(task.Result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region 同时请求MOM
|
||||
if (mesEnable == (int)EMOMEnable.Enable)//生产模式,才会请求MES(不是离线就要请求)
|
||||
{
|
||||
foreach (var item in scannList) //四个电芯扫码结果
|
||||
{
|
||||
if (item.IsSuccess) //可能是三个扫码OK,一个扫码NG,所以只有三个电芯请求到MOM
|
||||
{
|
||||
mesResultTasks.Add(Task.Run(() => _unityContainer.Resolve<MESProcess>().GetBatteryStatus(item.Content))); //多线程入库,会有先后顺序的
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != mesResultTasks.Count)
|
||||
{
|
||||
MESReturnCmdModel[] tt = await Task.WhenAll(mesResultTasks); // //发送MES,等待所有的MES请求。
|
||||
foreach (var item in mesResultTasks) //发送MOM,不一定是四个
|
||||
{
|
||||
mesResultList.Add(item.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
index = 1; //1..4,第0个索引不用
|
||||
for (EScanCode s = EScanCode.LoadingBatteryScan1; s <= EScanCode.LoadingBatteryScan8; s++, index++)
|
||||
{
|
||||
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
scanResult = scannList[scannIndex++];
|
||||
|
||||
result[index] = scanResult.IsSuccess ? (Int16)EResult.OK : (Int16)EResult.NG;
|
||||
if (scanResult.IsSuccess) //扫码成功
|
||||
{
|
||||
//长度判断
|
||||
//if (_batteryCodeLen != scanResult.Content.Length)
|
||||
//{
|
||||
// result[index] = (Int32)EResult.NG; //长度不对,赋NG
|
||||
// _unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, $"要求电芯条码长度为{_batteryCodeLen},实际长度为:{scanResult.Content.Length}");
|
||||
// continue;
|
||||
//}
|
||||
|
||||
//0:正常扫码,1:复投扫码
|
||||
if ("0" == _unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(Cowain.Bake.Common.Enums.ESysSetup.ScanCodeMode.ToString()))
|
||||
{
|
||||
if (_unityContainer.Resolve<BatteryInfoService>().IsBatteryCodeRepeat(scanResult.Content))
|
||||
{
|
||||
result[index] = (Int32)EResult.NG; //有相同电芯,赋NG
|
||||
LogHelper.Instance.Warn($"{s.GetDescription()},电芯条码:[{scanResult.Content}]重复扫码,将会排出到NG位;"); //不要弹屏
|
||||
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, $"重复扫码,将会排出到NG位");
|
||||
}
|
||||
}
|
||||
|
||||
//MES结果判断
|
||||
if (mesEnable == (int)EMOMEnable.Enable) ////mes-mom 7.电芯状态获取 只有联机才调用MES接口,MES返回成功,失败
|
||||
{
|
||||
MESReturnCmdModel mesResult = mesResultList[mesIndex++];//_unityContainer.Resolve<MESProcess>().MESCellState(scanResult.Content);
|
||||
if (mesResult == null)
|
||||
{
|
||||
result[index] = (int)EResult.NG;
|
||||
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, "MOM返回信息为空,请判断MOM是否离线,未离线则是MOM回复异常");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesResult.Info.ResultFlag != EResultFlag.OK.ToString())
|
||||
{
|
||||
result[index] = (int)EResult.NG;
|
||||
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, JSON.SerializeObject(mesResult));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
codeBatterys[index] = scanResult.Content; //MES判断OK的电芯,才放到电芯表中。
|
||||
}
|
||||
}
|
||||
|
||||
batteryVirtualIds = _unityContainer.Resolve<BatteryInfoService>().InsertBattery(string.Join(",", codeBatterys)).ToArray(); //新加的,四个一起存,并返回虚拟码
|
||||
//InsertBattery//四个电芯一起存数据库
|
||||
LogHelper.Instance.Info($"电芯虚拟码写入到PLC:{string.Join(",", batteryVirtualIds)},codes={string.Join(",", codeBatterys)},扫码状态:{string.Join(",", result)}");
|
||||
writeResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualIds); //电芯1...4虚拟码
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"写虚拟地址-{(string)d.WriteVirtualIds}:{writeResult.Message}");
|
||||
}
|
||||
//g_U01_HMI.UpLoadFromWcs.iCell_ScanCodeResults
|
||||
writeResult = PLC.Write<Int16[]>((string)d.WriteResult, result); //电芯1...8扫码结果
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ExecutScanBattery-{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16[]>((string)d.WriteAsk, ask); //回复
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ExecutScanBattery-{(string)d.WriteAsk}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.Fatal($"ExecutScanBattery-出错-param:{param}:{ex.Message},{index}");
|
||||
}
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
//保存组盘信息
|
||||
private void SavePalletInfo(int palletVID)
|
||||
{
|
||||
string dateFile;
|
||||
string filePath;
|
||||
|
||||
try
|
||||
{
|
||||
List<TBatteryInfo> batterys = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(palletVID);
|
||||
|
||||
if (0 == batterys.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string path = _unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DataFilePath.ToString());
|
||||
path += "\\组盘";
|
||||
dateFile = DateTime.Now.ToString("yyyyMMdd");
|
||||
filePath = path + $"\\{dateFile}.csv";
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
CSVHelper.WriteMap<TBatteryInfo, BatteryInfoMap>(batterys, filePath);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.Error($"SavePalletInfo:{ex.Message},{ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Cowain.Bake.Main/Station/MesCollectStation.cs
Normal file
73
Cowain.Bake.Main/Station/MesCollectStation.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Opc.Ua;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Unity;
|
||||
using JSON = Newtonsoft.Json.JsonConvert;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class MesCollectStation
|
||||
{
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
readonly List<TDeviceConfig> stoveConfs = null;
|
||||
IUnityContainer _unityContainer { get; set; }
|
||||
public MesCollectStation(IUnityContainer unityContainer)
|
||||
{
|
||||
|
||||
_unityContainer = unityContainer;
|
||||
stoveConfs = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.StovePlc1);
|
||||
}
|
||||
/*
|
||||
1 运行状态
|
||||
2 待机状态
|
||||
3 报警状态
|
||||
4 停机状态
|
||||
*/
|
||||
//mes-mom 2.设备状态 只有联机才调用MES接口,MOM返回成功,失败
|
||||
public void EqptStatus(DataValue data, Variable node)
|
||||
{
|
||||
Int16 value = (Int16)data.WrappedValue.Value;
|
||||
List<TAlarm> models = null;
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
|
||||
{
|
||||
if ((int)EStatusCode.Warn == value)
|
||||
{
|
||||
var alarms = _unityContainer.Resolve<MainWindowViewModel>().Alarms.Where(x=>x.StationId == node.StationId).ToList();
|
||||
models = JSON.DeserializeObject<List<TAlarm>>(JSON.SerializeObject(alarms));
|
||||
}
|
||||
//_unityContainer.Resolve<MESProcess>().MESEqptStatus((UInt16)value, models); //经常超时 2026-2-9
|
||||
}
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().DeviceStatusName = ((EStatusCode)value).GetDescription();
|
||||
}
|
||||
|
||||
//public string MakeJsonTemperature(string headName, float[] value)
|
||||
//{
|
||||
// headName = Regex.Replace(headName, @"\d", "");
|
||||
// List<PallletTemp> listTemp = new List<PallletTemp>();
|
||||
// for (int i = 1; i <= value.Length; i++)
|
||||
// {
|
||||
// listTemp.Add(new PallletTemp()
|
||||
// {
|
||||
// HeadName = $"{headName}{i}",
|
||||
// Value = value[i - 1]
|
||||
// });
|
||||
// }
|
||||
|
||||
// return JsonConvert.SerializeObject(listTemp);
|
||||
//}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
// 在需要取消任务的时候,调用以下代码:
|
||||
cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
397
Cowain.Bake.Main/Station/StoveProcessParam.cs
Normal file
397
Cowain.Bake.Main/Station/StoveProcessParam.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Models;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using HslCommunication;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Unity;
|
||||
using JSON = System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class StoveProcessParam
|
||||
{
|
||||
const int PROCESS_PARAM_NUM = 21;
|
||||
//ProcessParamService procParamService;
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
public StoveProcessParam(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
//procParamService = _unityContainer.Resolve<ProcessParamService>();
|
||||
}
|
||||
|
||||
public bool SendStoveProcessParam(IPLCDevice plc, ExCavityInfoModel palletProceParam)
|
||||
{
|
||||
ProceParamList proceParam = null;
|
||||
TProcessParameter proceParamModel = null;
|
||||
//_unityContainer.Resolve<LogService>().AddLog("StoveProcessParam:SendStoveProcessParam:下发工艺参数开始"
|
||||
// , E_LogType.Info.ToString());
|
||||
OperateResult<AddrValue> operateResult = null;
|
||||
Model.Models.Variable node = null;
|
||||
List<AddrValue> makeAddrValues = new List<AddrValue>();
|
||||
List<ProceParamList> listParams = null;
|
||||
if (null == palletProceParam)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn("发送工艺参数时,没有获取到托盘信息!");
|
||||
return false;
|
||||
}
|
||||
|
||||
//判断是否是复烘
|
||||
if (palletProceParam.PalletStatus == (int)EPalletStatus.TestNG)
|
||||
{
|
||||
//使用复烘工艺
|
||||
proceParamModel = _unityContainer.Resolve<ProcessParamService>().GetReProcessParam(palletProceParam.JobNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
proceParamModel = _unityContainer.Resolve<ProcessParamService>().GetProcessParam(palletProceParam.JobNum);
|
||||
}
|
||||
|
||||
if (null == proceParamModel)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn("没有找到工艺参数列表!");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
listParams = JSON.Deserialize<List<ProceParamList>>(proceParamModel.Parameters);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassFatal(ex.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
//温度上限预警值
|
||||
node = plc.GetVariable(EStoveSignal.TemperatureUpperWarnValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.TemperatureUpperWarnValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//真空上限预警值
|
||||
node = plc.GetVariable(EStoveSignal.VacuumUpperWarnValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumUpperWarnValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
////参数_设定温度
|
||||
node = plc.GetVariable(EStoveSignal.SetTemp.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.SetTemp.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam, 100); //乘以100,设定10000,表示100度
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_温度公差
|
||||
node = plc.GetVariable(EStoveSignal.TemperatureTolerance.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.TemperatureTolerance.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam, 100); //乘以100,设定10000
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_温度上限
|
||||
node = plc.GetVariable(EStoveSignal.TemperatureLimit.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.TemperatureLimit.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam, 100); //乘以100,设定10000
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_真空到达值
|
||||
node = plc.GetVariable(EStoveSignal.VacuumArriveValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumArriveValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_真空上限
|
||||
node = plc.GetVariable(EStoveSignal.VacuumUpValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumUpValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_真空下限
|
||||
node = plc.GetVariable(EStoveSignal.VacuumDownValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.VacuumDownValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_氮气到达值
|
||||
node = plc.GetVariable(EStoveSignal.NitrogenArriveValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.NitrogenArriveValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_氮气上限
|
||||
node = plc.GetVariable(EStoveSignal.NitrogenUpValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.NitrogenUpValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_氮气下限
|
||||
node = plc.GetVariable(EStoveSignal.NitrogenDownValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.NitrogenDownValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_常压到达值
|
||||
node = plc.GetVariable(EStoveSignal.AtmosphericArriveValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.AtmosphericArriveValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_常压上限
|
||||
node = plc.GetVariable(EStoveSignal.AtmosphericUpValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.AtmosphericUpValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_常压下限
|
||||
node = plc.GetVariable(EStoveSignal.AtmosphericDownValue.ToString(), palletProceParam.StationId);
|
||||
proceParam = listParams.Where(x => x.ParameterCode.ToLower() == EStoveSignal.AtmosphericDownValue.ToString().ToLower()).FirstOrDefault();
|
||||
operateResult = SetNodeValue(node, proceParam);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_循环启动工步
|
||||
node = plc.GetVariable(EStoveSignal.CycleStartStep.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.CycleStartStep.ToString(), false);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_循环结束工步
|
||||
node = plc.GetVariable(EStoveSignal.CycleEndStep.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.CycleEndStep.ToString(), false);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_循环次数
|
||||
node = plc.GetVariable(EStoveSignal.CycleNumber.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.CycleNumber.ToString(), false);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_加热启用
|
||||
node = plc.GetVariable(EStoveSignal.HeatingEnabled.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.HeatingEnabled.ToString(), true);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_真空启用
|
||||
node = plc.GetVariable(EStoveSignal.VacuumEnabled.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.VacuumEnabled.ToString(), true);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_氮气启用
|
||||
node = plc.GetVariable(EStoveSignal.NitrogenEnabled.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.NitrogenEnabled.ToString(), true);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
//参数_工步时间
|
||||
node = plc.GetVariable(EStoveSignal.StepWorkTime.ToString(), palletProceParam.StationId);
|
||||
operateResult = SetNodeValues(node, listParams, EStoveSignal.StepWorkTime.ToString(), true);
|
||||
if (operateResult.IsSuccess)
|
||||
{
|
||||
makeAddrValues.Add(operateResult.Content);
|
||||
}
|
||||
|
||||
if (PROCESS_PARAM_NUM != makeAddrValues.Count)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("发送工艺数据项不够!", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
OperateResult result = plc.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray());
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError($"发送工艺数据失败,{result.Message}!");
|
||||
return false;
|
||||
}
|
||||
_unityContainer.Resolve<LogService>().AddLog("StoveProcessParam:SendStoveProcessParam:下发工艺参数结束", E_LogType.Info.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
OperateResult<AddrValue> SetNodeValues(Model.Models.Variable node, List<ProceParamList> proceParams, string key, bool fristNull)
|
||||
{
|
||||
object obj;
|
||||
EDataType dt = EDataType.UINT32;
|
||||
OperateResult<AddrValue> result = new OperateResult<AddrValue>() { IsSuccess = false };
|
||||
AddrValue nodeValue = new AddrValue();
|
||||
List<object> vaules = new List<object>();
|
||||
|
||||
if (fristNull)
|
||||
{
|
||||
vaules.Add(StringToObject("0", node.VarType));
|
||||
}
|
||||
|
||||
foreach (var item in proceParams)
|
||||
{
|
||||
if (item.ParameterCode.ToLower().StartsWith(key.ToLower())) //在JOSN里面,数组一定要按顺序排,或者顺序乱了
|
||||
{
|
||||
dt = (EDataType)System.Enum.Parse(typeof(EDataType), node.VarType);
|
||||
obj = StringToObject(item.TargetValue, node.VarType);
|
||||
|
||||
if (null == obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
vaules.Add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (vaules.Count == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
nodeValue.Addr = node.Address + node.VarName;
|
||||
System.Type type = System.Type.GetType(dt.GetDescription());
|
||||
MethodInfo mi = this.GetType().GetMethod(ReflexFun.OBJECT_TO_T).MakeGenericMethod(new System.Type[] { type }); //如果不转T,直接object会写不进去
|
||||
nodeValue.Value = mi.Invoke(this, new object[]
|
||||
{
|
||||
vaules
|
||||
});
|
||||
result.Content = nodeValue;
|
||||
result.IsSuccess = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public T[] ObjectToT<T>(List<object> vaules) //where T : class
|
||||
{
|
||||
return vaules.OfType<T>().ToArray(); //object[]转T[]
|
||||
}
|
||||
|
||||
object StringToObject(string value, string varType, float multiples = 1)
|
||||
{
|
||||
object obj = null;
|
||||
EDataType dt = (EDataType)Enum.Parse(typeof(EDataType), varType);
|
||||
try
|
||||
{
|
||||
switch (dt)
|
||||
{
|
||||
case EDataType.BOOL:
|
||||
obj = (value == "1");
|
||||
break;
|
||||
case EDataType.UINT16:
|
||||
obj = (UInt16)(System.Convert.ToSingle(value) * multiples);
|
||||
break;
|
||||
case EDataType.INT16:
|
||||
obj = (Int16)(System.Convert.ToSingle(value) * multiples);
|
||||
break;
|
||||
case EDataType.INT32:
|
||||
obj = (Int32)(System.Convert.ToSingle(value) * multiples);
|
||||
break;
|
||||
case EDataType.UINT32:
|
||||
obj = (UInt32)(System.Convert.ToSingle(value) * multiples);
|
||||
break;
|
||||
case EDataType.FLOAT:
|
||||
case EDataType.REAL:
|
||||
obj = (float)(System.Convert.ToSingle(value) * multiples);
|
||||
break;
|
||||
default:
|
||||
LogHelper.Instance.Fatal($"没有这种数据类型:{varType}");
|
||||
break;
|
||||
}
|
||||
if (null == obj)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("获取工艺数据的值为空");
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassDebug(ex.Message);
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
OperateResult<AddrValue> SetNodeValue(Model.Models.Variable node, ProceParamList proceParam, float multiples = 1)
|
||||
{
|
||||
OperateResult<AddrValue> result = new OperateResult<AddrValue>() { IsSuccess = false};
|
||||
AddrValue nodeValue = new AddrValue();
|
||||
if (null == node)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("获取节点数据失败");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (null == proceParam)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("获取工艺数据失败");
|
||||
return result;
|
||||
}
|
||||
|
||||
nodeValue.Addr = node.Address + node.VarName;
|
||||
nodeValue.Value = StringToObject(proceParam.TargetValue, node.VarType, multiples);
|
||||
|
||||
if (null == nodeValue.Value)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.IsSuccess = true;
|
||||
result.Content = nodeValue;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
582
Cowain.Bake.Main/Station/TaskStation.cs
Normal file
582
Cowain.Bake.Main/Station/TaskStation.cs
Normal file
@@ -0,0 +1,582 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Common.Models;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Entity;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using HslCommunication;
|
||||
using Newtonsoft.Json;
|
||||
using Opc.Ua;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Unity;
|
||||
using JSON = Newtonsoft.Json.JsonConvert;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class TaskStation: IServerManager
|
||||
{
|
||||
public string Name { get; set; }
|
||||
static Int16 _lastStepId = 0;
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
readonly TDeviceConfig config;
|
||||
IPLCDevice agv = null;
|
||||
readonly List<CavityInfoModel> _stationCavity;
|
||||
public List<TStation> _station = null;
|
||||
public AutoResetEvent _newTaskEvent = new AutoResetEvent(true);
|
||||
public TaskStation(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
_station = _unityContainer.Resolve<MemoryDataProvider>().AllStation;
|
||||
config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.AGV)[0];
|
||||
_stationCavity = _unityContainer.Resolve<CavityInfoService>().GetAllStation();
|
||||
Start();
|
||||
StartNewTask();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var task = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
|
||||
if (null == task)
|
||||
{
|
||||
_lastStepId = (int)ETaskStep.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastStepId = (short)task.StepId;
|
||||
}
|
||||
|
||||
agv = _unityContainer.Resolve<IPLCDevice>(config.Name);
|
||||
//TTaskRecord task = await GenerateTask(); #测试
|
||||
}
|
||||
public async Task DealTask(DataValue data, Variable node)
|
||||
{
|
||||
bool dealResult = false; //进去这里,看会不会触发别的
|
||||
LogHelper.Instance.Info($"开始任务--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId},{node.VarDesc}");
|
||||
do
|
||||
{
|
||||
// 启动任务并等待结果
|
||||
//dealResult = await Task.Run(() => ThreadDealTask(data, node));
|
||||
dealResult = ThreadDealTask(data, node);
|
||||
if (!dealResult)
|
||||
{
|
||||
LogHelper.Instance.Error("-------------------------处理任务异常!");
|
||||
await Task.Delay(2 * 1000);
|
||||
}
|
||||
} while(!dealResult);
|
||||
LogHelper.Instance.Info($"完成任务--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
|
||||
}
|
||||
|
||||
void StartNewTask()
|
||||
{
|
||||
Task.Run( () =>
|
||||
{
|
||||
agv = _unityContainer.Resolve<IPLCDevice>(config.Name);
|
||||
while (!cts.Token.IsCancellationRequested)
|
||||
{
|
||||
if (Global.AppExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DealNewTask();
|
||||
}
|
||||
});
|
||||
}
|
||||
public void DealNewTask()
|
||||
{
|
||||
_newTaskEvent.WaitOne(10*1000);
|
||||
|
||||
Variable nodeTemp = (from secondaryList in agv.Storages //不能做触发,因为没有任务。要地直运行里面,来检测是否有任务
|
||||
from item in secondaryList.VariableList
|
||||
where item.ParamName == EAgvPLC.RetCount.ToString()
|
||||
select item).FirstOrDefault();
|
||||
Variable node = BasicFramework.DeepCopy<Variable>(nodeTemp);
|
||||
|
||||
if (null == node || !node.Quality || null == node.CurValue) //无值,退出
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TTaskRecord oldTask = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
|
||||
|
||||
//1.有任务 + 自动 ,退出
|
||||
//2.有任务 + 手动 + 任务执行中: 退出
|
||||
if (null != oldTask)
|
||||
{
|
||||
if (oldTask.Status != (int)ETaskStatus.UnExecute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TaskEntity task = GetTask();
|
||||
|
||||
if (null == task)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommonCoreHelper.Instance.BlockTask.Add(task); //更新界面(任务未执行)
|
||||
SetCount(node);
|
||||
_lastStepId = (int)ETaskStep.MoveFrom; //StepId:手动第一次为1,自动第一次为10
|
||||
if (!SendNextStep(task, node.Json, false)) //发送第一步
|
||||
{
|
||||
return; //发送失败
|
||||
}
|
||||
|
||||
|
||||
//一条任务第一次发任务时
|
||||
if (!_unityContainer.Resolve<TaskRecordService>().ModifyTaskStatus(ETaskStatus.Executing)) //更新任务状态为执行中
|
||||
{
|
||||
LogHelper.Instance.Fatal("更改任务状态失败");
|
||||
}
|
||||
CommonCoreHelper.Instance.BlockTask.Add(task); //任务没有执行完。所以不需要更新界面
|
||||
}
|
||||
|
||||
void SetCount(Variable node)
|
||||
{
|
||||
var model = agv.Read<Int16>(node.Address + node.VarName);
|
||||
if (!model.IsSuccess
|
||||
|| 1 != model.Content)
|
||||
{
|
||||
SettingProvider.Instance.CountCmd = 0; //每条任务从1开始
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingProvider.Instance.CountCmd = 100;
|
||||
}
|
||||
}
|
||||
|
||||
private TaskEntity GetTask()
|
||||
{
|
||||
if (SettingProvider.Instance.DispMode == EDispatchMode.Auto)
|
||||
{
|
||||
var oldTask = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
|
||||
if (oldTask != null)
|
||||
{
|
||||
return GetStationManualTask(oldTask);
|
||||
}
|
||||
|
||||
//看到过有任务还生成
|
||||
return _unityContainer.Resolve<TaskRecordService>().GetTask(); //获得调度任务,并插入一条任务进任务记录表
|
||||
}
|
||||
else //手动从数据库获取
|
||||
{
|
||||
TTaskRecord manualTask = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
|
||||
if (null == manualTask)
|
||||
{
|
||||
return null; //没有任务(手动任务),就退出
|
||||
}
|
||||
return GetStationManualTask(manualTask);
|
||||
}
|
||||
}
|
||||
/*
|
||||
//1.执行中:机器人正在执行任务中, 如果上位机重启,会触发,
|
||||
//2.无务任或任务执行完成:计命令计算为0或最后一步执行完成,更新状态(无任务不需要),生成任务,下发下一步指令
|
||||
//3.一步任务完成: 更新状态, 下发下一步指令
|
||||
*/
|
||||
public bool ThreadDealTask(DataValue data, Variable node)
|
||||
{
|
||||
string msg = "";
|
||||
LogHelper.Instance.Error("开始接收调度机器人信息!");
|
||||
Int16 countValue ;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
|
||||
if (null == agv || !agv.IsConnect)
|
||||
{
|
||||
msg = "连接机器人的PLC断开!";
|
||||
LogHelper.Instance.Error(msg);
|
||||
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var stepValue = agv.Read<Int16>((string)d.ReadCmd); //可以改成直接读PLC [命令地址]
|
||||
var resultValue = agv.Read<int>((string)d.ReadResult); //这是直接读PLC [执行命令结果]
|
||||
|
||||
if (!stepValue.IsSuccess || !resultValue.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"PLC反馈任务时,读取失败!,失败原因:{stepValue.Message},{stepValue.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
|
||||
{
|
||||
countValue = (Int16)data.WrappedValue.Value;
|
||||
LogHelper.Instance.Debug($"接收任务信息:计数:{countValue},命令步:{stepValue.Content},结果:{resultValue.Content},当前命令步:{_lastStepId},当前计数:{SettingProvider.Instance.CountCmd}");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn($"没有找到这个数据类型,节点名为{node.VarDesc}", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EnumHelper.IsDefined<ETaskStep>(stepValue.Content)) //不在范围内
|
||||
{
|
||||
LogHelper.Instance.Warn($"获取PLC的命令有问题,值:{countValue}", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<EquipmentMonitorViewModel>().SetAgvImage(resultValue.Content);
|
||||
if (resultValue.Content == (int)EAgvMoveStatus.Error) // -1:表示没有完成
|
||||
{
|
||||
//if (countValue > SettingProvider.Instance.CountCmd) 此时上位机是1,PLC是3。 如果执行下面,后续PLC执行1,就不会任务了
|
||||
//{
|
||||
// SettingProvider.Instance.CountCmd = countValue;
|
||||
// LogHelper.Instance.Debug($"更改当前计数:{SettingProvider.Instance.CountCmd}");
|
||||
//}
|
||||
return false;
|
||||
}
|
||||
|
||||
//1.机器人正在执行任务中, 如果上位机重启,此时又有任务
|
||||
//如果:countValue=3000,Instance.CountCmd=1,时,到下面退出,也不影响。
|
||||
if (countValue == SettingProvider.Instance.CountCmd - 1) //(重启上位机,任务在执行中)
|
||||
{
|
||||
LogHelper.Instance.Warn($"重启上位机,此时又有任务在执行中!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_lastStepId == (int)ETaskStep.None)
|
||||
{
|
||||
LogHelper.Instance.Warn($"重启上位机, 没有任务在执行!");
|
||||
return true;
|
||||
}
|
||||
|
||||
//表示执行完成了,执行下一个; 或无任务
|
||||
if (
|
||||
countValue >= SettingProvider.Instance.CountCmd
|
||||
&& stepValue.Content == _lastStepId
|
||||
)
|
||||
{
|
||||
SettingProvider.Instance.CountCmd = countValue; //PLC跳步
|
||||
TTaskRecord task = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
|
||||
if (null == task) //无任务:不需要做什么,有任务:更新状态
|
||||
{
|
||||
LogHelper.Instance.Fatal($"此时应该数据库中要有未执行的任务,计数:{countValue},命令:{stepValue}");
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskEntity detailTask = GetStationManualTask(task); //通过任务,获取工站信息
|
||||
detailTask.StepId = (sbyte)stepValue.Content;
|
||||
|
||||
if (!DealFinishCmd(detailTask, _lastStepId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_lastStepId == (int)ETaskStep.Place //表示当前是一个任务的最后一条命令
|
||||
/* || 0 == countCmd*/) //PLC重启为0,一条完整的任务完成了,将获取最后一条指令
|
||||
{
|
||||
detailTask.StepId = (int)ETaskStep.Finish;
|
||||
CommonCoreHelper.Instance.BlockTask.Add(detailTask); //机器人界面显示
|
||||
CommonCoreHelper.Instance.MainViewAutoEvent.Set();
|
||||
_newTaskEvent.Set();
|
||||
return true; //完成了一条完整的任务,另外一个方法生成新的任务
|
||||
}
|
||||
|
||||
//发送下一步命令
|
||||
if (!SendNextStep(detailTask, node.Json))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CommonCoreHelper.Instance.BlockTask.Add(detailTask); //机器人界面显示
|
||||
CommonCoreHelper.Instance.MainViewAutoEvent.Set();
|
||||
LogHelper.Instance.Error("处理完接收调度机器人信息!");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Error($"接收到的信息PLC的调试任务异常,plc cmd:{stepValue},plc 计数:{countValue};\r" +
|
||||
$"上位机 cmd:{_lastStepId},上位机 计数:{SettingProvider.Instance.CountCmd},正常不会执行到这里!");
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError($"{ex.Message}-{ex.StackTrace}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SendNextStep(TaskEntity detailTask, string json, bool next = true)
|
||||
{
|
||||
LogHelper.Instance.Info($"发送步骤:{detailTask.StepId},命令计数:{SettingProvider.Instance.CountCmd}");
|
||||
|
||||
detailTask = SetNextStep(detailTask, next); //会设置CountCmd StepId
|
||||
if (!SendTask(detailTask, json)) //发送任务
|
||||
{
|
||||
LogHelper.Instance.Error($"发送任务信息失败,{JsonConvert.SerializeObject(detailTask)}!");
|
||||
return false;
|
||||
}
|
||||
|
||||
_lastStepId = detailTask.StepId;
|
||||
SettingProvider.Instance.CountCmd = detailTask.CountCmd;
|
||||
LogHelper.Instance.Debug($"计数改变:{SettingProvider.Instance.CountCmd}");
|
||||
return StartStep(detailTask);
|
||||
}
|
||||
|
||||
public bool ManualTaskCmd(TTaskRecord task, short stepId) //界面上指定再发送一次时,
|
||||
{
|
||||
Variable nodeCountCmd = (from secondaryList in agv.Storages //不能做触发,因为没有任务。要地直运行里面,来检测是否有任务
|
||||
from item in secondaryList.VariableList
|
||||
where item.ParamName == EAgvPLC.RetCount.ToString()
|
||||
select item).FirstOrDefault();
|
||||
|
||||
_lastStepId = (short)stepId;
|
||||
TaskEntity detailTask = GetStationManualTask(task); //通过任务,获取工站信息
|
||||
return SendNextStep(detailTask, nodeCountCmd.Json, false);
|
||||
}
|
||||
bool DealFinishCmd(TaskEntity detailTask, Int16 cmdValue)
|
||||
{
|
||||
if (0 >= _unityContainer.Resolve<TaskStepService>().UpdateEndTime(detailTask.Id, (ETaskStep)cmdValue))
|
||||
{
|
||||
LogHelper.Instance.Error($"修改命令结束时间失败!任务ID:{detailTask.Id},命令:{_lastStepId}");
|
||||
}
|
||||
|
||||
return UpdateFinishStep(detailTask);
|
||||
}
|
||||
|
||||
bool StartStep(TaskEntity detailTask)
|
||||
{
|
||||
if (0 >= _unityContainer.Resolve<TaskStepService>().UpdateStartTime((int)detailTask.Id, detailTask.CountCmd, detailTask.StepId))
|
||||
{
|
||||
LogHelper.Instance.Error($"修改命令开始时间失败!任务ID:{detailTask.Id},命令:{detailTask.StepId},命令计算:{detailTask.CountCmd}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool UpdateFinishStep(TaskEntity stationTask)
|
||||
{
|
||||
int result = 0;
|
||||
switch (stationTask.StepId)
|
||||
{
|
||||
case (int)ETaskStep.MoveFrom:
|
||||
//修改机器人的位置,给界面发信号
|
||||
result =_unityContainer.Resolve<CavityInfoService>().SetRobotPos(stationTask.FromStationNumber);
|
||||
break;
|
||||
case (int)ETaskStep.Pick:
|
||||
UpdateOutStoveTime(stationTask); //更改出炉时间
|
||||
result = _unityContainer.Resolve<TaskRecordService>().BindPalletToRobot(); //将夹具绑定在机器人上
|
||||
break;
|
||||
case (int)ETaskStep.MoveTo:
|
||||
result = _unityContainer.Resolve<CavityInfoService>().SetRobotPos(stationTask.ToStationNumber);
|
||||
break;
|
||||
case (int)ETaskStep.Place:
|
||||
result = _unityContainer.Resolve<TaskRecordService>().UpdateTask(); //1.加锁,解锁,2.绑定,解绑夹具,3.更新机器人的位置,4.更新任务状态完成,
|
||||
SendIntoStove(stationTask); //如果是满载夹具,要将调用烘烤进站接口
|
||||
_unityContainer.Resolve<TaskRecordService>().UpdateFinishStepId(stationTask.Id); //修改任务步为完成
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result <= 0)
|
||||
{
|
||||
LogHelper.Instance.Error($"接到任务完成,但处理异常:{result},cmd:{stationTask.StepId}");
|
||||
//return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateOutStoveTime(TaskEntity stationTask)
|
||||
{
|
||||
var cavityStove = _stationCavity.Where(x => x.Id == stationTask.Source && x.Type == (int)EStationType.Stove).FirstOrDefault();
|
||||
if (null != cavityStove) //更改出炉时间
|
||||
{
|
||||
_unityContainer.Resolve<PalletInfoService>().UpdateOutStoveTime(cavityStove.PalletId);
|
||||
}
|
||||
}
|
||||
|
||||
void SendIntoStove(TaskEntity stationTask)
|
||||
{
|
||||
//if (!_unityContainer.Resolve<TaskTypeService>().IsPullInBaker(stationTask.TaskTypeId))
|
||||
if (1 != stationTask.TaskTypeId)// 1: 上料满夹具->烤箱
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
var cavityInfo = _stationCavity.Where(x=>x.Id == stationTask.Target).FirstOrDefault();
|
||||
var palletInfo = _unityContainer.Resolve<PalletInfoService>().GetPalletInfo(stationTask.PalletId);
|
||||
List<string> batteryCodes = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(palletInfo.VirtualId).Select(x=>x.BatteryCode).ToList();
|
||||
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable
|
||||
&& 0 != batteryCodes.Count)
|
||||
{
|
||||
_unityContainer.Resolve<MESProcess>().MESBakingInput(cavityInfo.CavityName, palletInfo.PalletCode, batteryCodes, _unityContainer.Resolve<BasicInfoViewModel>().CurrentOperation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TaskEntity GetStationManualTask(TTaskRecord task)
|
||||
{
|
||||
TaskEntity taskEn = JSON.DeserializeObject<TaskEntity>(JSON.SerializeObject(task));
|
||||
var sourceDetail = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(task.Source);
|
||||
var targetDetail = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(task.Target);
|
||||
var stationTask = MakeManualTask(taskEn, sourceDetail, targetDetail);
|
||||
//stationTask.Copy(task, stationTask);
|
||||
return stationTask;
|
||||
}
|
||||
|
||||
TaskEntity SetNextStep(TaskEntity task, bool isNext = true)
|
||||
{
|
||||
sbyte nextStepId = (sbyte)_lastStepId;
|
||||
if (isNext)
|
||||
{
|
||||
nextStepId = (sbyte)_unityContainer.Resolve<RgvActionService>().GetNext(_lastStepId); //下一步
|
||||
}
|
||||
task.CountCmd = SettingProvider.Instance.CountCmd + 1; //下一个计数
|
||||
task.StepId = (sbyte)nextStepId;
|
||||
return task;
|
||||
}
|
||||
|
||||
public TaskEntity MakeManualTask(TaskEntity taskEn, TCavityInfo src, TCavityInfo desc)
|
||||
{
|
||||
taskEn.FromStationNumber = src.StationNumber;
|
||||
taskEn.FromRow = src.Layer;
|
||||
taskEn.FromColumn = src.Column;
|
||||
taskEn.ToStationNumber = desc.StationNumber;
|
||||
taskEn.ToRow = desc.Layer;
|
||||
taskEn.ToColumn = desc.Column;
|
||||
return taskEn;
|
||||
}
|
||||
|
||||
public bool SendTask(TaskEntity task, string json)
|
||||
{
|
||||
LogHelper.Instance.Info($"发送任务开始");
|
||||
List<AddrValue> makeAddrValues = new List<AddrValue>();
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(json);
|
||||
string fromStation = d.FromStation;
|
||||
string fromLayer = d.FromRow;
|
||||
string fromColumn = d.FromColumn;
|
||||
string toStation = d.ToStation;
|
||||
string toLayer = d.ToRow;
|
||||
string toColumn = d.ToColumn;
|
||||
string cmd = d.Cmd;
|
||||
string countAddr = d.Count;
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = fromStation,
|
||||
Value = (int)task.FromStationNumber,
|
||||
});
|
||||
|
||||
var from = _station.Where(p => p.Id == (int)task.FromStationNumber).FirstOrDefault();
|
||||
if (from.Type == (int)EStationType.Loading
|
||||
|| from.Type == (int)EStationType.UnLoading)
|
||||
{
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = fromLayer,
|
||||
Value = (int)task.FromRow,
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = fromColumn,
|
||||
Value = (int)task.FromColumn,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = fromLayer,
|
||||
Value = (int)task.FromColumn,
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = fromColumn,
|
||||
Value = (int)task.FromRow,
|
||||
});
|
||||
}
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = toStation,
|
||||
Value = (int)task.ToStationNumber,
|
||||
});
|
||||
var to = _station.Where(p => p.Id == (int)task.ToStationNumber).FirstOrDefault();
|
||||
if (to.Type == (int)EStationType.Loading
|
||||
|| to.Type == (int)EStationType.UnLoading)
|
||||
{
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = toLayer,
|
||||
Value = (int)task.ToRow,
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = toColumn,
|
||||
Value = (int)task.ToColumn,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = toLayer,
|
||||
Value = (int)task.ToColumn,
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = toColumn,
|
||||
Value = (int)task.ToRow,
|
||||
});
|
||||
}
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = cmd,
|
||||
Value = (Int16)task.StepId,
|
||||
});
|
||||
|
||||
//makeAddrValues.Add(new AddrValue()
|
||||
//{
|
||||
// Addr = countAddr,
|
||||
// Value = (Int16)task.CountCmd, //必须最后一个写
|
||||
//});
|
||||
|
||||
OperateResult result = agv.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray());
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Fatal($"写任务步骤失败:{JsonConvert.SerializeObject(makeAddrValues)},{JsonConvert.SerializeObject(makeAddrValues)}");
|
||||
}
|
||||
|
||||
result = agv.Write<Int16>(countAddr, (Int16)task.CountCmd);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Fatal($"写任务计数失败:{JsonConvert.SerializeObject(makeAddrValues)},{JsonConvert.SerializeObject(makeAddrValues)}");
|
||||
}
|
||||
|
||||
LogHelper.Instance.Debug($"发送任务:{JsonConvert.SerializeObject(makeAddrValues)}");
|
||||
LogHelper.Instance.Debug($"发送计数:{countAddr}:{(Int16)task.CountCmd}");
|
||||
//_unityContainer.Resolve<LogService>().AddLog("TaskStation:SendTask:发送任务结束", E_LogType.Info.ToString());
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
// 在需要取消任务的时候,调用以下代码:
|
||||
cts.Cancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
225
Cowain.Bake.Main/Station/TrigStation.cs
Normal file
225
Cowain.Bake.Main/Station/TrigStation.cs
Normal file
@@ -0,0 +1,225 @@
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.PLC;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Opc.Ua;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Unity;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class TrigStation : ITrigService
|
||||
{
|
||||
IUnityContainer _unityContainer;
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
public TrigStation(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
//怕消息先后导致异常,所以只能单个去
|
||||
//for (int i = 0; i < 3; i++) //还有心跳,就放开这个功能
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Task.Run( () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Global.AppExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BlockData item = _unityContainer.Resolve<PLCBlockingCollection>().MsgBlock.Take();
|
||||
int msgCount = _unityContainer.Resolve<PLCBlockingCollection>().MsgBlock.Count;
|
||||
if ("Heart" == item.Node.ParamName) //消息队列太多,就删除心跳
|
||||
{
|
||||
if (msgCount >= 5)
|
||||
{
|
||||
LogHelper.Instance.Error($"----------消费者消息数:{msgCount}");
|
||||
continue;
|
||||
}
|
||||
|
||||
Task.Run(() => ExecuteHeartTask(item.Data, item.Node));
|
||||
}
|
||||
else
|
||||
{
|
||||
RecvTrigInfo(item.Data, item.Node);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ExecuteHeartTask(DataValue data, Variable node)
|
||||
{
|
||||
RecvTrigInfo(data, node);
|
||||
}
|
||||
//多线程处理
|
||||
public void RecvTrigInfo(DataValue data, Variable node)
|
||||
{
|
||||
int value = 0;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
|
||||
string service = d.Service;
|
||||
string func = d.Func;
|
||||
string trigValue = d.TrigValue;
|
||||
string param = d.Param; //方法的参数,如果是扫码,则是扫码的编号
|
||||
MethodInfo mi = null;
|
||||
|
||||
if (string.IsNullOrEmpty(service)
|
||||
|| string.IsNullOrEmpty(func))
|
||||
{
|
||||
LogHelper.Instance.Error("解析触发信号信息失败!解析内容:" + node.TrigJson);
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = Type.GetType(MyPath.SIGNAL_TRIGGER + service);
|
||||
|
||||
if (!string.IsNullOrEmpty(trigValue))
|
||||
{
|
||||
value = GetTrigValue(data);
|
||||
|
||||
if (data.Value.GetType().IsArray)
|
||||
{
|
||||
if (value == 0) //节点的值跟所触发的信号相同(6098,扫码是数组)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value != int.Parse(trigValue)) //节点值
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//LogHelper.Instance.Info($"5--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId},{node.VarDesc}:{param},func:{func},value:{value},{node.Json}"); //执行到这,信号都会丢,
|
||||
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("开始:" + node.VarDesc);
|
||||
mi = this.GetType().GetMethod(ReflexFun.TRIG_REPLY).MakeGenericMethod(new Type[] { type }); //回复信息;
|
||||
mi.Invoke(this, new object[]
|
||||
{
|
||||
func,
|
||||
value,
|
||||
param,
|
||||
node
|
||||
});
|
||||
//_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束0:" + node.VarDesc);
|
||||
}
|
||||
else
|
||||
{
|
||||
mi = this.GetType().GetMethod(ReflexFun.TRIG_INSTANCE).MakeGenericMethod(new Type[] { type }); //夹具信号,报警这些;
|
||||
mi.Invoke(this, new object[]
|
||||
{
|
||||
func,
|
||||
data,
|
||||
node
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void TrigInstance<T>(string func, DataValue data, Variable node)
|
||||
{
|
||||
//取得实例
|
||||
var instnce = _unityContainer.Resolve<T>();
|
||||
Type t = instnce.GetType();
|
||||
//取得方法
|
||||
MethodInfo mi = t.GetMethod(func);
|
||||
//调用方法
|
||||
mi.Invoke(instnce, new object[]
|
||||
{
|
||||
data,
|
||||
node
|
||||
});
|
||||
}
|
||||
|
||||
public void TrigReply<T>(string func, int curValue, string param, Variable node)
|
||||
{
|
||||
//取得实例
|
||||
var instnce = _unityContainer.Resolve<T>(); //上下料实例
|
||||
Type t = instnce.GetType();
|
||||
|
||||
//取得方法
|
||||
MethodInfo mi = t.GetMethod(func);
|
||||
//调用方法
|
||||
mi.Invoke(instnce, new object[]
|
||||
{
|
||||
curValue,
|
||||
param,
|
||||
node
|
||||
});
|
||||
}
|
||||
|
||||
private int GetTrigValue(DataValue data)
|
||||
{
|
||||
int value = 0;
|
||||
if (data.WrappedValue.TypeInfo.ValueRank == 1) //数组
|
||||
{
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean) //下料扫码
|
||||
{
|
||||
bool[] values = (bool[])data.Value;
|
||||
for (int i = 0; i < values.Count(); i++)
|
||||
{
|
||||
if (values[i])
|
||||
{
|
||||
double temp = Math.Pow(2, i); //o
|
||||
value += (int)temp;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else //上料扫码
|
||||
{
|
||||
Int16[] values = (Int16[])data.Value;
|
||||
for (int i = 0; i < values.Count(); i++)
|
||||
{
|
||||
double temp = values[i] * Math.Pow(2, i); //ok
|
||||
value += (int)temp;
|
||||
}
|
||||
LogHelper.Instance.Fatal($"接收扫码信号:{string.Join(",", values)},{value}");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.UInt16)
|
||||
{
|
||||
value = (UInt16)data.WrappedValue.Value;
|
||||
}
|
||||
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
|
||||
{
|
||||
value = (Int16)data.WrappedValue.Value;
|
||||
}
|
||||
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int32)
|
||||
{
|
||||
value = (Int32)data.WrappedValue.Value;
|
||||
}
|
||||
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.UInt32)
|
||||
{
|
||||
value = (int)data.WrappedValue.Value;
|
||||
}
|
||||
else if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)
|
||||
{
|
||||
value = ((bool)data.WrappedValue.Value) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (int)data.WrappedValue.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
772
Cowain.Bake.Main/Station/UnLoadingStation.cs
Normal file
772
Cowain.Bake.Main/Station/UnLoadingStation.cs
Normal file
@@ -0,0 +1,772 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Common.Models;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using Cowain.Bake.Main.Views;
|
||||
using Cowain.Bake.Model;
|
||||
using Cowain.Bake.Model.Entity;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Cowain.Bake.UI.CsvMap;
|
||||
using HslCommunication;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Unity;
|
||||
using static Cowain.Bake.Common.Models.MESModel;
|
||||
using JSON = Newtonsoft.Json.JsonConvert;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class UnLoadingStation : IServerManager
|
||||
{
|
||||
IPLCDevice PLC { get; set; }
|
||||
const int DUMMY_POS_SIZE = 3;
|
||||
private int _batteryCodeLen = 0;
|
||||
List<IScanCodeBase> _deviceScann = new List<IScanCodeBase>();
|
||||
List<TBatteryInfo> _tempList = new List<TBatteryInfo>();
|
||||
public string Name { get; set; }
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
private readonly Prism.Events.IEventAggregator _eventAggregator;
|
||||
public UnLoadingStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
_eventAggregator = eventAggregator;
|
||||
TDeviceConfig config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.Loading)[0]; //上下料一个PLC
|
||||
Name = config.Name;
|
||||
SetBatteryCodeLen();
|
||||
Start();
|
||||
}
|
||||
|
||||
bool IsConnectPLC()
|
||||
{
|
||||
if (null == PLC || !PLC.IsConnect)
|
||||
{
|
||||
LogHelper.Instance.Error($"PalletVirtualId:{PLC.Name},PLC为空!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public void Start()
|
||||
{
|
||||
var configScann = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.SCANNER).OrderByDescending(x => x.Id).Take(8).ToList();
|
||||
foreach (var item in configScann)
|
||||
{
|
||||
IScanCodeBase device = _unityContainer.Resolve<IScanCodeBase>(item.Name);
|
||||
_deviceScann.Add(device);
|
||||
}
|
||||
|
||||
PLC = _unityContainer.Resolve<IPLCDevice>(Name); //下料PLC
|
||||
System.Threading.Tasks.Task.Run(() => BuildRecordFile());
|
||||
}
|
||||
|
||||
void BuildRecordFile()
|
||||
{
|
||||
string dateFile = "";
|
||||
string filePath = "";
|
||||
string path = _unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DataFilePath.ToString());//
|
||||
path += "\\出站";
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(1000 * 60);
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
dateFile = DateTime.Now.ToString("yyyyMMdd");
|
||||
filePath = path + $"\\{dateFile}.csv";
|
||||
var batteryList = _unityContainer.Resolve<BatteryInfoService>().GetOutbound();
|
||||
|
||||
if (null == batteryList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CSVHelper.WriteMap<BatteryInfoEntity, BatteryInfoDetailMap>(batteryList, filePath);
|
||||
foreach (var item in batteryList)
|
||||
{
|
||||
if (0 == _unityContainer.Resolve<BatteryInfoService>().UpdateStatus(item.Id, (int)EBatteryStatus.OutBoundRecord))
|
||||
{
|
||||
LogHelper.Instance.Fatal("修改记录出站状态失败!");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.Fatal($"BuildRecordFile:{ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
void SetDummyToWaterPlatform(string param)
|
||||
{
|
||||
int number = int.Parse(param);
|
||||
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
|
||||
_unityContainer.Resolve<BLL.BatteryInfoService>().SetDummyToWaterPlatform(palletId);
|
||||
}
|
||||
|
||||
//开始下料 ,,验证数据库OK (分二次执行,一次取假电芯,一次取正常电芯)
|
||||
public void ExecuteUnLoading(int curValue, string param, Variable node)
|
||||
{
|
||||
//Int16 batteryType = 1; //1:假电芯, 0:正常电芯
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
|
||||
if (!IsConnectPLC()) return;
|
||||
|
||||
try
|
||||
{
|
||||
if (GetUnloadBattery(param, node.Json, out bool isUnLodingDummy, out TPalletInfo palletInfo))
|
||||
{
|
||||
_unityContainer.Resolve<LogService>().AddLog("ExecuteUnLoading:下料写入托盘电池信息!", E_LogType.Info.ToString());
|
||||
WriteBatteryPostionToPLC(palletInfo, node.Json, isUnLodingDummy);
|
||||
}
|
||||
else
|
||||
{
|
||||
//SetEmptyPallet(node.Json); //如果上料中写了下料电芯数据,此时再重启上位机,状态为“下料中”,会清除,所以注释
|
||||
}
|
||||
|
||||
var writeResult = PLC.Write<Int16>((string)d.WriteResult, 1);
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"ExecuteScanPallet-写数据失败:{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.Error($"ExecuteUnLoading,出错,{ex.Message},param{param},{node.Json}");
|
||||
}
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结果数据上传到MOM,烘烤开始时间,烘烤结束时间,烘烤温度,真空值,出炉冷却后温度
|
||||
/// </summary>BakingOutputCmd,MESReturnCmdModel
|
||||
/// <param name="batterys"></param>
|
||||
/// <param name="palletInfo"></param>
|
||||
public MESReturnCmdModel MesOutUnBinding(TPalletInfo palletInfo, List<TBatteryInfo> betterys, bool realTimeSend = false)
|
||||
{
|
||||
if (0 == palletInfo.BakingPosition.Value)
|
||||
{
|
||||
palletInfo.BakingPosition = 1; //防呆
|
||||
LogHelper.Instance.Error("手动触发烘烤完成,没有烘烤位置!");
|
||||
}
|
||||
|
||||
TCavityInfo cavityInfo = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(palletInfo.BakingPosition.Value);
|
||||
if (null == cavityInfo)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("通过烘烤位置查找托盘位置失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
return _unityContainer.Resolve<MESProcess>().MESBakingOutput(cavityInfo.Name, palletInfo, betterys, true, realTimeSend);
|
||||
}
|
||||
|
||||
//请求下料,出现异常处理
|
||||
TPalletInfo DealStartUnloadFail(int number)
|
||||
{
|
||||
//去机器人上获取夹具信息,此时没有转移。
|
||||
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetRobotPallet();
|
||||
if (null != palletInfo)
|
||||
{
|
||||
LogHelper.Instance.Error("请求下料的夹具在机器人上面!");
|
||||
return palletInfo;
|
||||
}
|
||||
|
||||
//如果还没有,再到下料获取。
|
||||
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
|
||||
return _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
|
||||
}
|
||||
private bool GetUnloadBattery(string param, string reply, out bool isUnLodingDummy, out TPalletInfo palletInfo)
|
||||
{
|
||||
isUnLodingDummy = false;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
|
||||
OperateResult operateResultX = null, operateResultY = null;
|
||||
OperateResult operateResult = null;
|
||||
List<TBatteryInfo> batterys = null;
|
||||
TBatteryInfo dummy;
|
||||
Int16 batteryType = 1; //1:假电芯, 0:正常电芯
|
||||
int number = int.Parse(param);
|
||||
Int16[] dummyPos = new Int16[DUMMY_POS_SIZE];
|
||||
int[] batteryVirtualId = new int[Global.PALLET_MAX_BATTERYS];
|
||||
Array.Clear(batteryVirtualId, 0, Global.PALLET_MAX_BATTERYS);
|
||||
|
||||
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
|
||||
palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
|
||||
//要求PLC必须在上位机反馈任务完成之后再请求托盘参数
|
||||
|
||||
if (null == palletInfo) //会出现异常(发触发下料,再告诉上位机放)
|
||||
{
|
||||
palletInfo = DealStartUnloadFail(number);
|
||||
if (null == palletInfo) //
|
||||
{
|
||||
LogHelper.Instance.Error($"接收到下料信号,但获取不到下料工站{param}的夹具信息!", true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
batterys = _unityContainer.Resolve<BLL.BatteryInfoService>().GetBatteryInfos(palletInfo.VirtualId);
|
||||
|
||||
if (0 == batterys.Count)
|
||||
{
|
||||
_unityContainer.Resolve<LogService>().AddLog($"下料工站{param},找不到电池位置数据!", E_LogType.Info.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
//要满足下料条件
|
||||
if (palletInfo.PalletStatus != (int)EPalletStatus.BakeOver
|
||||
&& palletInfo.PalletStatus != (int)EPalletStatus.TestOK)
|
||||
{
|
||||
LogHelper.Instance.Fatal($"下料夹具状态不对,请人为处理,要求状态:{EPalletStatus.BakeOver.GetDescription()},{EPalletStatus.TestOK.GetDescription()},实际状态:" +
|
||||
$"{((EPalletStatus)palletInfo.PalletStatus).GetDescription()}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (palletInfo.PalletStatus == (int)EPalletStatus.BakeOver
|
||||
&& _unityContainer.Resolve<BLL.BatteryInfoService>().IsPalletDummy(palletInfo.VirtualId)) //带水含量电芯,要测试
|
||||
{
|
||||
dummy = _unityContainer.Resolve<BLL.BatteryInfoService>().FindDummy(palletInfo, batterys);
|
||||
isUnLodingDummy = true;
|
||||
if (null == dummy)
|
||||
{
|
||||
LogHelper.Instance.Fatal("获取假电芯信息失败!");
|
||||
return false;
|
||||
}
|
||||
dummyPos[1] = (Int16)dummy.PositionX.Value;
|
||||
dummyPos[2] = (Int16)dummy.PositionY.Value;
|
||||
operateResultX = PLC.Write<Int16>((string)d.WriteDummyX, dummyPos[1]); //托盘假电池行列数
|
||||
operateResultY = PLC.Write<Int16>((string)d.WriteDummyY, dummyPos[2]); //托盘假电池行列数
|
||||
if (!operateResultX.IsSuccess
|
||||
|| !operateResultY.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Debug($"设置托盘假电池行列数失败:{operateResultX.Message},{operateResultY.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
batteryType = 0; //正常电芯
|
||||
_unityContainer.Resolve<BLL.PalletInfoService>().UpdateUnLoadingBegingTime(palletInfo.Id);
|
||||
List<TBatteryInfo> normalBatterys = (from b in batterys
|
||||
where b.BatteryStatus <= (int)EBatteryStatus.ToPallet
|
||||
select b).ToList();
|
||||
if (Global.PALLET_ROWS < Global.PALLET_COLS) //7行,24列:行少列多
|
||||
{
|
||||
foreach (var item in normalBatterys)
|
||||
{
|
||||
batteryVirtualId[(item.PositionX.Value - 1) * Global.PALLET_COLS + item.PositionY.Value] = item.Id;
|
||||
}
|
||||
}
|
||||
else//48行,2列,: 行少列多
|
||||
{
|
||||
foreach (var item in normalBatterys)
|
||||
{
|
||||
batteryVirtualId[(item.PositionY.Value - 1) * Global.PALLET_ROWS + item.PositionX.Value] = item.Id;
|
||||
}
|
||||
}
|
||||
|
||||
LogHelper.Instance.Info("下料写入电芯位置:" + JSON.SerializeObject(batteryVirtualId));
|
||||
}
|
||||
//水含量电芯时,全为0
|
||||
operateResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualId); //托盘_有无电池[1-120]
|
||||
if (!operateResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"设置托盘_有无电池失败:{operateResult.Message}");
|
||||
}
|
||||
|
||||
//电芯类型
|
||||
operateResult = PLC.Write<Int16>((string)d.WriteType, batteryType); //托盘1正常电芯下料
|
||||
if (!operateResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"写下料电芯类型失败:{(string)d.WriteType},{operateResult.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//写下料位置的电池位置信息给PLC
|
||||
private void WriteBatteryPostionToPLC(TPalletInfo palletInfo, string reply, bool isUnLodingDummy)
|
||||
{
|
||||
Int16 lastValue = 0;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
|
||||
OperateResult operateResult = null;
|
||||
|
||||
|
||||
|
||||
////水含量电芯时,全为0
|
||||
//operateResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualId); //托盘_有无电池[1-120]
|
||||
//if (!operateResult.IsSuccess)
|
||||
//{
|
||||
// LogHelper.Instance.Error($"设置托盘_有无电池失败:{operateResult.Message}");
|
||||
//}
|
||||
if (!isUnLodingDummy)
|
||||
{
|
||||
lastValue = (Int16)(palletInfo.LastFlag ? 1 : 0);
|
||||
}
|
||||
|
||||
operateResult = PLC.Write<Int16>((string)d.WriteLastFlag, lastValue); //最后一盘
|
||||
if (!operateResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error($"设置托盘最后一盘失败:{operateResult.Message},{operateResult.Message}");
|
||||
}
|
||||
|
||||
//在给下料参数成功之后,再更新托盘状态。
|
||||
if (0 == _unityContainer.Resolve<BLL.PalletInfoService>().UpdatePalletStatus(palletInfo.Id, (int)EPalletStatus.Blank))
|
||||
{
|
||||
LogHelper.Instance.Error($"在给下料参数成功之后,再更新托盘状态:{operateResult.Message},{operateResult.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEmptyPallet(string reply)
|
||||
{
|
||||
_unityContainer.Resolve<LogService>().AddLog("SetEmptyPallet:设置空托盘", E_LogType.Info.ToString());
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
|
||||
List<AddrValue> makeAddrValues = new List<AddrValue>();
|
||||
int[] batteryVirtualId = new int[Global.PALLET_MAX_BATTERYS];
|
||||
Array.Clear(batteryVirtualId, 0, Global.PALLET_MAX_BATTERYS);
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = (string)d.WriteDummyX,
|
||||
Value = (Int16)0
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = (string)d.WriteDummyY,
|
||||
Value = (Int16)0
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = (string)d.WriteType,
|
||||
Value = (Int16)0
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = (string)d.WriteVirtualIds,
|
||||
Value = batteryVirtualId
|
||||
});
|
||||
|
||||
makeAddrValues.Add(new AddrValue()
|
||||
{
|
||||
Addr = (string)d.WriteResult,
|
||||
Value = true
|
||||
});
|
||||
|
||||
OperateResult result = PLC.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray());
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError("清空托盘失败!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void ExecuteUnLoadingFinish(int curValue, string param, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式,1为正式模式
|
||||
|
||||
if (!IsConnectPLC()) return;
|
||||
|
||||
//得到这个工站的夹具,通过夹具得到电芯
|
||||
int number = int.Parse(param);
|
||||
int palletId = _unityContainer.Resolve<BLL.CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
|
||||
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
|
||||
|
||||
if (null == palletInfo)
|
||||
{
|
||||
LogHelper.Instance.Error($"托盘为空, 下料{number}#工站,palletId:{palletId}");
|
||||
return;
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<BLL.PalletInfoService>().UpdateUnLoadingOverTime(palletInfo.Id);
|
||||
|
||||
if (0 == palletInfo.VirtualId
|
||||
|| 1 == palletInfo.Id)
|
||||
{
|
||||
LogHelper.Instance.Error($"下料夹具异常, 下料托盘的虚拟码为0,或下料托盘为【新夹具】");
|
||||
}
|
||||
else
|
||||
{
|
||||
_unityContainer.Resolve<BLL.PalletInfoService>().PalletInfoToHistory(palletInfo.VirtualId,
|
||||
(int)EPalletStatus.BlankOver, (int)EBatteryStatus.Over, (int)EStationType.UnLoading, number);
|
||||
}
|
||||
|
||||
var writeResult = PLC.Write<Int16>((string)d.WriteResult, 1);
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ExecuteUnLoadingFinish-{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 核对电芯条码,下料扫码
|
||||
/// </summary>
|
||||
//void VerifyBatteryCode(int curValue, string param, string reply)
|
||||
//{
|
||||
// dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
|
||||
// var result = DealVerify(reply);
|
||||
|
||||
// var writeResult = PLC.Write<bool[]>((string)d.WriteResult, result.Result);//
|
||||
// if (!writeResult.IsSuccess)
|
||||
// {
|
||||
// LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
|
||||
// }
|
||||
//}
|
||||
|
||||
//async Task<bool[]> DealVerify(string reply)
|
||||
//{
|
||||
// int index = 0, j = 0;
|
||||
// bool[] results = new bool[Global.ONCE_SCAN_BATTERY];
|
||||
// Array.Clear(results, 0, Global.ONCE_SCAN_BATTERY);
|
||||
// List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
|
||||
// dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
|
||||
// if (!IsConnectPLC()) return results;
|
||||
|
||||
// OperateResult<Int32[]> batterys = PLC.Read<Int32[]>((string)d.ReadVirtualIds); //下料处电芯虚拟码 读取下料温度[1..8]
|
||||
// if (!batterys.IsSuccess)
|
||||
// {
|
||||
// LogHelper.Instance.Warn($"核对电芯条码时,读取电芯虚拟码错误:{batterys.Message}");
|
||||
// return results;
|
||||
// }
|
||||
|
||||
// if (batterys.Content.All(x => x == 0)) //True 全部为0
|
||||
// {
|
||||
// LogHelper.Instance.Warn($"核对电芯条码时,读取电芯虚拟码异常,全部虚拟码都为0");
|
||||
// return results;
|
||||
// }
|
||||
|
||||
// //读条码
|
||||
// for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, index++)
|
||||
// {
|
||||
// if (0 == batterys.Content[index])
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
|
||||
|
||||
// if (!scanDevice.IsConnect)
|
||||
// {
|
||||
// string msg = $"获取{s.GetDescription()}失败,请检测线路!";
|
||||
// LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
|
||||
// _unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
// scanDevice.Connect();
|
||||
// --s; //再次获取
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
|
||||
// }
|
||||
|
||||
// await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
|
||||
// index = 0;
|
||||
// var batteryCodes = GetBatteryCode(batterys.Content);//获取PLC传过来的虚拟码
|
||||
|
||||
// //比较条码
|
||||
// for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, j++)
|
||||
// {
|
||||
// if (0 == batterys.Content[index])
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (!batteryCodes.Contains(scannTasks[index++].Result.Content)) //没有用等于号,是因为这样兼容更好一点
|
||||
// {
|
||||
// LogHelper.Instance.Warn($"下料核对电芯异常,PLC电芯:{string.Join(",", batteryCodes)},扫码电芯:{JSON.SerializeObject(scannTasks)}");
|
||||
// //continue; //异常
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// results[j] = true;
|
||||
// }
|
||||
// }
|
||||
// _unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
|
||||
// return results;
|
||||
//}
|
||||
|
||||
//取假电芯完成,验证数据库OK
|
||||
public void ExecuteTakeDummyFinish(int curValue, string param, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
if (!IsConnectPLC()) return;
|
||||
_unityContainer.Resolve<LogService>().AddLog("UnLoadingStation:ExecuteTakeDummyFinish:取假电池开始:" + param, E_LogType.Info.ToString());
|
||||
int number = int.Parse(param);
|
||||
int palletId = _unityContainer.Resolve<BLL.CavityInfoService>().GetPalletId((int)EStationType.UnLoading, number);
|
||||
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
|
||||
|
||||
if (null == palletInfo)
|
||||
{
|
||||
LogHelper.Instance.Error($"接收下料{number}工站取假电芯完成信号,但获取不到下料夹具!", true);
|
||||
return;
|
||||
}
|
||||
|
||||
//这里再改假电芯状态
|
||||
SetDummyToWaterPlatform(param);
|
||||
|
||||
//重启后,可能再次收到1#托盘取假电池完成信号(待水含量测试),此时状态可能测试OK或NG
|
||||
if (palletInfo.PalletStatus == (int)EPalletStatus.BakeOver
|
||||
|| palletInfo.PalletStatus == (int)EPalletStatus.Blank) //取水含量电芯时,也是下料中状态
|
||||
{
|
||||
_unityContainer.Resolve<BLL.PalletInfoService>().UpdatePalletStatus(palletInfo.Id, (int)EPalletStatus.WaitTest);
|
||||
}
|
||||
|
||||
var writeResult = PLC.Write<Int16>((string)d.WriteResult, 1);
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn($"ExecuteTakeDummyFinish-{(string)d.WriteResult}:{writeResult.Message}");
|
||||
}
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
public void SetBatteryCodeLen()
|
||||
{
|
||||
_batteryCodeLen = int.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.BatteryCodeLen.ToString()));
|
||||
}
|
||||
public async Task<List<OperateResult<string>>> GetScannResult(int curValue)
|
||||
{
|
||||
int index = 1;
|
||||
List<string> batteryCodes = new List<string>();
|
||||
List<OperateResult<string>> scannList = new List<OperateResult<string>>();
|
||||
List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
|
||||
|
||||
OperateResult<string> scanResult = new OperateResult<string>()
|
||||
{
|
||||
IsSuccess = false,
|
||||
};
|
||||
|
||||
for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, index++)
|
||||
{
|
||||
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
|
||||
|
||||
if (!scanDevice.IsConnect)
|
||||
{
|
||||
string msg = $"获取{s.GetDescription()}失败,请检测线路!";
|
||||
LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
|
||||
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
scanDevice.Connect();
|
||||
--s; //再次获取
|
||||
continue;
|
||||
}
|
||||
|
||||
scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
|
||||
}
|
||||
|
||||
await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
|
||||
foreach (var task in scannTasks)
|
||||
{
|
||||
scannList.Add(task.Result);
|
||||
}
|
||||
|
||||
return scannList;
|
||||
}
|
||||
|
||||
public async Task<bool[]> DealTemp(IPLCDevice plc, int curValue, string reply)
|
||||
{
|
||||
string msg = "";
|
||||
int index = 1;
|
||||
int scannIndex = 0;
|
||||
bool[] repResults = new bool[Global.ONCE_SCAN_BATTERY + 1];
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(reply);
|
||||
List<string> batteryCodes = null;
|
||||
List<OperateResult<string>> scannList;
|
||||
MESReturnCmdModel result = null;
|
||||
bool isDummy = false;
|
||||
Array.Clear(repResults, 0, Global.ONCE_SCAN_BATTERY + 1);
|
||||
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式,1为正式模式
|
||||
_tempList.Clear();
|
||||
try
|
||||
{
|
||||
if (!IsConnectPLC()) return null;
|
||||
|
||||
OperateResult<float[]> readTemps = plc.Read<float[]>((string)d.ReadTemp); //下料处电芯温度,读取下料温度[1..4]
|
||||
if (!readTemps.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Warn("读取下料温度失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((int)EProductionMode.Debug == debugMode) //调试模式
|
||||
{
|
||||
repResults[1] = true;
|
||||
return repResults;
|
||||
}
|
||||
|
||||
scannList = await GetScannResult(curValue); //
|
||||
for (EScanCode s = EScanCode.UnLoadingBatteryScan1; s <= EScanCode.UnLoadingBatteryScan8; s++, index++)
|
||||
{
|
||||
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
repResults[index] = true;
|
||||
|
||||
if (scannList[scannIndex].IsSuccess)
|
||||
{
|
||||
_tempList.Add(new TBatteryInfo()
|
||||
{
|
||||
BatteryCode = scannList[scannIndex].Content, //实际要扫码
|
||||
CoolTemp = readTemps.Content[index] //1...8排序
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MessageBoxResult.Yes == HandyControl.Controls.MessageBox.Show($"[{s.GetDescription()}]扫码失败,您确定此位置是否有电芯?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Information))
|
||||
{
|
||||
_tempList.Add(new TBatteryInfo()
|
||||
{
|
||||
BatteryCode = GetBatteryCode(s.GetDescription()), //弹屏,输入电芯条码
|
||||
CoolTemp = readTemps.Content[index] //1...8排序
|
||||
});
|
||||
}
|
||||
else //无电芯
|
||||
{
|
||||
repResults[index] = false; //扫码NG,并人为确认无电芯
|
||||
}
|
||||
}
|
||||
|
||||
scannIndex++;
|
||||
}
|
||||
|
||||
batteryCodes = _tempList.Select(x => x.BatteryCode).ToList();
|
||||
LogHelper.Instance.Info($"读取下料PLC的电芯虚拟码:{string.Join(",", batteryCodes)}");
|
||||
List<TBatteryInfo> currentBatterys = _unityContainer.Resolve<BatteryInfoService>().GetBatterys(batteryCodes); //8个电芯(最多),可能会来自多个托盘
|
||||
if (null == currentBatterys
|
||||
|| currentBatterys.Count == 0) //PLC有BUG,有时为0,导致上位机没办法回复,会PLC超时
|
||||
{
|
||||
msg = $"下发温度读取失败,{Global.ONCE_SCAN_BATTERY}个电池虚拟码为0!";
|
||||
LogHelper.Instance.Error("下发温度读取完成失败,电池虚拟码为0!");
|
||||
_unityContainer.Resolve<LogService>().AddLog("下发温度读取完成失败,电池虚拟码为0!", E_LogType.Fatal.ToString());
|
||||
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
return repResults;
|
||||
}
|
||||
else if (currentBatterys.Count == 1) //一个电芯,判断是否是假电芯
|
||||
{
|
||||
if (_unityContainer.Resolve<BatteryInfoService>().IsDummy(currentBatterys[0].Id))
|
||||
{
|
||||
isDummy = true;
|
||||
return repResults; //假电芯就不上传了
|
||||
}
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<BatteryInfoService>().UpdateCoolTempAndUnBindingTime(currentBatterys, _tempList);// temps);
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
|
||||
{
|
||||
var batterySort = currentBatterys.GroupBy(p => new { p.PalletVirtualId }).Select(s => s.FirstOrDefault()).ToList(); //获取一个托盘中的一个电芯
|
||||
|
||||
foreach (var item in batterySort) //一个托盘只返回第一个电芯
|
||||
{
|
||||
var palletBatterys = currentBatterys.Where(x => batteryCodes.Contains(x.BatteryCode) && x.PalletVirtualId == item.PalletVirtualId).ToList(); //获取一个托盘中的电芯
|
||||
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfoByBatteryVirtualId(item.PalletVirtualId); //此时托盘可能已经转历史盘托了
|
||||
|
||||
if (null == palletInfo)
|
||||
{
|
||||
msg = $"MOM上传冷却温度时,找不到电芯所在托盘,电芯:{string.Join(",", palletBatterys.Select(x => x.BatteryCode).ToList())}!";
|
||||
LogHelper.Instance.Fatal(msg);
|
||||
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
var mesResult = MesOutUnBinding(palletInfo, palletBatterys);//组装数据 发送
|
||||
//因为没有等MOM,所以注掉下面代码
|
||||
//if (mesResult == null)
|
||||
//{
|
||||
// LogHelper.Instance.Error($"自动出站,MOM返回超时,电芯条码:{string.Join(",", palletBatterys.Select(x => x.BatteryCode).ToList())}"); //偶尔会返回空,导致人为要处理,麻烦,所以只保存到日志
|
||||
//}
|
||||
//else if (mesResult.Info.ResultFlag.ToUpper() == "NG" && (!isDummy))
|
||||
//{
|
||||
// msg = $"自动出站,MOM返回信息异常,信息:{JSON.SerializeObject(result)}";
|
||||
// LogHelper.Instance.Error(msg);
|
||||
// _unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// _unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Instance.Fatal($"读温失败:{e.Message},{e.StackTrace}");
|
||||
}
|
||||
|
||||
return repResults;
|
||||
}
|
||||
|
||||
public string GetBatteryCode(string desc)
|
||||
{
|
||||
string batteryCode = "";
|
||||
while (string.IsNullOrEmpty(batteryCode))
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke((Action)(() =>
|
||||
{
|
||||
PalletIdInputWindow f = new PalletIdInputWindow("电芯码输入框", $"{desc}扫码失败," + "请输入电芯条码", "确定输入电芯条码?")
|
||||
{
|
||||
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen,
|
||||
};
|
||||
f.ShowDialog();
|
||||
batteryCode = f.PalletId;
|
||||
}));
|
||||
|
||||
if (!_unityContainer.Resolve<BatteryInfoService>().IsBatteryCodeRepeat(batteryCode))
|
||||
{
|
||||
LogHelper.Instance.Error($"【{batteryCode}】,不存在,请重新输入!", true);
|
||||
batteryCode = "";
|
||||
}
|
||||
}
|
||||
return batteryCode;
|
||||
}
|
||||
//获取下料温度
|
||||
public async Task GetTemp(int curValue, string param, Variable node)
|
||||
{
|
||||
OperateResult operateResult = null;
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
|
||||
IPLCDevice plc = _unityContainer.Resolve<IPLCDevice>((string)d.PLCName); //上料PLC
|
||||
var result = await DealTemp(plc, curValue, node.Json);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
operateResult = plc.Write<bool[]>((string)d.WriteResult, result); //MOM没有返回数据,导致
|
||||
if (!operateResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.Error("下发温度读取完成失败!");
|
||||
return;
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
200
Cowain.Bake.Main/Station/UpdateStation.cs
Normal file
200
Cowain.Bake.Main/Station/UpdateStation.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Interface;
|
||||
using Cowain.Bake.Communication.Interface;
|
||||
using Cowain.Bake.Model.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Opc.Ua;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using Unity;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
public class UpdateStation : IServerManager
|
||||
{
|
||||
readonly ConcurrentDictionary<int, bool[]> _stovePalletSignal;
|
||||
public string Name { get; set; }
|
||||
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
|
||||
|
||||
public UpdateStation(IUnityContainer unityContainer)
|
||||
{
|
||||
_unityContainer = unityContainer;
|
||||
_stovePalletSignal = new ConcurrentDictionary<int, bool[]>();
|
||||
}
|
||||
bool IsConnectPLC(IPLCDevice PLC)
|
||||
{
|
||||
if (null == PLC || !PLC.IsConnect)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError($"连接PLC失败:{PLC.Name},PLC为空!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//LifeCycle PLC请求命令:0=无意义;10=无托盘;20=有托盘
|
||||
public int UpdateCavityStatus(DataValue data, Variable node)
|
||||
{
|
||||
Int16 signalValue = 0;
|
||||
Int16 result = (Int16)EResult.OK; //1=OK,2=重新上传
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson); //生命周期
|
||||
dynamic reply = JsonConvert.DeserializeObject<dynamic>(node.Json); //反馈收到PLC的周期信号,反馈PLC的命令,0也要反馈,1=OK,2=重新上传
|
||||
|
||||
var config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(node.StationId);
|
||||
IPLCDevice PLC = _unityContainer.Resolve<IPLCDevice>(config.Name);
|
||||
if (!IsConnectPLC(PLC)) return 0;
|
||||
|
||||
var countCavitySignal = PLC.GetValue<System.Int16>((string)d.CountCavitySignal, node.StationId, node.Number);
|
||||
if (!countCavitySignal.IsSuccess)
|
||||
{
|
||||
result = (Int16)EResult.NG;
|
||||
LogHelper.Instance.Error($"读取腔体的信号计数失败!原因:{countCavitySignal.Message}");
|
||||
}
|
||||
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16)
|
||||
{
|
||||
signalValue = (System.Int16)data.WrappedValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (Int16)EResult.NG;
|
||||
LogHelper.Instance.Warn($"没有找到夹具信号这个数据类型,节点名为{node.VarDesc}");
|
||||
}
|
||||
|
||||
var writeResult = PLC.Write<Int16>(reply.CountCavitySignal, countCavitySignal.Content);
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"写腔体的信号计数失败,地址:{reply.CountCavitySignal},值:{countCavitySignal.Content},{writeResult.Message}");
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16>(reply.SignalValue, signalValue);
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"写腔体的信号失败,地址:{reply.SignalValue},值:{signalValue},{writeResult.Message}");
|
||||
}
|
||||
|
||||
writeResult = PLC.Write<Int16>(reply.CavitySignalResult, result);
|
||||
if (!writeResult.IsSuccess)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassWarn($"写回复腔体的信号失败,地址:{reply.CavitySignalResult},值:{result},{writeResult.Message}");
|
||||
}
|
||||
|
||||
return _unityContainer.Resolve<CavityInfoService>().UpdateCavitySignal(node.StationId, node.Number, signalValue);
|
||||
}
|
||||
|
||||
public int UpdateDoorStatus(DataValue data, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
|
||||
string layer = d.Layer;
|
||||
bool status = false;
|
||||
|
||||
if (string.IsNullOrEmpty(layer))
|
||||
{
|
||||
LogHelper.Instance.Warn($"触发夹具到位信号,但获取相关信息失败{node.TrigJson}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)
|
||||
{
|
||||
status = (bool)data.WrappedValue.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Instance.Warn($"没有找到开/关门这个数据类型,节点名为{node.VarDesc}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (node.ParamName == EStoveSignal.OpenDoorPlace.ToString())
|
||||
{
|
||||
status = true;
|
||||
}
|
||||
|
||||
return _unityContainer.Resolve<CavityInfoService>().UpdateDoorStatus(node.StationId, int.Parse(layer), status);
|
||||
}
|
||||
|
||||
public int UpdateLoadStatus(DataValue data, Variable node)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.TrigJson);
|
||||
string layer = d.Layer;
|
||||
string number = d.Number;
|
||||
bool[] status = null;
|
||||
|
||||
if (data.WrappedValue.TypeInfo.ValueRank == 1) //数组,炉子夹具传感器信号
|
||||
{
|
||||
if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Boolean)
|
||||
{
|
||||
status = (bool[])data.WrappedValue.Value;
|
||||
}
|
||||
|
||||
if (_stovePalletSignal.TryGetValue(node.StationId, out bool[] oldValue)) //有
|
||||
{
|
||||
if (oldValue.Count() != status.Count())
|
||||
{
|
||||
LogHelper.Instance.Error($"烤箱到位信号老值与新值长度不匹配,工站:{node.StationId},desc:{string.Join(",", status)}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_stovePalletSignal[node.StationId] = status;
|
||||
var diffs = status.Zip(oldValue, (a, b) => a != b).Select((b, i) => new { Value = b, Index = i }).Where(x => x.Value);
|
||||
|
||||
foreach (var item in diffs)
|
||||
{
|
||||
if (0 == item.Index)
|
||||
{
|
||||
continue; //第一个不用
|
||||
}
|
||||
|
||||
int result = _unityContainer.Resolve<CavityInfoService>().UpdateLoadStatus(node.StationId, item.Index, 1, status[item.Index]);
|
||||
if (0 != result)
|
||||
{
|
||||
LogHelper.Instance.Warn($"修改状态数据失败,StationId:{node.StationId},layer:{item.Index},{status[item.Index]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else //重启时,更新所有信号
|
||||
{
|
||||
|
||||
|
||||
_stovePalletSignal[node.StationId] = status;
|
||||
for (int i = 1; i <= Global.STOVE_LAYERS; ++i) //上位机启动
|
||||
{
|
||||
int result = _unityContainer.Resolve<CavityInfoService>().UpdateLoadStatus(node.StationId, i, 1, status[i]);
|
||||
if (0 != result)
|
||||
{
|
||||
LogHelper.Instance.Warn($"修改状态数据失败,StationId:{node.StationId},layer:{i},{status[i]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else //上下料和人工夹具平台
|
||||
{
|
||||
var value = (bool)data.WrappedValue.Value;
|
||||
int result = _unityContainer.Resolve<CavityInfoService>().UpdateLoadStatus(node.StationId, int.Parse(layer), int.Parse(number), value);
|
||||
if (0 != result)
|
||||
{
|
||||
LogHelper.Instance.Warn($"修改状态数据失败,StationId:{node.StationId},layer:{layer},{number},{value}");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
public void Start()
|
||||
{
|
||||
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
227
Cowain.Bake.Main/Station/UploadMesStation.cs
Normal file
227
Cowain.Bake.Main/Station/UploadMesStation.cs
Normal file
@@ -0,0 +1,227 @@
|
||||
using Cowain.Bake.BLL;
|
||||
using Cowain.Bake.Common;
|
||||
using Cowain.Bake.Common.Core;
|
||||
using Cowain.Bake.Common.Enums;
|
||||
using Cowain.Bake.Common.Models;
|
||||
using Cowain.Bake.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Unity;
|
||||
using JSON = Newtonsoft.Json.JsonConvert;
|
||||
using Cowain.Bake.Main.ViewModels;
|
||||
using static Cowain.Bake.Common.Models.MESModel;
|
||||
using Cowain.Bake.Communication.MOM;
|
||||
using Cowain.Bake.Model.Models;
|
||||
|
||||
namespace Cowain.Bake.Main.Station
|
||||
{
|
||||
//自动上传模块
|
||||
public class UploadMesStation
|
||||
{
|
||||
public bool? OrdeIsMesOnline { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool haveWarn = true;
|
||||
public string IpAddress { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string URL { get; set; }
|
||||
public IUnityContainer _unityContainer { get; set; }
|
||||
public int Id { get; set; }
|
||||
List<ProceParamList> listParams = new List<ProceParamList>();
|
||||
private readonly Prism.Events.IEventAggregator _eventAggregator;
|
||||
public UploadMesStation(IUnityContainer unityContainer, Prism.Events.IEventAggregator eventAggregator)
|
||||
{
|
||||
bool IsMesOnline = false;
|
||||
_unityContainer = unityContainer;
|
||||
TDeviceConfig dev = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.MOM)[0];
|
||||
Id = dev.Id;
|
||||
Name = dev.Name;
|
||||
_eventAggregator = eventAggregator;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Global.AppExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsMesOnline = false;
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
|
||||
{
|
||||
MESReturnCmdModel mesResult = _unityContainer.Resolve<MESProcess>().Alive();
|
||||
IsMesOnline = DealAlive(mesResult);
|
||||
}
|
||||
|
||||
if (OrdeIsMesOnline != IsMesOnline)
|
||||
{
|
||||
;
|
||||
OrdeIsMesOnline = IsMesOnline;
|
||||
_unityContainer.Resolve<DeviceConfigService>().UpdateStatus(this.Id, IsMesOnline);
|
||||
_unityContainer.Resolve<BasicInfoViewModel>().MesStatus = IsMesOnline;
|
||||
}
|
||||
|
||||
await Task.Delay(5000); //放这里的目的,是心跳后,再执行上传
|
||||
}
|
||||
});
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(3000);
|
||||
if (Global.AppExit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable)
|
||||
{
|
||||
Run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//MOM在回复心跳时通过KeyFlag= 2提醒设备需要调用MOM的工艺参数下发接口
|
||||
//MOM在回复心跳时通过KeyFlag= 2提醒设备需要调用MOM的工艺参数下发接口
|
||||
bool DealAlive(MESReturnCmdModel mesResult)
|
||||
{
|
||||
if (null == mesResult)
|
||||
{
|
||||
LogHelper.Instance.Warn($"MES不在线:{JSON.SerializeObject(mesResult)}");
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (((int)EKeyFlag.NG).ToString() == mesResult.Info.KeyFlag)
|
||||
{
|
||||
TAlarm model = new TAlarm()
|
||||
{
|
||||
StationId = (int)EAlarmStationId.Mom,
|
||||
Desc = $"MOM心跳报警->{mesResult.Info.MOMMessage}", //会存在多次不同的报警
|
||||
StartTime = DateTime.Now,
|
||||
Status = EAlarmStatus.Alert.GetDescription(),
|
||||
};
|
||||
haveWarn = true;
|
||||
|
||||
_eventAggregator.GetEvent<AlarmAddEvent>().Publish(model);//2.界面刷新,发布事件(发送消息)
|
||||
_unityContainer.Resolve<AlarmService>().Insert(model);
|
||||
return true;
|
||||
}
|
||||
else if (((int)EKeyFlag.ProcessParam).ToString() == mesResult.Info.KeyFlag) //心跳时通过KeyFlag= 2提醒设备需要调用MOM的工艺参数下发接口
|
||||
{
|
||||
listParams.Clear();
|
||||
EqptParameterReturnCmd resultModel = _unityContainer.Resolve<MESProcess>().GetProcessParam();//获取返回的JOSN
|
||||
if (null == resultModel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TProductionInformation model = _unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo();//实例化工单类
|
||||
|
||||
if (!_unityContainer.Resolve<ProcessParamService>().UpdateProcessParam(model.ProcessParamId, JSON.SerializeObject(resultModel.Info.ParameterInfo)))
|
||||
{
|
||||
LogHelper.Instance.Warn("保存工艺参数失败!");
|
||||
}
|
||||
}
|
||||
|
||||
if (haveWarn && ((int)EKeyFlag.NG).ToString() != mesResult.Info.KeyFlag)
|
||||
{
|
||||
_eventAggregator.GetEvent<AlarmStaionCancelEvent>().Publish((int)EAlarmStationId.Mom);//2.界面刷新,发布事件(发送消息)
|
||||
var alarms = _unityContainer.Resolve<AlarmService>().GetInAlarm((int)EAlarmStationId.Mom);
|
||||
foreach (var item in alarms)
|
||||
{
|
||||
_unityContainer.Resolve<AlarmService>().CancelAlarm(item);
|
||||
}
|
||||
haveWarn = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//public void GetJsonParam(string param)
|
||||
//{
|
||||
// dynamic d = JsonConvert.DeserializeObject<dynamic>(param);
|
||||
// this.IpAddress = d.Ip;
|
||||
// this.Port = d.Port;
|
||||
// this.URL = d.URL;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
void Run()
|
||||
{
|
||||
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) != (int)EMOMEnable.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<TMesData> uploadItems = _unityContainer.Resolve<MesDataService>().GetUpLoadData();
|
||||
|
||||
foreach (var item in uploadItems)
|
||||
{
|
||||
dynamic d = JsonConvert.DeserializeObject<dynamic>(item.CommandType);
|
||||
string service = d.Service;
|
||||
string func = d.Func;
|
||||
string url = d.UrlCmd;
|
||||
Type type = Type.GetType(MyPath.SIGNAL_TRIGGER + service);
|
||||
MethodInfo mi = this.GetType().GetMethod("ExecuteUpload").MakeGenericMethod(new Type[] { type }); //回复信息;
|
||||
|
||||
mi.Invoke(this, new object[]
|
||||
{
|
||||
func,
|
||||
url,
|
||||
item,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteUpload<T>(string func, string url, TMesData mesModel)
|
||||
{
|
||||
//取得实例
|
||||
var instnce = _unityContainer.Resolve<T>(); //上下料实例
|
||||
Type t = instnce.GetType();
|
||||
//取得方法
|
||||
MethodInfo mi = t.GetMethod(func);
|
||||
//调用方法
|
||||
mi.Invoke(instnce, new object[] //这里会去执行哪个方法上传,参数只有发送的信息
|
||||
{
|
||||
url,
|
||||
mesModel
|
||||
});
|
||||
}
|
||||
|
||||
public void UploadCommon(string url, TMesData mesModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
//这里就是调用上传的接口
|
||||
mesModel.SendTime = DateTime.Now;
|
||||
string result = HttpClientHelper.HttpPost(url, mesModel.Content);
|
||||
if (string.IsNullOrEmpty(result)) //请求失败
|
||||
{
|
||||
mesModel.SendFlag = (sbyte)EMesUpLoadStatus.Fail;
|
||||
}
|
||||
else //请求成功
|
||||
{
|
||||
mesModel.SendFlag = (sbyte)EMesUpLoadStatus.Success;
|
||||
mesModel.RecvContent = result;
|
||||
mesModel.RecvTime = DateTime.Now;
|
||||
_unityContainer.Resolve<MESProcess>().WriteRequestLog(mesModel.Content);
|
||||
_unityContainer.Resolve<MESProcess>().WriteResponseLog(result);
|
||||
}
|
||||
|
||||
_unityContainer.Resolve<MesDataService>().Update(mesModel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Instance.GetCurrentClassError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user