using FSM5000FSIAPI.Version3; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Text.Json; 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; } // tabel translation FSM Status String to Modbus Register Value ObservableCollection ModbusTranslationTable; ObservableCollection FSMConditionTable; 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(); Load_ModbusTranslationTable(); Load_ConditionTable(); DataContext = this; } /// /// Load Modbus Translation Table from JSON File /// private void Load_ModbusTranslationTable() { if (File.Exists("ModbusTranslationTable.json")) { String loadedJson = File.ReadAllText("ModbusTranslationTable.json"); try { ModbusTranslationTable = JsonSerializer.Deserialize>(loadedJson); Debug.WriteLine("ModbusTranslationTable loaded"); } catch (Exception ex) { Debug.WriteLine("Error loading ModbusTranslationTable : " + ex.Message); Create_Default_ModbusTranslationTable(); } } else { Debug.WriteLine("ModbusTranslationTable.json not found, creating default"); Create_Default_ModbusTranslationTable(); } } /// /// Create Default Modbus Translation Table /// It also save the default table to JSON File /// private void Create_Default_ModbusTranslationTable() { ModbusTranslationTable = new ObservableCollection(); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.INVALID.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.NORMAL.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.TROUBLE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.FIRE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.FIRE_PRE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.VERIFY_FIRE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.HEAT.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.SUPERVISORY.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.SMOKE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.ACTIVATION.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.ACTIVATION_FAILED.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.TAMPER.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.COVER_OPEN.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.PAPER_OUT.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.WARNING.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.TROUBLE_LIGHT.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.WATCHDOGRESTART.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.ON.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.OFF.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.POLLUTION.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.POLLUTION_LIGHT.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.MONITOR.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.WATER.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.POWERFAIL.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.MANUAL_ALARM.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.PAS_WAIT_FOR_ACK.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.PAS_INVESTIGATE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.AC_CHANGED.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.AC_COUNTDOWN_STARTED.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.AC_TAMPER.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.FIRE_INT.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.ERROR.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.UNKNOWN.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.MATCHALL.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.NET_CONFIG_MISMATCH.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.UNKNOWN_ITEM.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.MISSING_ITEM.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.INCOMPATIBLE_SOFTWARE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.INCOMPATIBLE_NET_PROTOCOL.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.INFO_ALARM.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.CHEMICAL.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.WARNING_HEAT.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.WARNING_SMOKE.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.WARNING_CHEMICAL.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.REBOOT_READY.ToString(), 0)); ModbusTranslationTable.Add(new FSMModbusData(SILogicalState.LASTLOGICAL.ToString(), 0)); Save_ModbusTranslationTable(); } /// /// Save Modbus Translation Table to JSON File /// private void Save_ModbusTranslationTable() { try { String json = JsonSerializer.Serialize(ModbusTranslationTable); File.WriteAllText("ModbusTranslationTable.json", json); Debug.WriteLine("ModbusTranslationTable saved"); FSMtoModbusTranslationTable.ItemsSource = ModbusTranslationTable; } catch (Exception e) { Debug.WriteLine("Error saving ModbusTranslationTable : " + e.Message); } } private void Load_ConditionTable() { if (File.Exists("FSMConditionTable.json")) { String loadedJson = File.ReadAllText("FSMConditionTable.json"); try { FSMConditionTable = JsonSerializer.Deserialize>(loadedJson); Debug.WriteLine("FSMConditionTable loaded"); } catch (Exception ex) { Debug.WriteLine("Error loading FSMConditionTable : " + ex.Message); Create_Default_ConditionTable(); } } else { Debug.WriteLine("FSMConditionTable.json not found, creating default"); Create_Default_ConditionTable(); } } private void Create_Default_ConditionTable() { FSMConditionTable = new ObservableCollection(); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.INVALID.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.NORMAL.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.TROUBLE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.FIRE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.FIRE_PRE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.VERIFY_FIRE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.HEAT.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.SUPERVISORY.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.SMOKE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.ACTIVATION.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.ACTIVATION_FAILED.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.TAMPER.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.COVER_OPEN.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.PAPER_OUT.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.WARNING.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.TROUBLE_LIGHT.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.WATCHDOGRESTART.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.ON.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.OFF.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.POLLUTION.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.POLLUTION_LIGHT.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.MONITOR.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.WATER.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.POWERFAIL.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.MANUAL_ALARM.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.PAS_WAIT_FOR_ACK.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.PAS_INVESTIGATE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.AC_CHANGED.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.AC_COUNTDOWN_STARTED.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.AC_TAMPER.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.FIRE_INT.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.ERROR.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.UNKNOWN.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.MATCHALL.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.NET_CONFIG_MISMATCH.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.UNKNOWN_ITEM.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.MISSING_ITEM.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.INCOMPATIBLE_SOFTWARE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.INCOMPATIBLE_NET_PROTOCOL.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.INFO_ALARM.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.CHEMICAL.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.WARNING_HEAT.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.WARNING_SMOKE.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.WARNING_CHEMICAL.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.REBOOT_READY.ToString(), 0)); FSMConditionTable.Add(new FSMConditionVX(SILogicalState.LASTLOGICAL.ToString(), 0)); Save_ConditionTable(); } private void Save_ConditionTable() { try { String json = JsonSerializer.Serialize(FSMConditionTable); File.WriteAllText("FSMConditionTable.json", json); Debug.WriteLine("FSMConditionTable saved"); ConditionTable.ItemsSource = FSMConditionTable; } catch (Exception e) { Debug.WriteLine("Error saving FSMConditionTable : " + e.Message); } } 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; FSMtoModbusTranslationTable.ItemsSource = ModbusTranslationTable; ConditionTable.ItemsSource = FSMConditionTable; // 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); List ConditionON = new List(); List ConditionOFF = new List(); //add for example. delete if database condition done. ConditionON.Add(SILogicalState.FIRE.ToString()); ConditionON.Add(SILogicalState.SMOKE.ToString()); ConditionOFF.Add(SILogicalState.NORMAL.ToString()); fsm.AddListener(new FSMTableUpdater(FsmTableMember, DetectedSIID, DetectedSIIDCount)); fsm.AddListener(new ModbusTriggerFromFSM(FsmTableMember, ModbusTableMember, modbusSlave, ModbusTranslationTable)); 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 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 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"); } private void FSMtoModbusTranslationTable_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { Debug.WriteLine("FSMtoModbusTranslationTable_AutoGeneratingColumn : " + e.PropertyName); switch (e.PropertyName) { case "LogicalState": e.Column.Width = DataGridLength.Auto; break; case "Register": e.Column.Width = DataGridLength.Auto; break; } } private void FSMtoModbusTranslationTable_MouseDoubleClick(object sender, MouseButtonEventArgs e) { var selected = (sender as DataGrid).SelectedItem; if (selected != null) { try { FSMModbusData vv = (FSMModbusData)selected; Debug.WriteLine($"Selected Key={vv.LogicalState}, Value={vv.Register}"); InputBox ib = new InputBox(vv.LogicalState, vv.Register); bool? haschange = ib.ShowDialog(); if (haschange.Value) { Debug.WriteLine($"Changed Key={ib.FsmState}, Value={ib.ModbusRegister}"); for (int ii = 0; ii < ModbusTranslationTable.Count; ii++) { if (ModbusTranslationTable[ii].LogicalState == vv.LogicalState) { ModbusTranslationTable[ii].Register = ib.ModbusRegister; break; } } FSMtoModbusTranslationTable.InvalidateProperty(DataGrid.ItemsSourceProperty); } } catch(Exception exception) { Debug.WriteLine("FSMtoModbusTranslationTable_MouseDoubleClick Error : " + exception.Message); } } else Debug.WriteLine("Not selected yet"); } private void ResetFSMtoModbusTranslationTable_Click(object sender, RoutedEventArgs e) { var result = MessageBox.Show($"Reset FSM to Modbus Translation Table ?", "Reset FSM to Modbus Translation Table", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { if (ModbusTranslationTable != null) ModbusTranslationTable.Clear(); Create_Default_ModbusTranslationTable(); } } private void SetFSMtoModbusTranslationTable_Click(object sender, RoutedEventArgs e) { var result = MessageBox.Show($"Save FSM to Modbus Translation Table ?", "Save FSM to Modbus Translation Table", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { Save_ModbusTranslationTable(); } } private void ConditionTable_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { Debug.WriteLine("ConditionTable_AutoGeneratingColumn : " + e.PropertyName); switch (e.PropertyName) { case "condition": e.Column.Width = DataGridLength.Auto; break; case "status": e.Column.Width = DataGridLength.Auto; break; } } private void btnResetFSMCon_Click(object sender, RoutedEventArgs e) { var result = MessageBox.Show($"Reset FSM Condition Table ?", "Reset FSM Condition Table", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { if (FSMConditionTable != null) FSMConditionTable.Clear(); Create_Default_ConditionTable(); } } private void btnSetFSMCon_Click(object sender, RoutedEventArgs e) { var result = MessageBox.Show($"Save FSM Condition Table ?", "Save FSM Condition Table", MessageBoxButton.YesNo); if (result == MessageBoxResult.Yes) { Save_ConditionTable(); } } private void btnStartStopFSM_TouchEnter(object sender, TouchEventArgs e) { btnStartStopFSM_Click(sender, e); } private void TabItem_TouchDown(object sender, TouchEventArgs e) { if (sender is TabItem touchedTabItem) { // Set the touched TabItem as the selected one mainTab.SelectedItem = touchedTabItem; e.Handled = true; // Mark the event as handled } } private void mainTab_SelectionChanged(object sender, SelectionChangedEventArgs e) { } } /// e /// 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); } } /// /// Event Handler for Modbus /// 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() { Margin=new Thickness(5,0,5,0), TextWrapping=TextWrapping.Wrap, Width=connectedlist.Width, Tag = client, Height=50 }; UpdateLabel(l, 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; } } /// /// Event Handler for Bosch FSM /// 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; } /// /// Method ini untuk menambahkan SIID yang muncul dari FSM ke Listbox /// /// SIID yang muncul /// Tipe nya 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, Height=50 }); countlabel.Content = "Count : " + listbox.Items.Count; }); } } } /// /// Method ini untuk mengupdate State SIID yang ada di FSM /// /// SIID yang muncul /// Previous State kalau ada /// State sekarang 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; ObservableCollection translation; public ModbusTriggerFromFSM(ObservableCollection source, ObservableCollection data, ModbusSlave slave, ObservableCollection translation) { this.source = source; this.data = data; this.slave = slave; this.translation = translation; } /// /// Tidak dipakai /// void FSMResultInterface.DiscoveredSIID(string SIID, NodeData type) { } /// /// Ada State baru dari FSM, Action to Modbus /// /// SIID yang muncul /// Previous State kalau ada /// State sekarang 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 (translation != null) { foreach (var x in translation) { if (x.LogicalState.Equals(current.LogicalState)) { ushort reg = (ushort)x.Register; Debug.WriteLine($"NewState for SIID={SIID} State={current.LogicalState} is Register={reg}"); slave.SetRegister(dt.Register, reg); dt.Value = "" + reg; dt.LastUpdate = DateTime.Now.ToString(); return; } } Debug.WriteLine($"Translation for SIID={SIID} LogicalState={current.LogicalState} is not found"); dt.Value = "RULE NOT SET"; } else { Debug.WriteLine($"Translation 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; } /// /// Event Discovered SIID, tidak dipakai di sini /// void FSMResultInterface.DiscoveredSIID(string SIID, NodeData type) { } /// /// Ada State baru dari FSM, Action to VX 3K /// /// SIID yang muncul /// Previous state kalau ada /// State sekarang 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"); } } }