| | |
| | | using System.Windows; |
| | | using System.Collections.Generic; |
| | | using System.Configuration; |
| | | using System; |
| | | using System.Windows; |
| | | using System.Windows.Controls; |
| | | using HMI.Base; |
| | | using HMI.Core.Api; |
| | | using HMI.IOMonitor.Entity; |
| | | using log4net; |
| | | using System.Linq; |
| | | using System.IO; |
| | | using HMI.Core.Util; |
| | | using System.Collections.ObjectModel; |
| | | using HMI.Core.Setting; |
| | | using HMI.UI.Util; |
| | | using System.Timers; |
| | | using System.Windows.Media; |
| | | using System.Threading.Tasks; |
| | | using System.Windows.Data; |
| | | using Microsoft.Win32; |
| | | using NPOI.SS.UserModel; |
| | | using NPOI.XSSF.UserModel; |
| | | using NPOI.HSSF.UserModel; |
| | | |
| | | namespace HMI.IOMonitor |
| | | { |
| | |
| | | /// </summary> |
| | | public partial class IOMonitor : PluginControl |
| | | { |
| | | public string SettingFilePath { get; private set; } |
| | | public string DataFilePath { get; private set; } |
| | | /// <summary> |
| | | /// DIO地址 |
| | | /// </summary> |
| | | private string DITag = string.Empty; |
| | | private string DQTag = string.Empty; |
| | | private SystemSetting systemSetting; |
| | | private Timer MonitorTimer; |
| | | private OpcInterface.OpcInterface lTSCADAApi = new OpcInterface.OpcInterface(); |
| | | |
| | | |
| | | /// <summary> |
| | | /// The diosde 反序列化的DIO对象 |
| | | /// </summary> |
| | | private List<DIO> diosde = new List<DIO>(); |
| | | /// <summary>The dis |
| | | /// DI口对象 |
| | | /// </summary> |
| | | private ObservableCollection<DIO> _dis = new ObservableCollection<DIO>() { |
| | | new DIO(null,null,null,false), |
| | | new DIO(null,null,null,true), |
| | | }; |
| | | public ObservableCollection<DIO> Dis |
| | | { |
| | | get => _dis; |
| | | set { Set(ref _dis, value); } |
| | | } |
| | | |
| | | private ObservableCollection<DIO> _dos = new ObservableCollection<DIO>() { |
| | | new DIO(null,null,null,false), |
| | | new DIO(null,null,null,true), |
| | | }; |
| | | public ObservableCollection<DIO> Dos |
| | | { |
| | | get => _dos; |
| | | set { Set(ref _dos, value); } |
| | | } |
| | | |
| | | private ObservableCollection<IPManage> iPManages = new ObservableCollection<IPManage>(); |
| | | |
| | | public ObservableCollection<IPManage> IPManages |
| | | { |
| | | get { return iPManages; } |
| | | set { Set(ref iPManages, value); } |
| | | } |
| | | |
| | | |
| | | public IOMonitor() |
| | | { |
| | | systemSetting = SystemSetting.Instance; |
| | | MonitorTimer = new Timer() |
| | | { |
| | | Interval = 100 |
| | | }; |
| | | MonitorTimer.Elapsed += MonitorTimer_Elapsed; |
| | | DataContext = this; |
| | | InitializeComponent(); |
| | | } |
| | | |
| | | private void MonitorTimer_Elapsed(object sender, ElapsedEventArgs e) |
| | | { |
| | | MonitorTimer.Enabled = false; |
| | | try |
| | | { |
| | | // stopwatch.Start(); |
| | | if (lTSCADAApi.DoFctReadSingle(DITag, out string resulti, out string errMsgi)) |
| | | { |
| | | byte[] stri = HexUtil.ToBytesFromHexString(resulti); |
| | | Array.Reverse(stri); |
| | | if (stri != null) |
| | | { |
| | | for (int i = 0; i < Dis.Count; i++) |
| | | { |
| | | Dis[i].Value = Convert.ToBoolean(GetValue(stri, "bool", Dis[i].DIO_No.ToString())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (lTSCADAApi.DoFctReadSingle(DQTag, out string resulto, out string errMsgo)) |
| | | { |
| | | byte[] stro = HexUtil.ToBytesFromHexString(resulto); |
| | | if (stro != null) |
| | | { |
| | | for (int i = 0; i < Dos.Count; i++) |
| | | { |
| | | Dos[i].Value = Convert.ToBoolean(GetValue(stro, "bool", Dos[i].DIO_No.ToString())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //stopwatch.Stop(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Warn("MonitorTimer_Elapsed Execute Failed.", ex); |
| | | MonitorTimer.Enabled = true; |
| | | return; |
| | | } |
| | | finally |
| | | { |
| | | this.MonitorTimer.Enabled = true; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 初始化方法 |
| | | /// </summary> |
| | | private void LoadData() |
| | | { |
| | | diosde.Clear(); |
| | | //Dis.Clear(); |
| | | //Dos.Clear(); |
| | | |
| | | diName.Items.Clear(); |
| | | doName.Items.Clear(); |
| | | diGroup.Items.Clear(); |
| | | doGroup.Items.Clear(); |
| | | try |
| | | { |
| | | this.diosde = XmlHelper.DeserializeFromXml<List<DIO>>(DataFilePath); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | MsgBoxHelper.Error(this, ex.Message); |
| | | } |
| | | |
| | | if (diosde.Count != 0) |
| | | { |
| | | for (int i = 0; i < diosde.Count; i++) |
| | | { |
| | | switch (diosde[i].DIOType) |
| | | { |
| | | case "I": |
| | | Dis.Add(diosde[i]); |
| | | break; |
| | | case "Q": |
| | | Dos.Add(diosde[i]); |
| | | break; |
| | | case "X": |
| | | Dis.Add(diosde[i]); |
| | | break; |
| | | case "Y": |
| | | Dos.Add(diosde[i]); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | Dis = new ObservableCollection<DIO>(Dis.OrderByDescending(t => t.DIO_No).ToList()); |
| | | Dos = new ObservableCollection<DIO>(Dos.OrderByDescending(t => t.DIO_No).ToList()); |
| | | List<string> listnew1 = new List<string>(); |
| | | foreach (var item in Dis) |
| | | { |
| | | listnew1.Add(item.Name); |
| | | } |
| | | |
| | | diName.ItemsSource = listnew1; |
| | | List<string> listnew2 = new List<string>(); |
| | | foreach (var item in Dos) |
| | | { |
| | | listnew2.Add(item.Name); |
| | | } |
| | | |
| | | doName.ItemsSource = listnew2; |
| | | List<string> listDis = new List<string>(); |
| | | int digroupmax = int.Parse(Dis[0].DIO_No.ToString().Split('.')[0]); |
| | | switch (digroupmax % 2) |
| | | { |
| | | case 1: |
| | | for (int i = 0; i < digroupmax; i++) |
| | | { |
| | | listDis.Add(i.ToString() + @".&" + (i + 1).ToString() + "."); |
| | | } |
| | | |
| | | break; |
| | | case 0: |
| | | if (digroupmax >= 0) |
| | | { |
| | | for (int i = 0; i < (digroupmax - 1); i++) |
| | | { |
| | | listDis.Add(i.ToString() + @".&" + (i + 1).ToString() + "."); |
| | | } |
| | | |
| | | listDis.Add(digroupmax.ToString() + "."); |
| | | } |
| | | |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | int dogroupmax = int.Parse(Dos[0].DIO_No.ToString().Split('.')[0]); |
| | | |
| | | diGroup.ItemsSource = listDis; |
| | | List<string> listDos = new List<string>(); |
| | | switch (dogroupmax % 2) |
| | | { |
| | | case 1: |
| | | for (int i = 0; i < dogroupmax; i++) |
| | | { |
| | | listDos.Add(i.ToString() + @".&" + (i + 1).ToString() + "."); |
| | | } |
| | | |
| | | break; |
| | | case 0: |
| | | if (dogroupmax >= 0) |
| | | { |
| | | for (int i = 0; i < (dogroupmax - 1); i++) |
| | | { |
| | | listDos.Add(i.ToString() + @".&" + (i + 1).ToString() + "."); |
| | | } |
| | | |
| | | listDos.Add(dogroupmax.ToString() + "."); |
| | | } |
| | | |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | doGroup.ItemsSource = listDos; |
| | | diCode.ItemsSource = Dis; |
| | | doCode.ItemsSource = Dos; |
| | | } |
| | | else |
| | | { |
| | | // |
| | | } |
| | | } |
| | | |
| | | private void UserControl_Loaded(object sender, RoutedEventArgs e) |
| | | { |
| | | |
| | | LoadData(); |
| | | Loaded -= UserControl_Loaded; |
| | | } |
| | | |
| | | private void Button_Click(object sender, RoutedEventArgs e) |
| | | { |
| | | Button btn = sender as Button; |
| | | switch (btn.Name) |
| | | { |
| | | case "addBtn": |
| | | OpenAddModal(); |
| | | break; |
| | | case "importBtn": |
| | | ImportFromExcel(); |
| | | break; |
| | | case "diSelect": |
| | | CollectionViewSource disFilter = this.Resources["disFilter"] as CollectionViewSource; |
| | | disFilter?.View.Refresh(); |
| | | break; |
| | | case "diReset": |
| | | ResetInput("di"); |
| | | break; |
| | | case "doSelect": |
| | | CollectionViewSource dosFilter = this.Resources["dosFilter"] as CollectionViewSource; |
| | | dosFilter?.View.Refresh(); |
| | | break; |
| | | case "doReset": |
| | | ResetInput("do"); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | private void OpenAddModal() |
| | | { |
| | | IPManageModal modal = new IPManageModal(log) |
| | | { |
| | | Title = "新增", |
| | | Owner = Window.GetWindow(this), |
| | | }; |
| | | if (modal.Open(-1, new IPManage(), IPManages, SettingFilePath) == true) |
| | | { |
| | | this.Success("新增成功"); |
| | | } |
| | | } |
| | | |
| | | private void ImportFromExcel() |
| | | { |
| | | IWorkbook workbook = null; |
| | | OpenFileDialog dialog = new OpenFileDialog(); |
| | | ////该值确定是否可以选择多个文件 |
| | | dialog.Multiselect = false; |
| | | dialog.Title = "请选择文件"; |
| | | dialog.Filter = "execl文件(*.xlsx;*.xls)|*.xlsx;*.xls"; |
| | | if (dialog.ShowDialog() == true) |
| | | { |
| | | MonitorTimer.Enabled = false; |
| | | string file = dialog.FileName; |
| | | try |
| | | { |
| | | FileStream fileStream1 = new FileStream(@file, FileMode.Open, FileAccess.Read); |
| | | if (file.IndexOf(".xlsx") >= 0) |
| | | { |
| | | workbook = new XSSFWorkbook(fileStream1); |
| | | } |
| | | else if (file.IndexOf(".xls") >= 0) |
| | | { |
| | | workbook = new HSSFWorkbook(fileStream1); |
| | | } |
| | | |
| | | ISheet sheet = workbook.GetSheetAt(0); |
| | | List<DIO> dios1 = new List<DIO>(); |
| | | IRow row; |
| | | for (int i = 1; i < (sheet.LastRowNum + 1); i++) |
| | | { |
| | | DIO[] dIO = new DIO[sheet.LastRowNum]; |
| | | row = sheet.GetRow(i); |
| | | DIO diotest = new DIO(); |
| | | if (row != null) |
| | | { |
| | | dIO[i - 1] = new DIO(); |
| | | dIO[i - 1].Name = row.GetCell(4).ToString(); |
| | | dIO[i - 1].No = row.GetCell(3).ToString(); |
| | | dIO[i - 1].Value = false; |
| | | dIO[i - 1].DIO_No = Convert.ToDecimal(dIO[i - 1].No.Substring(2)); |
| | | if (row.GetCell(3).ToString().IndexOf("I") >= 0) |
| | | { |
| | | dIO[i - 1].DIOType = "I"; |
| | | } |
| | | else if (row.GetCell(3).ToString().IndexOf("Q") >= 0) |
| | | { |
| | | dIO[i - 1].DIOType = "Q"; |
| | | } |
| | | else if (row.GetCell(3).ToString().IndexOf("X") >= 0) |
| | | { |
| | | dIO[i - 1].DIOType = "X"; |
| | | } |
| | | else if (row.GetCell(3).ToString().IndexOf("Y") >= 0) |
| | | { |
| | | dIO[i - 1].DIOType = "Y"; |
| | | } |
| | | |
| | | dios1.Add(dIO[i - 1]); |
| | | } |
| | | } |
| | | |
| | | fileStream1.Close(); |
| | | workbook.Close(); |
| | | XmlHelper.SerializeToXml(SettingFilePath, dios1); |
| | | lock (this) |
| | | { |
| | | MonitorTimer.Stop(); |
| | | LoadData(); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error("Import Failed.", ex); |
| | | MsgBoxHelper.Error(this, $"导入失败!{ex.Message}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void ResetInput(string flag) |
| | | { |
| | | if (flag == "di") |
| | | { |
| | | diName.Text = ""; |
| | | diCode.Text = ""; |
| | | diGroup.Text = ""; |
| | | CollectionViewSource source = this.Resources["disFilter"] as CollectionViewSource; |
| | | source?.View.Refresh(); |
| | | } |
| | | else |
| | | { |
| | | doName.Text = ""; |
| | | doCode.Text = ""; |
| | | doGroup.Text = ""; |
| | | CollectionViewSource source = this.Resources["dosFilter"] as CollectionViewSource; |
| | | source?.View.Refresh(); |
| | | } |
| | | } |
| | | |
| | | private string GetValue(byte[] bt, string valueType, string address) |
| | | { |
| | | string[] str = address.Split('.'); |
| | | switch (valueType.ToLower()) |
| | | { |
| | | case "bool": |
| | | return Snap7.S7.GetBitAt(bt, int.Parse(str[0]), int.Parse(str[1])).ToString(); |
| | | default: |
| | | return "false"; |
| | | } |
| | | } |
| | | |
| | | |
| | | public override void SetBaseFolder(string folder) |
| | | { |
| | | base.SetBaseFolder(folder); |
| | | this.SettingFilePath = Path.Combine(BaseFolder, "Setting.xml"); |
| | | this.DataFilePath = Path.Combine(BaseFolder, "Data.xml"); |
| | | } |
| | | |
| | | public override object Active() |
| | | { |
| | | try |
| | | { |
| | | if (File.Exists(SettingFilePath)) |
| | | { |
| | | ObservableCollection<IPManage> datas = |
| | | XmlHelper.DeserializeFromXml<ObservableCollection<IPManage>>(SettingFilePath); |
| | | IPManages = datas; |
| | | |
| | | DITag = IPManages[0].DItag; |
| | | DQTag = IPManages[0].DQtag; |
| | | } |
| | | else |
| | | { |
| | | IPManage tag = new IPManage(); |
| | | tag.DItag = ""; |
| | | tag.DQtag = ""; |
| | | IPManages.Add(tag); |
| | | XmlHelper.SerializeToXml(SettingFilePath, IPManages); |
| | | } |
| | | if (systemSetting.PlcEnabled) |
| | | { |
| | | if (!lTSCADAApi.Connect2("127.0.0.1", 6543, 18888, out string errMsg)) |
| | | { |
| | | MsgBoxHelper.Error(this, errMsg); |
| | | } |
| | | else |
| | | { |
| | | this.MonitorTimer.Start(); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | log.Error("Active Execute Failed.", ex); |
| | | MsgBoxHelper.ErrorMessage(this, $"插件激活失败!{ex.Message}"); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private void CollectionViewSource_Filter(object sender, System.Windows.Data.FilterEventArgs e) |
| | | { |
| | | DIO data = e.Item as DIO; |
| | | if (data == null) return; |
| | | |
| | | CollectionViewSource source = sender as CollectionViewSource; |
| | | DIO param = new DIO(); |
| | | if (source.Source == Dis) |
| | | { |
| | | param.Name = diName.Text; |
| | | param.No = diCode.Text; |
| | | } |
| | | else |
| | | { |
| | | param.Name = doName.Text; |
| | | param.No = doCode.Text; |
| | | } |
| | | |
| | | if (!string.IsNullOrEmpty(param.Name) && data.Name != param.Name) |
| | | { |
| | | e.Accepted = false; |
| | | return; |
| | | } |
| | | if (!string.IsNullOrEmpty(param.No) && data.No != param.No) |
| | | { |
| | | e.Accepted = false; |
| | | return; |
| | | } |
| | | e.Accepted = true; |
| | | } |
| | | } |
| | | } |