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; if (oldValues.Count == newValues.Count) { var tempNew = new List(newValues); var tempOld = new List(oldValues); MonitorCheckAndInvoke(tempNew, tempOld); } oldValues = new List(newValues); Thread.Sleep(PLCIConfig.ScanInterval); } catch (Exception ex) { OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{ex.GetExceptionMessage()}"); } } } } protected virtual void MonitorCheckAndInvoke(List tempNew, List tempOld) { #region PLC警报信息 PLCIConfig.WarningSetCollection.ForEach(w => { if (w.WarningIndex_Word < 0 || w.WarningIndex_Word >= tempNew.Count) return; if (w.WarningIndex_Bit < 0 || w.WarningIndex_Bit > 16) return; bool isOn = ((tempNew[w.WarningIndex_Word] >> w.WarningIndex_Bit) & 1) == 1; if (w.CurrentStatus != isOn) { w.CurrentStatus = isOn; OnMonitorAlarm?.BeginInvoke(DateTime.Now, this, w, null, null); } }); #endregion PLCIConfig.MonitorSetCollection.ForEach(m => { if (m.TriggerIndex < 0 || m.TriggerIndex >= tempNew.Count) { return; } 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, this, m, OnMethodInvoked, m); } } }); } protected virtual 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反馈写入异常", ExceptionLevel.Info, ex); } } } while (repeatTime > 0); } } public virtual void ResetAlarm() { PLCIConfig.WarningSetCollection.ForEach(u => u.CurrentStatus = !u.TriggerValue); } #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 : InitialMonitorConfigBase { #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 { } }