using FSM5000FSIAPI.Version3; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace FAtoPA.Net { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { private DispatcherTimer timer1s; private Config config; private Database database; private FSM fsm; private ModbusSlave modbusSlave; private VX3K vx3k; // untuk values di Combobox FSM SIID public ObservableCollection FSMSIID { get; set; } // untuk values di Combobox VX3K ID dan CIN public ObservableCollection VX3KID { get; set; } public ObservableCollection VX3KCIN { get; set; } // untuk values di Combobox Modbus Registers public ObservableCollection ModbusRegisters { get; set; } // Untuk manual add SIID to FSM Table public ObservableCollection NetGroupList { get; set; } public ObservableCollection NetNodeList { get; set; } public ObservableCollection PNAList { get; set; } public ObservableCollection SINumberList { get; set; } public ObservableCollection SISubList { get; set; } // Isi FSM Table ObservableCollection FsmTableMember { get; set; } // Isi Modbus Table ObservableCollection ModbusTableMember { get; set; } // Isi VX Table ObservableCollection VXTableMember { get; set; } public List ConditionON; public List ConditionOFF; FSMEvent fsmEvent; public MainWindow() { InitializeComponent(); // Di-isi dengan user input di Tab Fire Alarm FSMSIID = new ObservableCollection(); // Isinya ada di Window_Loaded ModbusRegisters = new ObservableCollection(); FsmTableMember = new ObservableCollection(); ModbusTableMember = new ObservableCollection(); VXTableMember = new ObservableCollection(); // Set default value for VX3KID and VX3KCIN VX3KID = new ObservableCollection(); for (int i = 0; i < 40; i++) { VX3KID.Add(i); } VX3KCIN = new ObservableCollection(); for (int i = 0; i < 16; i++) { VX3KCIN.Add(i); } NetGroupList = new ObservableCollection(); NetNodeList = new ObservableCollection(); PNAList = new ObservableCollection(); SINumberList = new ObservableCollection(); SISubList = new ObservableCollection(); for (int ii = 1; ii < 256; ii++) { NetGroupList.Add(ii); NetNodeList.Add(ii); PNAList.Add(ii); SINumberList.Add(ii); SISubList.Add(ii); } siType.ItemsSource = Enum.GetValues(typeof(SIType)).Cast().ToList(); this.DataContext = this; //TODO : Add Condition for ON and OFF ConditionON = new List(); ConditionON.Add(SILogicalState.ACTIVATION.ToString()); ConditionON.Add(SILogicalState.FIRE.ToString()); ConditionOFF = new List(); ConditionOFF.Add(SILogicalState.NORMAL.ToString()); } private void Window_Loaded(object sender, RoutedEventArgs e) { Debug.WriteLine("Window Loaded"); // Timer untuk update datetimebar tiap 1 detik timer1s = new DispatcherTimer(); timer1s.Interval = new TimeSpan(0, 0, 1); timer1s.Tick += Timer1s_Tick; timer1s.Start(); // Load Config config = new Config(); config.Load(); FSMConfig_NetGroup.Text = config.FSM_NetGroup.ToString(); FSMConfig_NetNode.Text = config.FSM_NetNode.ToString(); FSMConfig_PNA.Text = config.FSM_PNA.ToString(); FSMConfig_LocalIP.Text = config.FSM_LocalIP; FSM_UseMulticast.IsChecked = config.FSM_UseMulticast; FSMConfig_MulticastAddress.Text = config.FSM_MulticastIP; FSMConfig_MulticastPort.Text = config.FSM_MulticastPort.ToString(); Debug.WriteLine("NetGroup : " + config.FSM_NetGroup); Debug.WriteLine("NetNode : " + config.FSM_NetNode); Debug.WriteLine("PNA : " + config.FSM_PNA); Debug.WriteLine("LocalIP : " + config.FSM_LocalIP); Debug.WriteLine("UseMulticast : " + config.FSM_UseMulticast); Debug.WriteLine("MulticastIP : " + config.FSM_MulticastIP); Debug.WriteLine("MulticastPort : " + config.FSM_MulticastPort); ModbusListenPort.Text = config.Modbus_ListenPort.ToString(); ModbusDeviceID.Text = config.Modbus_DeviceID.ToString(); ModbusMaxRegister.Text = config.Modbus_MaxRegister.ToString(); VX3K_IP.Text = config.VX_TargetIP; VX3K_Port.Text = config.VX_TargetPort.ToString(); // Load Database database = new Database(); database.GetFSMDatas().ForEach(f => { FsmTableMember.Add(f); FSMSIID.Add(f.SIID); }); database.GetModbusDatas().ForEach(m => ModbusTableMember.Add(m)); database.GetVXDatas().ForEach(v => VXTableMember.Add(v)); FSMTable.ItemsSource = FsmTableMember; ModbusTable.ItemsSource = ModbusTableMember; VXTable.ItemsSource = VXTableMember; // Load FSM fsmEvent = new FSMEvent(this.firealarmstatusbar); fsm = new FSM(fsmEvent, config.FSM_NetGroup, config.FSM_NetNode, config.FSM_PNA, IPAddress.Parse(config.FSM_LocalIP).GetAddressBytes()); if (config.FSM_UseMulticast) { fsm.MulticastConfig(config.FSM_UseMulticast, IPAddress.Parse(config.FSM_MulticastIP).GetAddressBytes(), config.FSM_MulticastPort); } ModbusRegisters.Clear(); for (int i = 0; i < config.Modbus_MaxRegister; i++) { ModbusRegisters.Add(i); } Debug.WriteLine($"Creating ModbusRegisters untuk Combobox, length={ModbusRegisters.Count}"); // Load Modbus Slave modbusSlave = new ModbusSlave(new ModbusEvent(modbusstatusbar, ConnectedModbusClients, ConnectedModbusCount), config.Modbus_MaxRegister); modbusSlave.ID = config.Modbus_DeviceID; //modbusSlave.Start(config.Modbus_ListenPort); // Connect with VX3000 vx3k = new VX3K(new VX3KEvent(this.vxstatusbar)); //vx3k.Connect(config.VX_TargetIP, config.VX_TargetPort); fsm.AddListener(new FSMTableUpdater(FsmTableMember, DetectedSIID, DetectedSIIDCount)); fsm.AddListener(new ModbusTriggerFromFSM(FsmTableMember, ModbusTableMember, modbusSlave, ConditionON, ConditionOFF)); fsm.AddListener(new VXTriggerFromFSM(FsmTableMember, VXTableMember, vx3k, ConditionON, ConditionOFF)); } private void Timer1s_Tick(object sender, EventArgs e) { datetimebar.Text = DateTime.Now.ToString(); } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { Debug.WriteLine("Window Closing"); timer1s.Stop(); fsm.Stop(); modbusSlave.Stop(); vx3k.Disconnect(); } private void btnStartStopFSM_Click(object sender, RoutedEventArgs e) { if (FSM.Started) { fsm.Stop(); btnStartStopFSM.Content = "Start FSM Connection"; FSM.Started = false; } else { fsm.Start(); btnStartStopFSM.Content = "Stop FSM Connection"; FSM.Started = true; } } private void btnStartStopModbus_Click(object sender, RoutedEventArgs e) { if (ModbusSlave.Started) { modbusSlave.Stop(); btnStartStopModbus.Content = "Start Modbus Connection"; ModbusSlave.Started = false; } else { if (config != null) { modbusSlave.Start(config.Modbus_ListenPort); btnStartStopModbus.Content = "Stop Modbus Connection"; ModbusSlave.Started = true; } } } private void btnStartStopVX_Click(object sender, RoutedEventArgs e) { if (VX3K.Started) { vx3k.Disconnect(); btnStartStopVX.Content = "Start VX Connection"; VX3K.Started = false; } else { if (config != null) { vx3k.Connect(config.VX_TargetIP, config.VX_TargetPort); btnStartStopVX.Content = "Stop VX Connection"; VX3K.Started = true; } } } private void ApplyFSMConfig(object sender, RoutedEventArgs e) { if (config != null) { Boolean changed = false; int netgroup = 0; if (int.TryParse(FSMConfig_NetGroup.Text, out netgroup)) { if (NetGroupList.Contains(netgroup)) { if (netgroup != config.FSM_NetGroup) { config.FSM_NetGroup = (byte)netgroup; changed = true; } } else { MessageBox.Show("Invalid Net Group"); return; } } else { MessageBox.Show("Invalid Net Group"); return; } int netnode = 0; if (int.TryParse(FSMConfig_NetNode.Text, out netnode)) { if (NetNodeList.Contains(netnode)) { if (netnode != config.FSM_NetNode) { config.FSM_NetNode = (byte)netnode; changed = true; } } else { MessageBox.Show("Invalid Net Node"); return; } } else { MessageBox.Show("Invalid Net Node"); return; } int pna = 0; if (int.TryParse(FSMConfig_PNA.Text, out pna)) { if (PNAList.Contains(pna)) { if (pna != config.FSM_PNA) { config.FSM_PNA = (byte)pna; changed = true; } } else { MessageBox.Show("Invalid PNA"); return; } } else { MessageBox.Show("Invalid PNA"); return; } if (TextIsIPAddress(FSMConfig_LocalIP.Text)) { if (FSMConfig_LocalIP.Text != config.FSM_LocalIP) { config.FSM_LocalIP = FSMConfig_LocalIP.Text; changed = true; } } else { MessageBox.Show("Invalid Local IP"); return; } if (FSM_UseMulticast.IsChecked != null) { if (FSM_UseMulticast.IsChecked != config.FSM_UseMulticast) { config.FSM_UseMulticast = (bool)FSM_UseMulticast.IsChecked; changed = true; } } else { MessageBox.Show("Invalid Multicast Use"); return; } if (TextIsIPAddress(FSMConfig_MulticastAddress.Text)) { if (FSMConfig_MulticastAddress.Text != config.FSM_MulticastIP) { config.FSM_MulticastIP = FSMConfig_MulticastAddress.Text; changed = true; } } else { MessageBox.Show("Invalid Multicast Address"); return; } int multicastport = 0; if (int.TryParse(FSMConfig_MulticastPort.Text, out multicastport)) { if (multicastport >= 0 && multicastport <= 65535) { if (multicastport != config.FSM_MulticastPort) { config.FSM_MulticastPort = (ushort)multicastport; changed = true; } } else { MessageBox.Show("Invalid Multicast Port"); return; } } else { MessageBox.Show("Invalid Multicast Port"); return; } if (changed) { if (config.Save()) { MessageBox.Show("FSM Config Saved"); //TODO : Restart FSM Connection } else MessageBox.Show("FSM Config Save Failed"); } else MessageBox.Show("No changes in FSM Config"); } else MessageBox.Show("Config is null"); } private void ApplyModbusConfig(object sender, RoutedEventArgs e) { if (config != null) { Boolean changed = false; int listenport = 0; if (int.TryParse(ModbusListenPort.Text, out listenport)) { if (listenport >= 0 && listenport <= 65535) { if (listenport != config.Modbus_ListenPort) { config.Modbus_ListenPort = (ushort)listenport; changed = true; } } else { MessageBox.Show("Invalid Listen Port"); return; } } else { MessageBox.Show("Invalid Listen Port"); return; } int devid = 0; if (int.TryParse(ModbusDeviceID.Text, out devid)) { if (devid >= 1 && devid <= 247) { if (devid != config.Modbus_DeviceID) { config.Modbus_DeviceID = (byte)devid; changed = true; } } else { MessageBox.Show("Invalid Device ID"); return; } } else { MessageBox.Show("Invalid Device ID"); return; } int maxreg = 0; if (int.TryParse(ModbusMaxRegister.Text, out maxreg)) { if (maxreg >= 1 && maxreg <= 10000) { if (maxreg != config.Modbus_MaxRegister) { config.Modbus_MaxRegister = (ushort)maxreg; changed = true; } } else { MessageBox.Show("Invalid Max Register"); return; } } else { MessageBox.Show("Invalid Max Register"); } if (changed) { if (config.Save()) { MessageBox.Show("Modbus Config Saved"); //TODO : Restart Modbus Connection } else MessageBox.Show("Modbus Config Save Failed"); } else MessageBox.Show("No changes in Modbus Config"); } else MessageBox.Show("Config is null"); } private void ApplyVX3KConfig(object sender, RoutedEventArgs e) { if (config != null) { Boolean changed = false; String ipaddress = ""; int port = 0; try { IPAddress ip = IPAddress.Parse(VX3K_IP.Text); ipaddress = ip.ToString(); if (ipaddress != config.VX_TargetIP) { config.VX_TargetIP = ipaddress; changed = true; } } catch (Exception) { MessageBox.Show("Invalid IP Address"); return; } if (int.TryParse(VX3K_Port.Text, out port)) { if (port != config.VX_TargetPort) { config.VX_TargetPort = (ushort)port; changed = true; } } else { MessageBox.Show("Invalid Port"); return; } if (changed) { if (config.Save()) { MessageBox.Show("VX3K Config Saved"); //TODO : Restart VX3K Connection } else MessageBox.Show("VX3K Config Save Failed"); } else MessageBox.Show("No changes in VX3K Config"); } else MessageBox.Show("Config is null"); } // Regex Protection for FSMConfig_NetGroup private void FSMConfig_NetGroup_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } // Regex Protection for FSMConfig_NetNode private void FSMConfig_NetNode_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } // Regex Protection for FSMConfig_PNA private void FSMConfig_PNA_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } // Regex Protection for FSMConfig_LocalIP private void FSMConfig_LocalIP_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxIPAddressOnly(e); } // Regex Protection for FSMConfig_MulticastAddress private void FSMConfig_MulticastAddress_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxIPAddressOnly(e); } // Regex Protection for FSMConfig_MulticastPort private void FSMConfig_MulticastPort_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } // If NetGroup value is changed, check for valid value. If not valid, change background to red private void FSMConfig_NetGroup_TextChanged(object sender, TextChangedEventArgs e) { TextBox_FSMVerify(FSMConfig_NetGroup); } // If NetNode value is changed, check for valid value. If not valid, change background to red private void FSMConfig_NetNode_TextChanged(object sender, TextChangedEventArgs e) { TextBox_FSMVerify(FSMConfig_NetNode); } // If PNA value is changed, check for valid value. If not valid, change background to red private void FSMConfig_PNA_TextChanged(object sender, TextChangedEventArgs e) { TextBox_FSMVerify(FSMConfig_PNA); } // If LocalIP value is changed, check for valid value. If not valid, change background to red private void FSMConfig_LocalIP_TextChanged(object sender, TextChangedEventArgs e) { TextBox_IPVerify(FSMConfig_LocalIP); } // If MulticastAddress value is changed, check for valid value. If not valid, change background to red private void FSMConfig_MulticastAddress_TextChanged(object sender, TextChangedEventArgs e) { TextBox_IPVerify(FSMConfig_MulticastAddress); } // If MulticastPort value is changed, check for valid value. If not valid, change background to red private void FSMConfig_MulticastPort_TextChanged(object sender, TextChangedEventArgs e) { TextBox_PortVerify(FSMConfig_MulticastPort); } // Only allow number input private void TextBoxNumberOnly(TextCompositionEventArgs e) { Regex regex = new Regex("[^0-9]+"); e.Handled = regex.IsMatch(e.Text); } private void TextBoxIPAddressOnly(TextCompositionEventArgs e) { //string pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"; //Regex regex = new Regex(pattern); //e.Handled = regex.IsMatch(e.Text); e.Handled = TextIsIPAddress(e.Text); } private Boolean TextIsIPAddress(String vv) { if (vv != null) { if (vv.Length > 0) { string pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"; Regex regex = new Regex(pattern); return regex.IsMatch(vv); } } return false; } // Verify Textbox value for FSM, which mostly only accept number 1 - 255 private void TextBox_FSMVerify(TextBox e) { if (int.TryParse(e.Text, out int result)) { if (result < 0 || result > 255) { e.Background = Brushes.Red; } else { e.Background = Brushes.Transparent; } } else { e.Background = Brushes.Red; } } private void TextBox_IPVerify(TextBox e) { try { IPAddress.Parse(e.Text); e.Background = Brushes.Transparent; } catch (Exception) { e.Background = Brushes.Red; } } private void TextBox_PortVerify(TextBox e) { if (int.TryParse(e.Text, out int result)) { if (result < 0 || result > 65535) { e.Background = Brushes.Red; } else { e.Background = Brushes.Transparent; } } else { e.Background = Brushes.Red; } } private void VX3K_IP_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxIPAddressOnly(e); } private void VX3K_Port_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } private void ModbusListenPort_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } private void ModbusDeviceID_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } private void ModbusMaxRegister_PreviewTextInput(object sender, TextCompositionEventArgs e) { TextBoxNumberOnly(e); } private void ModbusListenPort_TextChanged(object sender, TextChangedEventArgs e) { TextBox_PortVerify(ModbusListenPort); } private void VX3K_Port_TextChanged(object sender, TextChangedEventArgs e) { TextBox_PortVerify(VX3K_Port); } private void VX3K_IP_TextChanged(object sender, TextChangedEventArgs e) { TextBox_IPVerify(VX3K_IP); } private void ModbusDeviceID_TextChanged(object sender, TextChangedEventArgs e) { int devid = 0; if (int.TryParse(ModbusDeviceID.Text, out devid)) { if (devid >= 1 && devid <= 247) { ModbusDeviceID.Background = Brushes.Transparent; } else { ModbusDeviceID.Background = Brushes.Red; } } else { ModbusDeviceID.Background = Brushes.Red; } } private void ModbusMaxRegister_TextChanged(object sender, TextChangedEventArgs e) { int maxreg = 0; if (int.TryParse(ModbusMaxRegister.Text, out maxreg)) { if (maxreg >= 1 && maxreg <= 10000) { ModbusMaxRegister.Background = Brushes.Transparent; } else { ModbusMaxRegister.Background = Brushes.Red; } } else { ModbusMaxRegister.Background = Brushes.Red; } } private void btnAddSIID_Click(object sender, RoutedEventArgs e) { SIID selected = GetSIID(); if (selected != null) { MessageBoxResult result = MessageBox.Show("Add SIID " + selected.ToString() + " ?", "Add SIID", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { if (database != null) { //TODO Manual Add SIID, perlukah ? //FSMData f = new FSMData(selected.ToString()); //if (database.AddFSMData(f)) //{ // FSMTable.ItemsSource = database.GetFSMDatas(); // FSMSIID.Add(selected.ToString()); //} //else MessageBox.Show("Failed to add to database"); } else MessageBox.Show("Database is null"); } } else MessageBox.Show("Invalid Selection"); } private void btnDelSIID_Click(object sender, RoutedEventArgs e) { if (FSMTable != null) { var selected = FSMTable.SelectedItem as FSMData; if (selected != null) { MessageBoxResult result = MessageBox.Show($"Are you sure want to delete SIID={selected.SIID}, Label={selected.Label}, Type={selected.Type} ?", "Delete SIID", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { FsmTableMember.Remove(selected); database.RemoveFSMDatabySIID(selected.SIID); FSMSIID.Remove(selected.SIID); } } else MessageBox.Show("Select a row in table to delete"); } } private void btnClearSIID_Click(object sender, RoutedEventArgs e) { MessageBoxResult result = MessageBox.Show("Clear all SIID ?", "Clear SIID", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { FsmTableMember.Clear(); database.ClearFSMTable(); FSMSIID.Clear(); } } private SIID GetSIID() { int netgroup = 0; int netnode = 0; SIType sitype = 0; int sinumber = 0; int sisub = 0; if (netGroupNumber.SelectedItem != null) { netgroup = (int)netGroupNumber.SelectedItem; if (netNodeNumber.SelectedItem != null) { netnode = (int)netNodeNumber.SelectedItem; if (siType.SelectedItem != null) { sitype = (SIType)siType.SelectedItem; if (siNumber.SelectedItem != null) { sinumber = (int)siNumber.SelectedItem; if (siSub.SelectedItem != null) { sisub = (int)siSub.SelectedItem; return new SIID((byte)netgroup, (byte)netnode, sitype, (ushort)sinumber, (byte)sisub); } } } } } return null; } private void btnAddModbus_Click(object sender, RoutedEventArgs e) { String ssid = ""; int reg = 0; if (ModbusSIIDComboBox.SelectedItem != null) { ssid = (string)ModbusSIIDComboBox.SelectedItem; } else { MessageBox.Show("Invalid SIID"); return; } if (ModbusRegister.SelectedItem != null) { reg = (int)ModbusRegister.SelectedItem; } else { MessageBox.Show("Invalid Register"); return; } MessageBoxResult result = MessageBox.Show("Add SIID " + ssid + " Link with Register " + reg + " ?", "Add Modbus Linkage", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { if (database != null) { ModbusData m = new ModbusData(ssid, (ushort)reg); if (database.AddModbusData(m)) { ModbusTable.ItemsSource = database.GetModbusDatas(); } else MessageBox.Show("Failed to add to database"); } else MessageBox.Show("Database is null"); } } private void btnDelModbus_Click(object sender, RoutedEventArgs e) { if (ModbusTable != null) { var selected = ModbusTable.SelectedItem as ModbusData; if (selected != null) { MessageBoxResult xx = MessageBox.Show($"Are you sure want to delete SIID={selected.SIID}, Register={selected.Register} ?", "Delete SIID", MessageBoxButton.YesNo); if (xx == MessageBoxResult.Yes) { database.RemoveModbusDatabySIID(selected.SIID); ModbusTableMember.Remove(selected); } } else MessageBox.Show("Select a row in Table to delete"); } } private void btnClearModbus_Click(object sender, RoutedEventArgs e) { MessageBoxResult result = MessageBox.Show("Clear all Modbus Linkage ?", "Clear Modbus Linkage", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { database.ClearModbusTable(); ModbusTableMember.Clear(); } } private void btnAddVX_Click(object sender, RoutedEventArgs e) { String ssid = ""; int id = 0; int cin = 0; if (VXSIIDComboBox.SelectedItem != null) { ssid = (string)VXSIIDComboBox.SelectedItem; } else { MessageBox.Show("Invalid SIID"); return; } if (VXFrame.SelectedItem != null) { id = (int)VXFrame.SelectedItem; } else { MessageBox.Show("Invalid ID"); return; } if (VXCIN.SelectedItem != null) { cin = (int)VXCIN.SelectedItem; } else { MessageBox.Show("Invalid CIN"); return; } MessageBoxResult result = MessageBox.Show("Add SIID " + ssid + " Link with Frame " + id + " CIN " + cin + " ?", "Add VX Linkage", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { if (database != null) { VXData v = new VXData(ssid, (byte)id, (byte)cin); if (database.AddVXData(v)) { VXTable.ItemsSource = database.GetVXDatas(); } else MessageBox.Show("Failed to add to database"); } else MessageBox.Show("Database is null"); } } private void btnDelVX_Click(object sender, RoutedEventArgs e) { if (VXTable != null) { var selected = VXTable.SelectedItem as VXData; if (selected != null) { var result = MessageBox.Show($"Delete SIID={selected.SIID}, ID={selected.FrameID}, CIN={selected.CIN} ?", "Delete SIID", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { database.RemoveVXDatabySIID(selected.SIID); VXTableMember.Remove(selected); } } else MessageBox.Show("Select a row in Table to delete"); } } private void btnClearVX_Click(object sender, RoutedEventArgs e) { MessageBoxResult result = MessageBox.Show("Clear all VX Linkage ?", "Clear VX Linkage", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { database.ClearVXTable(); VXTableMember.Clear(); } } private void FSMTable_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { Debug.WriteLine("FSMTable_AutoGeneratingColumn : " + e.PropertyName); switch (e.PropertyName) { case "SIID": e.Column.Width = DataGridLength.Auto; break; case "Enable": e.Column.Width = DataGridLength.Auto; break; case "Description": e.Column.Width = DataGridLength.Auto; break; case "Value": e.Column.Width = DataGridLength.Auto; break; case "LastUpdate": e.Column.Width = DataGridLength.Auto; break; } } private void ModbusTable_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { Debug.WriteLine("ModbusTable_AutoGeneratingColumn : " + e.PropertyName); switch (e.PropertyName) { case "SIID": e.Column.Width = DataGridLength.Auto; break; case "Register": e.Column.Width = DataGridLength.Auto; break; case "Description": e.Column.Width = DataGridLength.Auto; break; case "Value": e.Column.Width = DataGridLength.Auto; break; case "LastUpdate": e.Column.Width = DataGridLength.Auto; break; } } private void VXTable_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { Debug.WriteLine("VXTable_AutoGeneratingColumn : " + e.PropertyName); switch (e.PropertyName) { case "SIID": e.Column.Width = DataGridLength.Auto; break; case "ID": e.Column.Width = DataGridLength.Auto; break; case "CIN": e.Column.Width = DataGridLength.Auto; break; case "Description": e.Column.Width = DataGridLength.Auto; break; case "Value": e.Column.Width = DataGridLength.Auto; break; case "LastUpdate": e.Column.Width = DataGridLength.Auto; break; } } private void AddSelectedSIID(object sender, RoutedEventArgs e) { var lbl = DetectedSIID.SelectedItem; if (lbl != null && lbl is Label) { Label selected = (Label)lbl; if (selected.Tag is NodeData) { NodeData data = (NodeData)selected.Tag; FSMData fSMData = new FSMData(data.SIID.ToString(), true, data.Label, data.Description); if (database.FSMDataHaveSIID(fSMData.SIID)!=null) { Debug.WriteLine($"database already have SIID={fSMData.SIID}"); } else { if (database.AddFSMData(fSMData)) { FsmTableMember.Add(fSMData); FSMSIID.Add(fSMData.SIID); Debug.WriteLine($"Added SIID={fSMData.SIID}, Label={fSMData.Label}, Type= {fSMData.Type} to database"); } else MessageBox.Show($"Failed to add SIID={fSMData.SIID}, Label={fSMData.Label}, Type={fSMData.Type} to database"); } } else MessageBox.Show("Selected SIID dont have NodeData"); } else MessageBox.Show("No SIID Selected"); } } // event handler for VX3K class VX3KEvent : EventInterface { private TextBlock statusbar; public VX3KEvent(TextBlock statusbar) { this.statusbar = statusbar; } public void ConnectStatus(bool success, string message) { Debug.WriteLine("VX-3000 ConnectStatus: " + success + " " + message); if (statusbar != null) statusbar.Background = success ? Brushes.Green : Brushes.Transparent; } public void StatisticUpdate(uint TXOK, uint RXOK, uint TXErr, uint RXerr, uint TXBytes, uint RXBytes) { if (statusbar != null) statusbar.Text = "VX-3000 : TXOK: " + TXOK + " RXOK: " + RXOK + " TXErr: " + TXErr + " RXErr: " + RXerr + " TXBytes: " + TXBytes + " RXBytes: " + RXBytes; } public void Log(string msg) { Debug.WriteLine("VX-3000 Log: " + msg); } } class ModbusEvent : ModbusSlaveEvent { private TextBlock statusbar; private ListBox connectedlist; private Label connectedcount; private ObservableCollection ModbusSlave; public ModbusEvent(TextBlock statusbar, ListBox connectedlist, Label connectedcount) { this.statusbar = statusbar; this.connectedlist = connectedlist; this.connectedcount = connectedcount; ModbusSlave = new ObservableCollection(); ModbusSlave.CollectionChanged += (sender, e) => refresh_connectedlist(); } private void refresh_connectedlist() { Application.Current.Dispatcher.Invoke(() => { connectedlist.Items.Clear(); foreach (ModbusClientRecord client in ModbusSlave) { TextBlock l = new TextBlock(); l.Width = connectedlist.Width; l.Margin = new Thickness(5, 0, 5, 0); l.TextWrapping = TextWrapping.Wrap; UpdateLabel(l, client); l.Tag = client; connectedlist.Items.Add(l); } if (connectedcount != null) connectedcount.Content = "Connected : " + connectedlist.Items.Count; }); } void ModbusSlaveEvent.Log(string msg) { Debug.WriteLine("Modbus Log: " + msg); } void ModbusSlaveEvent.NewConnection(ModbusClientRecord client) { ModbusSlave.Add(client); } void ModbusSlaveEvent.CloseConnection(ModbusClientRecord client) { ModbusSlave.Remove(client); } void ModbusSlaveEvent.ConnectStatus(bool success, string message) { Debug.WriteLine("Modbus ConnectStatus: " + success + " " + message); if (statusbar != null) statusbar.Background = success ? Brushes.Green : Brushes.Transparent; } public void TXRXStatusUpdate(ModbusClientRecord client) { connectedlist.Dispatcher.Invoke(() => { foreach (var item in connectedlist.Items) { TextBlock l = (TextBlock)item; if (l.Tag == client) { UpdateLabel(l, client); return; } } }); } private void UpdateLabel(TextBlock l, ModbusClientRecord client) { l.Text = client.remoteEP + "/TX: " + client.TXBytes + "/RX: " + client.RXBytes + "/TXOK: " + client.TXResponse + "/RXOK: " + client.RXValidRequest+"/RXFAIL: "+client.RXInvalidRequest; } } class FSMEvent : EventInterface { private TextBlock statusbar; public FSMEvent(TextBlock statusbar) { this.statusbar = statusbar; } public void ConnectStatus(bool success, string message) { if (statusbar != null) { statusbar.Dispatcher.Invoke(() => { statusbar.Background = success ? Brushes.Green : Brushes.Transparent; statusbar.Text = "FSM : " + message; }); } Debug.WriteLine("FSM ConnectStatus: " + success + " " + message); } public void Log(string msg) { Debug.WriteLine("FSM Log: " + msg); } public void StatisticUpdate(uint TXOK, uint RXOK, uint TXErr, uint RXerr, uint TXBytes, uint RXBytes) { //if (statusbar != null) //{ // statusbar.Dispatcher.Invoke(() => // { // statusbar.Text = "FSM : TXOK: " + TXOK + " RXOK: " + RXOK + " TXErr: " + TXErr + " RXErr: " + RXerr + " TXBytes: " + TXBytes + " RXBytes: " + RXBytes; // }); //} } } // Class ini untuk update Table FSM class FSMTableUpdater : FSMResultInterface { // dari database ObservableCollection data; ListBox listbox; Label countlabel; public FSMTableUpdater(ObservableCollection data, ListBox listbox, Label countlabel) { this.data = data; this.listbox = listbox; this.countlabel = countlabel; } public void DiscoveredSIID(string SIID, NodeData type) { Debug.WriteLine($"Discovered SIID={SIID} Label={type.Label} Type={type.Description}"); if (type.Label != null && type.Label.Length > 0) { if (type.Description != null && type.Description.Length > 0) { // yang punya Label dan Description saja yang masuk ke Listbox dan dihitung Application.Current.Dispatcher.Invoke(() => { listbox.Items.Add(new Label() { Content = $"{SIID} : {type.Label} : {type.Description}", Tag = type }); countlabel.Content = "Count : " + listbox.Items.Count; }); } } } public void NewState(string SIID, NodeState previous, NodeState current) { Debug.WriteLine("New State : " + SIID + " Previous : " + previous?.LogicalState + " Current : " + current.LogicalState); if (data != null) { // update yang ada di FsmTable saja foreach (var dd in data) { if (dd.SIID.Equals(SIID)) { dd.LastUpdate = DateTime.Now.ToString(); dd.Value = current.LogicalState ?? "Unknown"; Debug.WriteLine($"Changing row in FSM Table for SIID={SIID} Value={dd.Value}"); return; } } } Debug.WriteLine($"FSM Table dont have row with SIID={SIID}"); } } // Class ini untuk Update Modbus Register dari FSM Update class ModbusTriggerFromFSM : FSMResultInterface { // dari database ObservableCollection source; ObservableCollection data; ModbusSlave slave; List ConditionON; List ConditionOFF; public ModbusTriggerFromFSM(ObservableCollection source, ObservableCollection data, ModbusSlave slave, List conditionON, List conditionOFF) { this.source = source; this.data = data; this.slave = slave; ConditionON = conditionON; ConditionOFF = conditionOFF; } public void DiscoveredSIID(string SIID, NodeData type) { } public void NewState(string SIID, NodeState previous, NodeState current) { FSMData src = null; ModbusData dt = null; foreach(var x in source) { if (x.SIID.Equals(SIID)) { src = x; break; } } foreach (var x in data) { if (x.SIID.Equals(SIID)) { dt = x; break; } } if (src != null && dt != null) { if (src.Enable) { if (dt.Register >= 0) { if (slave != null) { if (ConditionON != null && ConditionOFF != null) { if (ConditionON.Contains(current.LogicalState)) { Debug.WriteLine($"NewState for SIID={SIID} State={current.LogicalState} is ConditionON"); slave.SetRegister(dt.Register, 1); dt.Value = "ON"; } else if (ConditionOFF.Contains(current.LogicalState)) { Debug.WriteLine($"NewState for SIID={SIID} State={current.LogicalState} is ConditionOFF"); slave.SetRegister(dt.Register, 0); dt.Value = "OFF"; } else { Debug.WriteLine($"NewState for SIID={SIID} in Modbus is ignored because Condition ON/OFF is not met"); dt.Value = "RULE NOT AVAILABLE"; } } else { Debug.WriteLine($"Condition ON/OFF for SIID={SIID} in Modbus is not set"); dt.Value = "RULE NOT SET"; } } else { Debug.WriteLine($"Not connected to Modbus Slave, NewState for SIID={SIID} in Modbus is ignored"); dt.Value = "NO MODBUS"; } dt.LastUpdate = DateTime.Now.ToString(); } else Debug.WriteLine($"NewState for SIID={SIID} in Modbus is ignored because Register is not set"); } else Debug.WriteLine($"NewState for SIID={SIID} in Modbus is ignored because FSMData is Disabled"); } else Debug.WriteLine($"NewState for SIID={SIID} in Modbus is ignored because not registered in ModbusTable"); } } // Class ini untuk Trigger VX3K dari FSM Update class VXTriggerFromFSM : FSMResultInterface { ObservableCollection data; ObservableCollection source; VX3K vx; List ConditionON; List ConditionOFF; public VXTriggerFromFSM(ObservableCollection source, ObservableCollection data, VX3K vx, List conditionON, List conditionOFF) { this.source = source; this.data = data; this.vx = vx; ConditionON = conditionON; ConditionOFF = conditionOFF; } public void DiscoveredSIID(string SIID, NodeData type) { } public void NewState(string SIID, NodeState previous, NodeState current) { FSMData src = null; VXData dt = null; foreach (var x in source) { if (x.SIID.Equals(SIID)) { src = x; break; } } foreach (var x in data) { if (x.SIID.Equals(SIID)) { dt = x; break; } } if (src != null && dt != null) { if (src.Enable) { if (vx != null && vx.IsConnected()) { if (ConditionON != null && ConditionOFF != null) { if (ConditionON.Contains(current.LogicalState)) { Debug.WriteLine($"NewState for SIID={SIID} State={current.LogicalState} is ConditionON"); vx.Virtual_Contact_Input(dt.FrameID, dt.CIN, true); dt.Value = "ON"; } else if (ConditionOFF.Contains(current.LogicalState)) { Debug.WriteLine($"NewState for SIID={SIID} State={current.LogicalState} is ConditionOFF"); vx.Virtual_Contact_Input(dt.FrameID, dt.CIN, false); dt.Value = "OFF"; } else { Debug.WriteLine($"NewState for SIID={SIID} in VX3K is ignored because Condition ON/OFF is not met"); dt.Value = "RULE NOT AVAILABLE"; } } else { Debug.WriteLine($"Condition ON/OFF for SIID={SIID} in VX3K is not set"); dt.Value = "RULE NOT SET"; } } else { Debug.WriteLine($"Not connected to VX3K, NewState for SIID={SIID} in VX3K is ignored"); dt.Value = "NO VX"; } dt.LastUpdate = DateTime.Now.ToString(); } else Debug.WriteLine($"NewState for SIID={SIID} in VX3K is ignored because FSMData is Disabled"); } else Debug.WriteLine($"NewState for SIID={SIID} in VX3K is ignored because not registered in VXTable"); } } }