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 _stovePalletSignal; public string Name { get; set; } public IUnityContainer _unityContainer { get; set; } public UpdateStation(IUnityContainer unityContainer) { _unityContainer = unityContainer; _stovePalletSignal = new ConcurrentDictionary(); } 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(node.TrigJson); //生命周期 dynamic reply = JsonConvert.DeserializeObject(node.Json); //反馈收到PLC的周期信号,反馈PLC的命令,0也要反馈,1=OK,2=重新上传 var config = _unityContainer.Resolve().GetConfig(node.StationId); IPLCDevice PLC = _unityContainer.Resolve(config.Name); if (!IsConnectPLC(PLC)) return 0; var countCavitySignal = PLC.GetValue((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(reply.CountCavitySignal, countCavitySignal.Content); if (!writeResult.IsSuccess) { LogHelper.Instance.GetCurrentClassWarn($"写腔体的信号计数失败,地址:{reply.CountCavitySignal},值:{countCavitySignal.Content},{writeResult.Message}"); } writeResult = PLC.Write(reply.SignalValue, signalValue); if (!writeResult.IsSuccess) { LogHelper.Instance.GetCurrentClassWarn($"写腔体的信号失败,地址:{reply.SignalValue},值:{signalValue},{writeResult.Message}"); } writeResult = PLC.Write(reply.CavitySignalResult, result); if (!writeResult.IsSuccess) { LogHelper.Instance.GetCurrentClassWarn($"写回复腔体的信号失败,地址:{reply.CavitySignalResult},值:{result},{writeResult.Message}"); } return _unityContainer.Resolve().UpdateCavitySignal(node.StationId, node.Number, signalValue); } public int UpdateDoorStatus(DataValue data, Variable node) { dynamic d = JsonConvert.DeserializeObject(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().UpdateDoorStatus(node.StationId, int.Parse(layer), status); } public int UpdateLoadStatus(DataValue data, Variable node) { dynamic d = JsonConvert.DeserializeObject(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().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().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().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() { } } }