using Bro.Common.Helper; using Bro.Common.Model; using Bro.Common.Model.Interface; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing.Design; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using static Bro.Common.Helper.EnumHelper; namespace Bro.Common.Base { public abstract class PLCBase : DeviceBase, IMonitor { public PLCInitialConfigBase PLCIConfig { get => InitialConfig as PLCInitialConfigBase; } public abstract void Write(PLCOperationConfigBase config); public abstract void Read(PLCOperationConfigBase config); public abstract void ReadItem(PLC_ITEM item); public abstract void WriteItem(PLC_ITEM item, bool waitForReply = true); public abstract void WriteSingleAddress(int address, int writeValue, bool waitForReply = true); #region 委托 public Action OnPLCDataChanged; #endregion #region IMonitor public event OnMonitorInvokeDelegate OnMonitorInvoke; public event OnMonitorAlarmDelegate OnMonitorAlarm; protected List oldValues = new List(); public abstract List GetMonitorValues(int startAddress, int length); public virtual void Monitor() { if (PLCIConfig != null && PLCIConfig.EventStartAddress > 0 && PLCIConfig.EventLength > 0 && PLCIConfig.ScanInterval > 0) { while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept) { try { List newValues = GetMonitorValues(PLCIConfig.EventStartAddress, PLCIConfig.EventLength); if (newValues == null || newValues.Count == 0) continue; //Stopwatch sw = new Stopwatch(); //sw.Start(); if (oldValues.Count == newValues.Count) { var tempNew = new List(newValues); var tempOld = new List(oldValues); MonitorCheckAndInvoke(tempNew, tempOld); } oldValues = new List(newValues); //sw.Stop(); //if (sw.ElapsedMilliseconds > 10) //{ // LogAsync(DateTime.Now, $"轮询时间:{sw.ElapsedMilliseconds}", ""); // TimeRecordCSV(DateTime.Now, "轮询时间", (int)sw.ElapsedMilliseconds); //} Thread.Sleep(PLCIConfig.ScanInterval); } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, "PLC监听异常:" + ex.GetExceptionMessage()); } } } } protected virtual void MonitorCheckAndInvoke(List tempNew, List tempOld) { #region PLC警报信息 //bool warningSignal = (m.TriggerIndex >= PLCIConfig.WarningStartIndex && m.TriggerIndex < PLCIConfig.WarningStartIndex + PLCIConfig.WarningLength); //if (warningSignal) //{ // if (newValue != oldValue) // { // int warningIndex = m.TriggerIndex - PLCIConfig.WarningStartIndex; // for (int i = 0; i < 16; i++) // { // var ws = PLCIConfig.WarningSetCollection.FirstOrDefault(w => w.WaringIndex == (warningIndex * 16) + i); // if (ws != null) // { // int newAlarmValue = newValue >> i & 1; // int oldAlarmValue = oldValue >> i & 1; // if (newAlarmValue != oldAlarmValue) // { // OnMonitorAlarm?.BeginInvoke(ws, newAlarmValue == 1, null, null); // //仅保存警报信息,不保存提示信息 // //if (ws.WarningLvl == 0) // //{ // // SaveAlarm(Config.StationCode, ws, newValue); // //} // } // } // } // } // return; //} #endregion PLCIConfig.MonitorSetCollection.ForEach(m => { int newValue = tempNew[m.TriggerIndex]; int oldValue = tempOld[m.TriggerIndex]; if (newValue != oldValue) { if (m.TriggerValue == -999 || newValue == m.TriggerValue) { if (m.OpConfig == null) { m.OpConfig = new OperationConfigBase(); } m.OpConfig.InputPara = m.InputDataIndex.ConvertAll(index => { return tempNew[index]; }).ToList(); OnMonitorInvoke?.BeginInvoke(DateTime.Now, m, OnMethodInvoked, m); } } }); } private void OnMethodInvoked(IAsyncResult ar) { MonitorSet monitorSet = ar.AsyncState as MonitorSet; ProcessResponse resValues = monitorSet.Response; if (resValues.ResultValue == (int)PLCReplyValue.IGNORE) { return; } if (monitorSet.ReplyDataAddress != -1 && resValues.DataList.Count > 0) { PLC_ITEM item = new PLC_ITEM(); item.OP_TYPE = 2; item.ITEM_LENGTH = resValues.DataList.Count; item.ADDRESS = monitorSet.ReplyDataAddress.ToString(); item.ITEM_VALUE = String.Join(",", resValues.DataList); this.WriteItem(item, false); } if (monitorSet.NoticeAddress != -1) { int repeatTime = 5; //LogAsync(DateTime.Now, methodCode + "开始反馈", ""); do { try { this.WriteSingleAddress(monitorSet.NoticeAddress, resValues.ResultValue, false); repeatTime = 0; } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { new ProcessException("PLC反馈写入异常", ex); } } } while (repeatTime > 0); } } #endregion } public abstract class PLCOperationConfigBase : OperationConfigBase { /// /// 需要操作的PLC项 /// public List Items { get; set; } = new List(); /// /// 是否循环操作 /// public bool IsCycle { get; set; } = false; } public class PLCDeviceConfigBase : DeviceConfigBase { } public class PLCInitialConfigBase : InitialConfigBase { [Category("监听设置")] [Description("警报配置列表")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List WarningSetCollection { get; set; } = new List(); [Category("监听设置")] [Description("监听操作配置集合")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List MonitorSetCollection { get; set; } = new List(); [Category("监听设置")] [Description("扫描间隔时间,单位:ms")] public int ScanInterval { get; set; } = 100; [Category("监听设置")] [Description("超时设置,单位:ms")] public int Timeout { get; set; } = 500; [Category("输出设置")] [Description("是否日志输出")] public bool IsEnabelLog { get; set; } = false; [Category("输出设置")] [Description("输出文件路径")] public string LogPath { get; set; } = @"D:\PLCLog.txt"; #region 地址设置 [Category("事件地址设置")] [Description("事件开始地址,PLC的实际寄存器地址。十进制,不包含功能码。")] public int EventStartAddress { get; set; } = 8000; [Category("事件地址设置")] [Description("事件地址长度,最大长度128")] public int EventLength { get; set; } = 120; [Category("事件地址设置")] [Description("警报开始索引,从0开始")] public int WarningStartIndex { get; set; } = 0; [Category("事件地址设置")] [Description("警报地址长度")] public int WarningLength { get; set; } = 8; #endregion } public class PLCInputConfigBase : InputConfigBase { } }