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(); cmdFactories = _unityContainer.Resolve(); Start(); } public void Start() { Task.Run(async () => { while (!cts.Token.IsCancellationRequested) { try { if (Global.AppExit) { return; } await Task.Delay(6 * 1000); List details = _unityContainer.Resolve().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().AddLog("BakingStation:Start:工艺参数,异常" + ex.Message, E_LogType.Debug.ToString()); //throw; } } }, cts.Token); } void ProcessStartBaking(List stoveDetails) { List bakeFlag = new List(); bool[] bakeEnable = new bool[Global.STOVE_MAX_LAYERS]; List layers = null; var stoves = stoveDetails.GroupBy(p => new { p.StationId }).Select(s => s.FirstOrDefault()).ToList(); foreach (var stove in stoves) //烘烤以层为单位,所以以层为单位循环,这样简单 { var conf = _unityContainer.Resolve().GetConfig(stove.StationId); IPLCDevice plc = _unityContainer.Resolve(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 ids = layers.Select(x => x.PalletId).ToList(); //修改夹具状态 LogHelper.Instance.Info($"下发工艺参数成功!工站:{stove.Name},工单:{stove.JobNum},托盘号:{JsonSerializer.Serialize(ids)}"); int updateResult = _unityContainer.Resolve().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 stoveCavitys = _unityContainer.Resolve().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().UpdateBakingOverTime(ids); if (updateResult <= 0) { LogHelper.Instance.Warn($"修改夹具为烘烤完成,{string.Join(",", ids)}状态失败!"); }; } //void ProcessEndBaking(List stoveDetails) //{ // bool[] bakeFlag = new bool[Global.STOVE_LAYERS]; // List 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().GetConfig(stove.StationId); // IPLCDevice plc = _unityContainer.Resolve(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(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().UpdateBakingOverTime(ids); // if (updateResult <= 0) // { // LogHelper.Instance.Warn($"修改夹具{string.Join(",", ids)}状态失败!"); // }; // } // } //} public void Stop() { // 在需要取消任务的时候,调用以下代码: cts.Cancel(); } } }