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<PLC_ITEM> OnPLCDataChanged;
|
#endregion
|
|
#region IMonitor
|
public event OnMonitorInvokeDelegate OnMonitorInvoke;
|
public event OnMonitorAlarmDelegate OnMonitorAlarm;
|
|
protected List<int> oldValues = new List<int>();
|
|
public abstract List<int> 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<int> 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<int>(newValues);
|
var tempOld = new List<int>(oldValues);
|
MonitorCheckAndInvoke(tempNew, tempOld);
|
}
|
oldValues = new List<int>(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, $"{Name}监听异常:{ex.GetExceptionMessage()}");
|
}
|
}
|
}
|
}
|
|
protected virtual void MonitorCheckAndInvoke(List<int> tempNew, List<int> 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, this, 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
|
{
|
/// <summary>
|
/// 需要操作的PLC项
|
/// </summary>
|
public List<PLC_ITEM> Items { get; set; } = new List<PLC_ITEM>();
|
|
/// <summary>
|
/// 是否循环操作
|
/// </summary>
|
public bool IsCycle { get; set; } = false;
|
}
|
|
public class PLCDeviceConfigBase : DeviceConfigBase
|
{
|
}
|
|
public class PLCInitialConfigBase : InitialConfigBase
|
{
|
[Category("监听设置")]
|
[Description("警报配置列表")]
|
[TypeConverter(typeof(CollectionCountConvert))]
|
[Editor(typeof(ComplexCollectionEditor<WarningSet>), typeof(UITypeEditor))]
|
public List<WarningSet> WarningSetCollection { get; set; } = new List<WarningSet>();
|
|
[Category("监听设置")]
|
[Description("监听操作配置集合")]
|
[TypeConverter(typeof(CollectionCountConvert))]
|
[Editor(typeof(ComplexCollectionEditor<MonitorSet>), typeof(UITypeEditor))]
|
public List<MonitorSet> MonitorSetCollection { get; set; } = new List<MonitorSet>();
|
|
[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
|
{
|
}
|
}
|