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 } }