using JinYuan.Helper;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
namespace PLC.PLCAlarm
{
///
/// PLC报警记录模块
///
public class PLCAlarmReader
{
///
/// 报警模板(从触摸屏导出的报警数据)
///
private readonly List alarmFileDataList;
///
/// 报警记录路径(实际记录下来的实时报警)
///
private readonly string alarmRecordPath;
///
/// 是否忽略报警状态下的新增报警
///
private readonly bool ignoreAlarm;
///
/// 报警记录类型
///
private readonly RecordType recordType;
///
/// 初始化一个报警读取器
///
/// 报警文件路径
///
/// 文件格式 .csv
/// 字,位,触发数值,报警代码,报警内容
/// 40000,0,1,E001,急停报警(IO:A1_I0.05)
/// 40000,1,1,E002,上下料安全门报警(IO:A1_I0.06)
///
///
/// 报警记录目录路径
/// 报警记录类型
/// 是否忽略报警状态下的新增报警
public PLCAlarmReader(string AlarmFilePath, string AlarmRecordPath, RecordType recType = RecordType.RecordWhenStart, bool ignore = false)
{
alarmFileDataList = ReadAlarmFile(AlarmFilePath);
alarmRecordPath = AlarmRecordPath;
recordType = recType;
ignoreAlarm = ignore;
RecordAlarms = new List();
}
///
/// 新增报警事件
///
public event EventHandler PLCAlarm_New;
///
/// 报警复位事件
///
public event EventHandler PLCAlarm_Remove;
///
/// 当前记录中的报警
///
public List RecordAlarms { get; }
///
/// 读取本地报警文件
///
///
private List ReadAlarmFile(string alarmFilePath)
{
List fileAlarmList = new List();
try
{
if (!File.Exists(alarmFilePath))
return null;
using (StreamReader sr = new StreamReader(alarmFilePath, Encoding.Default))
{
if (!sr.EndOfStream)
sr.ReadLine(); // 读掉第一行标题行
while (!sr.EndOfStream)
{
string[] alarmData = sr.ReadLine().Split('\t');
fileAlarmList.Add(new AlarmFileData(alarmData));
}
}
return fileAlarmList;
}
catch (Exception ex)
{
LogHelper.Instance.WriteError("读取本地报警信息配置文件出错:" + ex.Message);
return null;
}
}
///
/// 寻找报警代码
///
/// 字地址
/// 位地址
/// 值
/// 报警信息
/// 是否找到
private bool FindAlarm(int word, int bit, bool value, out AlarmFileData alarmData)
{
if (alarmFileDataList==null)
{
alarmData = null;
return false;
}
foreach (var item in alarmFileDataList)
{
if (item.Word == word &&
item.Bit == bit &&
item.AlarmTriger == value)
{
alarmData = item;
return true;
}
}
alarmData = null;
return false;
}
///
/// 获得当前报警列表
///
/// 报警字开始地址
/// 报警地址递增步进(个别情况用)
/// 比如按字读取基恩士MR地址时,字地址是40000,40100,40200这样增加的,此时就要把addrStep设成100
///
/// 报警字长度(有几个字)
/// 读到的数据
/// 返回的当前报警列表
///
private bool GenerateAlarmList(int startAddr, int length, ushort[] readDatas, out List readPLCAlrms, int addrStep = 1)
{
bool isAlarm = false;
readPLCAlrms = new List();
for (int wi = 0; wi < length; wi++)
{
ushort word = readDatas[wi];
if (word != 0)
{
isAlarm = true;
bool[] bits = PLCDataTool.WordToBits(word);
for (int bi = 0; bi < 16; bi++)
{
if (FindAlarm(startAddr + wi * addrStep, bi, bits[bi], out AlarmFileData alarmdata))
{
if (!readPLCAlrms.Exists((p) => p.AlarmCode == alarmdata.AlarmCode))
readPLCAlrms.Add(alarmdata);
}
}
}
}
return isAlarm;
}
///
/// 输入读取的数据,判断当前是否报警,保存报警记录
///
/// 报警字开始地址
/// 报警地址递增步进(个别情况用)
/// 比如按字读取基恩士MR地址时,字地址是40000,40100,40200这样增加的,此时就要把addrStep设成100
///
/// 报警字长度(有几个字)
/// 读到的数据
///
public bool IsPLCAlarm(int startAddr, int length, ushort[] readDatas, int addrStep = 1)
{
if (GenerateAlarmList(startAddr, length, readDatas, out List readPLCAlrms, addrStep))
{
// 新增
if (!ignoreAlarm || RecordAlarms.Count <= 0) //当不忽略报警状态下新增报警,或者当前是无报警状态的话,就记录
{
foreach (var alrmItem in readPLCAlrms)
{
if (RecordAlarms.Exists(p => p.AlarmCode == alrmItem.AlarmCode))
continue;
// 记录新增报警
var recordData = new RecordAlarmDataArgs()
{
AlarmCode = alrmItem.AlarmCode,
AlarmInfo = alrmItem.AlarmInfo,
AlarmDate = DateTime.Now.ToString("yyyy/MM/dd"),
StartTime = DateTime.Now
};
RecordAlarms.Add(recordData);
SaveAlarmRecordWhenStart(recordData);
OnAlarm_New(recordData);
}
}
// 复位
for (int i = RecordAlarms.Count - 1; i >= 0; i--)
{
// 遍历记录中的报警,如果有当前报警中不包含的报警项,说明报警已复位
if (!readPLCAlrms.Exists(p => p.AlarmCode == RecordAlarms[i].AlarmCode))
{
SaveAlarmRecordWhenFinish(RecordAlarms[i], DateTime.Now);
OnAlarm_Remove(RecordAlarms[i]);
RecordAlarms.RemoveAt(i);
}
}
return true;
}
else
{
// 全都复位
for (int i = RecordAlarms.Count - 1; i >= 0; i--)
{
SaveAlarmRecordWhenFinish(RecordAlarms[i], DateTime.Now);
OnAlarm_Remove(RecordAlarms[i]);
RecordAlarms.RemoveAt(i);
}
return false;
}
}
///
/// 触发新增报警事件
///
///
private void OnAlarm_New(RecordAlarmDataArgs args)
{
// 以线程安全的方式引发事件
var temp = PLCAlarm_New;
temp?.Invoke(this, args);
}
///
/// 触发报警复位事件
///
///
private void OnAlarm_Remove(RecordAlarmDataArgs args)
{
// 以线程安全的方式引发事件
var temp = PLCAlarm_Remove;
temp?.Invoke(this, args);
}
#region 保存报警记录
///
/// 当报警消除的时候记录已消除的报警
///
/// 报警数据
/// 结束时间
private void SaveAlarmRecordWhenFinish(RecordAlarmDataArgs alrmData, DateTime endTime)
{
if (recordType != RecordType.RecordWhenFinish)
return;
string start = alrmData.StartTime.ToString("HH:mm:ss");
string end = endTime.ToString("HH:mm:ss");
string totaltime = (endTime - alrmData.StartTime).TotalMinutes.ToString("f2");
if (!Directory.Exists(alarmRecordPath))
{
Directory.CreateDirectory(alarmRecordPath);
}
try
{
string filePath = Path.Combine(alarmRecordPath, DateTime.Now.ToString("yyyy-MM-dd") + ".csv");
if (!File.Exists(filePath))
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.WriteLine("报警信息,报警代码,统计日期,开始时间,结束时间,消耗时间(min)");
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start + "," + end + "," + totaltime);
}
}
else
{
using (StreamWriter sw = new StreamWriter(filePath, true))
{
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start + "," + end + "," + totaltime);
}
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex.Message);
}
}
///
/// 当报警触发的时候记录报警
///
/// 报警数据
private void SaveAlarmRecordWhenStart(RecordAlarmDataArgs alrmData)
{
if (recordType != RecordType.RecordWhenStart)
return;
string start = alrmData.StartTime.ToString("HH:mm:ss");
if (!Directory.Exists(alarmRecordPath))
{
Directory.CreateDirectory(alarmRecordPath);
}
try
{
string filePath = Path.Combine(alarmRecordPath, DateTime.Now.ToString("yyyy-MM-dd") + ".csv");
if (!File.Exists(filePath))
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.WriteLine("报警信息,报警代码,统计日期,开始时间");
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start);
}
}
else
{
using (StreamWriter sw = new StreamWriter(filePath, true))
{
sw.WriteLine(alrmData.AlarmInfo + "," + alrmData.AlarmCode + "," + alrmData.AlarmDate + "," + start);
}
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex.Message);
}
}
#endregion
}
}