diff --git a/App.config b/App.config new file mode 100644 index 0000000..816b022 --- /dev/null +++ b/App.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/App.xaml b/App.xaml new file mode 100644 index 0000000..40d34dc --- /dev/null +++ b/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/App.xaml.cs b/App.xaml.cs new file mode 100644 index 0000000..3413eb6 --- /dev/null +++ b/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace FAtoPA.Net +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/Config.cs b/Config.cs new file mode 100644 index 0000000..594adf5 --- /dev/null +++ b/Config.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace FAtoPA +{ + class Config + { + // FSM settings + public byte FSM_NetGroup { get; set; } = 2; + public byte FSM_NetNode { get; set; } = 1; + public byte FSM_PNA { get; set; } = 2; + public String FSM_LocalIP { get; set; } = "192.168.10.23"; + public bool FSM_UseMulticast { get; set; } = false; + public String FSM_MulticastIP { get; set; } = "239.192.0.1"; + public UInt16 FSM_MulticastPort { get; set; } = 25000; + + public UInt16 Modbus_ListenPort { get; set; } = 502; + public byte Modbus_DeviceID { get; set; } = 1; + public UInt16 Modbus_MaxRegister { get; set; } = 2000; + + public String VX_TargetIP { get; set; } = "192.168.14.1"; + public UInt16 VX_TargetPort { get; set; } = 5000; + private String _configpath = ""; + + public Config() { + _configpath = GetConfigPath(); + // kalau belum ada, create default + if (!File.Exists(_configpath)) Save(); + } + + public Boolean FileIsExist() { return File.Exists(_configpath); } + + public bool Save() + { + + Debug.WriteLine("Will Save Config to [" + _configpath + "]"); + + try + { + String jsonstring = JsonSerializer.Serialize(this); + File.WriteAllText(_configpath, jsonstring); + Debug.WriteLine("Config saved to [" + _configpath + "]"); + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Config Save to ["+ _configpath + "] Error: " + ex.Message); + } + return false; + } + + public bool Load() + { + + if (File.Exists(_configpath)) + { + try + { + string jsonstring = File.ReadAllText(_configpath); + Config _loaded = JsonSerializer.Deserialize(jsonstring); + if (_loaded != null) + { + this.FSM_NetGroup = _loaded.FSM_NetGroup; + this.FSM_NetNode = _loaded.FSM_NetNode; + this.FSM_PNA = _loaded.FSM_PNA; + this.FSM_LocalIP = _loaded.FSM_LocalIP; + this.FSM_UseMulticast = _loaded.FSM_UseMulticast; + this.FSM_MulticastIP = _loaded.FSM_MulticastIP; + this.FSM_MulticastPort = _loaded.FSM_MulticastPort; + this.Modbus_ListenPort = _loaded.Modbus_ListenPort; + this.Modbus_DeviceID = _loaded.Modbus_DeviceID; + this.Modbus_MaxRegister = _loaded.Modbus_MaxRegister; + this.VX_TargetIP = _loaded.VX_TargetIP; + this.VX_TargetPort = _loaded.VX_TargetPort; + + Debug.WriteLine("Config Loaded from [" + _configpath + "]"); + return true; + } else Debug.WriteLine("Config Load Error: File ["+ _configpath + "] is not valid Config."); + } catch(Exception ex) + { + Debug.WriteLine("Config Load from ["+ _configpath + "] Error: " + ex.Message); + } + } + else Debug.WriteLine("Config Load Error: File ["+ _configpath + "] not found."); + return false; + } + + private static String GetConfigPath() + { + String _xx = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FAtoPA"); + Debug.WriteLine("Config Path: " + _xx); + if (!Directory.Exists(_xx)) { + try + { + Directory.CreateDirectory(_xx); + } + catch (Exception ex) + { + Debug.WriteLine("Config Path Error: " + ex.Message); + } + } + + return System.IO.Path.Combine(_xx, "config.json"); + } + } +} diff --git a/Database.cs b/Database.cs new file mode 100644 index 0000000..7acedb0 --- /dev/null +++ b/Database.cs @@ -0,0 +1,475 @@ +using Microsoft.Data.Sqlite; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FAtoPA +{ + class Database + { + String connectionString = "Data Source=database.db"; + + /// + /// Create Database Object + /// + public Database() + { + + CreateFSMTable(); + CreateModbusTable(); + CreateVXTable(); + } + + private bool CreateFSMTable() + { + //Debug.WriteLine("About to execute CreateFSMTable"); + using (var connection = new SqliteConnection(connectionString)) + { + try + { + connection.Open(); + var createtablecmd = connection.CreateCommand(); + createtablecmd.CommandText = "CREATE TABLE IF NOT EXISTS FsmData (SIID TEXT PRIMARY KEY, Enable INTEGER, Description TEXT)"; + createtablecmd.ExecuteNonQuery(); + Debug.WriteLine("CreateFSMTable success"); + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Error CreateFSMTable, Exception : " + ex.Message); + return false; + } + + } + } + + public bool ClearFSMTable() { + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + var deleteCmd = connection.CreateCommand(); + deleteCmd.CommandText = "DELETE FROM FsmData"; + try + { + int result = deleteCmd.ExecuteNonQuery(); + return (result > 0); + } + catch (SqliteException e) + { + Debug.WriteLine("Error deleting FSMData: " + e.Message); + } + } + return false; + } + + public List GetFSMDatas() + { + List fsmDatas = new List(); + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + + var selectCmd = connection.CreateCommand(); + selectCmd.CommandText = "SELECT * FROM FsmData"; + using (var reader = selectCmd.ExecuteReader()) + { + while (reader.Read()) + { + FSMData fsmData = new FSMData(reader.GetString(0), reader.GetBoolean(1), reader.GetString(2)); + fsmDatas.Add(fsmData); + } + } + } + return fsmDatas; + } + + public bool AddFSMData(params FSMData[] data) + { + using(var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + using (var transaction = connection.BeginTransaction()) + { + foreach (var item in data) + { + var insertCmd = connection.CreateCommand(); + insertCmd.CommandText = "INSERT INTO FsmData (SIID, Enable, Description) VALUES (@SIID, @Enable, @Description)"; + insertCmd.Parameters.AddWithValue("@SIID", item.SIID); + insertCmd.Parameters.AddWithValue("@Enable", item.Enable); + insertCmd.Parameters.AddWithValue("@Description", item.Description); + try + { + int result = insertCmd.ExecuteNonQuery(); + if (result <= 0) + { + transaction.Rollback(); + return false; + } + } + catch (SqliteException e) + { + Debug.WriteLine("Error inserting FSMData: " + e.Message); + transaction.Rollback(); + return false; + } + } + transaction.Commit(); + } + return true; + } + } + + public bool RemoveFSMDatabySIID(String SIID) + { + using (var conn = new SqliteConnection(connectionString)) + { + conn.Open(); + var deleteCmd = conn.CreateCommand(); + deleteCmd.CommandText = "DELETE FROM FsmData WHERE SIID = @SIID"; + deleteCmd.Parameters.AddWithValue("@SIID", SIID); + try + { + int result = deleteCmd.ExecuteNonQuery(); + return (result > 0); + } + catch (SqliteException e) + { + Debug.WriteLine("Error deleting FSMData: " + e.Message); + return false; + } + } + } + + private bool CreateModbusTable() + { + //Debug.WriteLine("About to execute CreateModbusTable"); + using (var connection = new SqliteConnection(connectionString)) + { + try + { + connection.Open(); + var modbuscmd = connection.CreateCommand(); + modbuscmd.CommandText = "CREATE TABLE IF NOT EXISTS ModbusData (SIID TEXT PRIMARY KEY, Register INTEGER, Description TEXT)"; + modbuscmd.ExecuteNonQuery(); + Debug.WriteLine("CreateModbusTable success"); + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Error CreateModbusTable, Exception : " + ex.Message); + return false; + } + } + } + + public bool ClearModbusTable() + { + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + var deleteCmd = connection.CreateCommand(); + deleteCmd.CommandText = "DELETE FROM ModbusData"; + try + { + int result = deleteCmd.ExecuteNonQuery(); + return (result > 0); + } + catch (SqliteException e) + { + Debug.WriteLine("Error deleting ModbusData: " + e.Message); + } + } + return false; + } + + public Boolean AddModbusData(params ModbusData[] data) + { + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + using (var transaction = connection.BeginTransaction()) + { + foreach (var item in data) + { + var insertCmd = connection.CreateCommand(); + insertCmd.CommandText = "INSERT INTO ModbusData (SIID, Register, Description) VALUES (@SIID, @Register, @Description)"; + insertCmd.Parameters.AddWithValue("@SIID", item.SIID); + insertCmd.Parameters.AddWithValue("@Register", item.Register); + insertCmd.Parameters.AddWithValue("@Description", item.Description); + try + { + int result = insertCmd.ExecuteNonQuery(); + if (result <= 0) + { + transaction.Rollback(); + return false; + } + } + catch (SqliteException e) + { + Debug.WriteLine("Error inserting ModbusData: " + e.Message); + transaction.Rollback(); + return false; + } + } + transaction.Commit(); + } + return true; + } + } + + public List GetModbusDatas() + { + List modbusDatas = new List(); + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + + var selectCmd = connection.CreateCommand(); + selectCmd.CommandText = "SELECT * FROM ModbusData"; + using (var reader = selectCmd.ExecuteReader()) + { + while (reader.Read()) + { + ModbusData modbusdata = new ModbusData(reader.GetString(0), reader.GetFieldValue(1), reader.GetString(2)); + modbusDatas.Add(modbusdata); + } + } + } + return modbusDatas; + } + + public bool RemoveModbusDatabySIID(String SIID) + { + using (var conn = new SqliteConnection(connectionString)) + { + conn.Open(); + var deleteCmd = conn.CreateCommand(); + deleteCmd.CommandText = "DELETE FROM ModbusData WHERE SIID = @SIID"; + deleteCmd.Parameters.AddWithValue("@SIID", SIID); + try + { + int result = deleteCmd.ExecuteNonQuery(); + return (result > 0); + } + catch (SqliteException e) + { + Debug.WriteLine("Error deleting ModbusData: " + e.Message); + return false; + } + } + } + + private bool CreateVXTable() + { + //Debug.WriteLine("About to execute CreateVXTable"); + using (var connection = new SqliteConnection(connectionString)) + { + try + { + connection.Open(); + var vxlancmd = connection.CreateCommand(); + vxlancmd.CommandText = "CREATE TABLE IF NOT EXISTS VxTable (SIID TEXT PRIMARY KEY, FrameID INTEGER, CIN INTEGER, Description TEXT)"; + vxlancmd.ExecuteNonQuery(); + Debug.WriteLine("CreateVXTable success"); + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Error CreateVXTable, Exception : " + ex.Message); + return false; + } + } + } + + public bool ClearVXTable() + { + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + var deleteCmd = connection.CreateCommand(); + deleteCmd.CommandText = "DELETE FROM VxTable"; + try + { + int result = deleteCmd.ExecuteNonQuery(); + return (result > 0); + } + catch (SqliteException e) + { + Debug.WriteLine("Error deleting VXData: " + e.Message); + } + } + return false; + } + + public List GetVXDatas() + { + List vxDatas = new List(); + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + + var selectCmd = connection.CreateCommand(); + selectCmd.CommandText = "SELECT * FROM VxTable"; + using (var reader = selectCmd.ExecuteReader()) + { + while (reader.Read()) + { + VXData vxdata = new VXData(reader.GetString(0), reader.GetByte(1), reader.GetByte(2)); + vxDatas.Add(vxdata); + } + } + } + return vxDatas; + } + + public bool RemoveVXDatabySIID(String SIID) + { + using (var conn = new SqliteConnection(connectionString)) + { + conn.Open(); + var deleteCmd = conn.CreateCommand(); + deleteCmd.CommandText = "DELETE FROM VxTable WHERE SIID = @SIID"; + deleteCmd.Parameters.AddWithValue("@SIID", SIID); + try + { + int result = deleteCmd.ExecuteNonQuery(); + return (result > 0); + } + catch (SqliteException e) + { + Debug.WriteLine("Error deleting VXData: " + e.Message); + return false; + } + } + } + + public bool AddVXData(params VXData[] data) { + using(var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + using (var transaction = connection.BeginTransaction()) + { + foreach (var item in data) + { + var insertCmd = connection.CreateCommand(); + insertCmd.CommandText = "INSERT INTO VxTable (SIID, FrameID, CIN, Description) VALUES (@SIID, @FrameID, @CIN, @Description)"; + insertCmd.Parameters.AddWithValue("@SIID", item.SIID); + insertCmd.Parameters.AddWithValue("@FrameID", item.FrameID); + insertCmd.Parameters.AddWithValue("@CIN", item.CIN); + insertCmd.Parameters.AddWithValue("@Description", item.Description); + try + { + int result = insertCmd.ExecuteNonQuery(); + if (result <= 0) + { + transaction.Rollback(); + return false; + } + } + catch (SqliteException e) + { + Debug.WriteLine("Error inserting VXData: " + e.Message); + transaction.Rollback(); + return false; + } + } + transaction.Commit(); + } + return true; + } + } + + } + + class FSMData + { + public String SIID { get; set; } + public Boolean Enable { get; set; } + public String Description { get; set; } + public String Value { get; set; } + public String LastUpdate { get; set; } + public FSMData(String siid, Boolean enable, String description) + { + this.SIID = siid; + this.Enable = enable; + this.Description = description; + this.Value = ""; + this.LastUpdate = ""; + } + public FSMData(String siid) + { + this.SIID = siid; + this.Enable = true; + this.Description = ""; + this.Value = ""; + this.LastUpdate = ""; + } + public FSMData(String siid, Boolean enable) + { + this.SIID = siid; + this.Enable = enable; + this.Description = ""; + this.LastUpdate = ""; + this.Value = ""; + + } + } + + class ModbusData + { + public String SIID { get; set; } + public UInt16 Register { get; set; } + public String Description { get; set; } + + public String Value { get; set; } + public String LastUpdate { get; set; } + public ModbusData(String siid, UInt16 register, String description) + { + this.SIID = siid; + this.Register = register; + this.Description = description; + this.Value = ""; + this.LastUpdate = ""; + } + public ModbusData(String siid, UInt16 register) + { + this.SIID = siid; + this.Register = register; + this.Description = siid + " To " + register; + this.Value = ""; + this.LastUpdate = ""; + } + } + + class VXData + { + public String SIID { get; set; } + public Byte FrameID { get; set; } + public Byte CIN { get; set; } + public String Description { get; set; } + public String Value { get; set; } + public String LastUpdate { get; set; } + public VXData(String siid, Byte frameid, Byte cin, String Description) + { + this.SIID = siid; + this.FrameID = frameid; + this.CIN = cin; + this.Description=Description; + this.Value = ""; + this.LastUpdate = ""; + } + public VXData(String siid, Byte frameid, Byte cin) + { + this.SIID = siid; + this.FrameID = frameid; + this.CIN = cin; + this.Description = siid+" To "+ frameid + "." + cin; + this.Value = ""; + this.LastUpdate = ""; + } + } +} diff --git a/EventInterface.cs b/EventInterface.cs new file mode 100644 index 0000000..b2ef6b0 --- /dev/null +++ b/EventInterface.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FAtoPA +{ + interface EventInterface + { + void ConnectStatus(bool success, String message); + void StatisticUpdate(uint TXOK, uint RXOK, uint TXErr, uint RXerr, uint TXBytes, uint RXBytes); + void Log(String msg); + } +} diff --git a/FAtoPA.Net.csproj b/FAtoPA.Net.csproj new file mode 100644 index 0000000..cb23295 --- /dev/null +++ b/FAtoPA.Net.csproj @@ -0,0 +1,207 @@ + + + + + Debug + AnyCPU + {C158634C-A54E-41CD-A41A-6D0AFF841BE4} + WinExe + FAtoPA.Net + FAtoPA.Net + v4.8 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\ApplicationProtocolCIL.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\Backend.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\DataExchangeInterfaces.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\FSIConfig.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\FSITrace.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\FSM5000FSI.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\FSM5000FSIAPI.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\FSM5000FSILoader.dll + + + packages\Microsoft.Bcl.AsyncInterfaces.9.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + packages\Microsoft.Data.Sqlite.Core.9.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\MPNetCIL.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\MPNetGate.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\Repository.dll + + + packages\SQLitePCLRaw.bundle_e_sqlite3.2.1.10\lib\net461\SQLitePCLRaw.batteries_v2.dll + + + packages\SQLitePCLRaw.core.2.1.10\lib\netstandard2.0\SQLitePCLRaw.core.dll + + + packages\SQLitePCLRaw.provider.dynamic_cdecl.2.1.10\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll + + + ..\..\..\Bosch FA\FSM5000FSI-2.0.21\Release_x64\StandardCIL.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + packages\System.IO.Pipelines.9.0.0\lib\net462\System.IO.Pipelines.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + packages\System.Text.Encodings.Web.9.0.0\lib\net462\System.Text.Encodings.Web.dll + + + packages\System.Text.Json.9.0.0\lib\net462\System.Text.Json.dll + + + packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + + + + MainWindow.xaml + Code + + + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + \ No newline at end of file diff --git a/FAtoPA.Net.sln b/FAtoPA.Net.sln new file mode 100644 index 0000000..fbfdd7a --- /dev/null +++ b/FAtoPA.Net.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35514.174 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FAtoPA.Net", "FAtoPA.Net.csproj", "{C158634C-A54E-41CD-A41A-6D0AFF841BE4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Debug|x64.ActiveCfg = Debug|x64 + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Debug|x64.Build.0 = Debug|x64 + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Release|Any CPU.Build.0 = Release|Any CPU + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Release|x64.ActiveCfg = Release|x64 + {C158634C-A54E-41CD-A41A-6D0AFF841BE4}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FSM.cs b/FSM.cs new file mode 100644 index 0000000..fa18635 --- /dev/null +++ b/FSM.cs @@ -0,0 +1,288 @@ +using FSM5000FSI; +using FSM5000FSIAPI.Version3; + +using System; +using System.CodeDom; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FAtoPA +{ + class FSM + { + public static bool Started = false; + private FSIConfig config; + private FSIController controller; + private List listenerlist; + public Dictionary ItemTypeDictionary { get; } + public Dictionary AvailableNodes { get; } + private EventInterface _event; + public FSM(EventInterface callback) + { + _event = callback; + ItemTypeDictionary = new Dictionary(); + AvailableNodes = new Dictionary(); + listenerlist = new List(); + } + + /// + /// Initialize Fire Alarm Module + /// + /// 1 - 255 + /// 1 - 255 + /// 1 - 255 + /// on a system with multiple network adapter, use this to specify which adapter will be used + public FSM(EventInterface callback, byte netgroup, byte netnode, byte pna, byte[] localip) : this(callback) { + SetConfig(netgroup, netnode, pna, localip); + } + + public void SetConfig(byte netgroup, byte netnode, byte pna, byte[] localip) + { + config = new FSIConfig(); + config.MPNetGroup = netgroup; + config.MPNetNode = netnode; + config.PNA = pna; + config.LocalIPAddress = localip; + config.RepositoryLocation = ".\\repository"; + config.AdvancedFSIConfig = new AdvancedFSIConfig(); + } + + /// + /// Optional option if using Multicast Communication + /// + /// true if want to use Multicast + /// target Multicast IP, if not available, default to 239.192.0.1 + /// target Port, if not available, default to 25000 + public void MulticastConfig(Boolean useMulticast, byte[] MulticastIP, ushort PortNumber) + { + if (config != null) + { + if (config.AdvancedFSIConfig == null) config.AdvancedFSIConfig = new AdvancedFSIConfig(); + config.AdvancedFSIConfig.IsIPMulticast = useMulticast; + config.AdvancedFSIConfig.MulticastAddress = MulticastIP; + config.AdvancedFSIConfig.PortNumber = PortNumber; + config.AdvancedFSIConfig.NetstackTraceLevel = SourceLevels.Error; + } + + } + + + /// + /// Start FSM Monitoring + /// + public void Start() + { + controller = FSIController.GetInstance(); + // internal Listeners + controller.AddListener(new ConfigListener(ItemTypeDictionary, AvailableNodes, listenerlist)); + controller.AddListener(new StateListener(AvailableNodes, listenerlist)); + TraceConsoleWritter outputter = new TraceConsoleWritter(); + controller.SetTraceLevel(SourceLevels.Warning); //for support issues please set the level to SourceLevels.Verbose + Result result = controller.Startup(config); + //Debug.WriteLine("[FSM] Start result = "+result.ToString()); + if (result==Result.SUCCESS) + { + Started = true; + if (_event != null) _event.ConnectStatus(true, "FSM Started"); + } + else + { + Started = false; + if (_event != null) _event.ConnectStatus(false, "FSM Failed to Start"); + } + } + + public void AddListener(FSMResultInterface listener) + { + if (listenerlist != null) listenerlist.Add(listener); + } + + /// + /// Stop FSM Monitoring + /// + public void Stop() + { + if (controller != null) + { + try + { + Result result = controller.Shutdown(); + //Console.WriteLine("[FSM] Shutdown result = " + result.ToString()); + if (_event!=null) _event.ConnectStatus(false, "FSM Stopped"); + } catch (Exception e) + { + Debug.WriteLine("[FSM] Error on Stop: " + e.Message); + } + + } + + } + + + + } + + + /// + /// The Config Listener receives all information about the configuration + /// received from the panel network. The information must be stored in real application + /// to know the devices from the panel network and the possible commands. + /// + class ConfigListener : IPanelConfigListener + { + private Dictionary type_dictionary; + private Dictionary node_data; + private List listeners; + public ConfigListener(Dictionary type, Dictionary data, List listener) + { + this.type_dictionary = type; + this.node_data = data; + this.listeners = listener; + } + + /// + /// Akan muncul di pertama kali, untuk informasi bahwa device dengan FunctionalType [X} memiliki deskripsi [Y] + /// + /// + public void SetItemType(ItemType devItemType) + { + Debug.WriteLine($"Item type {devItemType.FunctionalType} ({devItemType.Description})"); + if (type_dictionary != null) + { + int type = int.Parse(devItemType.FunctionalType.ToString()); + if (!type_dictionary.ContainsKey(type)) type_dictionary.Add(type, devItemType.Description); + + } + + } + + /// + /// Akan muncul di urutan kedua, untuk informasi node device apa saja yang terdeteksi di system + /// + /// + public void SetItem(Item devItem) + { + Debug.WriteLine($"Item ({devItem.SIID}, {devItem.FunctionalType} ({devItem.Label})"); + if (node_data != null) + { + String SIID = devItem.SIID.ToString(); + int type = int.Parse(devItem.FunctionalType.ToString()); + if (!node_data.ContainsKey(SIID)) + { + NodeData nodeData = new NodeData(); + nodeData.SIID = devItem.SIID; + nodeData.Type = type; + nodeData.Label = devItem.Label; + nodeData.Description = type_dictionary.ContainsKey(type) ? type_dictionary[type] : "Unknown"; + node_data.Add(SIID, nodeData); + // notify all listeners + if (listeners != null) + foreach (var item in listeners) + item.DiscoveredSIID(SIID, nodeData); + + } + } + + } + + /// + /// Akan muncul kalau suatu node hilang dari system + /// + /// + public void RemoveItem(SIID address) + { + Debug.WriteLine("SI " + address + " removed."); + if (node_data != null) + { + String SIID = address.ToString(); + if (node_data.ContainsKey(SIID)) node_data.Remove(SIID); + + } + + } + } + + /// + /// The State Listener receive all states for devices send by the panel network. + /// Ini yang paling penting, untuk trigger ke Modbus dan VX3000 + /// + class StateListener : IStateListener + { + private Dictionary node_data; + private List listeners; + public StateListener(Dictionary data, List listener) + { + this.node_data= data; + this.listeners = listener; + } + /// + /// Akan muncul ketiga dan seterusnya, ketika ada perubahan status dari node device + /// + /// + public void SetItemState(ItemState devItemState) + { + Debug.WriteLine($"State {devItemState.SIID} = {devItemState.LogicalState}"); + if (node_data != null) + { + String SIID = devItemState.SIID.ToString(); + if (node_data.ContainsKey(SIID)) + { + NodeData nd = node_data[SIID]; + if (nd != null) + { + NodeState prev = nd.State; + nd.State = new NodeState(devItemState); + + // notify all listeners + if (listeners != null) + foreach (var item in listeners) + item.NewState(SIID, prev, nd.State); + + if (prev != null) + { + Debug.WriteLine("SIID=" + SIID + " Change LogicalState from " + prev.LogicalState + " to " + nd.State.LogicalState); + } + else + { + Debug.WriteLine("New State for SIID=" + SIID + " LogicalState=" + nd.State.LogicalState); + } + } else Debug.WriteLine("NodeData with SIID " + SIID + " is null"); + } else Debug.WriteLine("node_data doesn't contain SIID " + SIID); + + } else Debug.WriteLine("node_data is null"); + + + } + + /// + /// Akan muncul sekali di awal mula, sebagai informasi waktu di panel system + /// + /// + public void SetMPNetTime(DateTime mpNetTime) + { + Debug.WriteLine("Time is " + mpNetTime + "."); + } + } + + /// + /// Receive the traces from the FSI and output the traces to console + /// In real application it is very useful to write the traces to files + /// for suppport issues + /// + class TraceConsoleWritter : TraceListener + { + public override void Write(string message) + { + if (message!=null && message.Length>0) Debug.Write(message); + } + + public override void WriteLine(string message) + { + if (message != null && message.Length > 0) Debug.WriteLine(message); + } + } + +} diff --git a/FSMResultInterface.cs b/FSMResultInterface.cs new file mode 100644 index 0000000..9fcee90 --- /dev/null +++ b/FSMResultInterface.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FAtoPA +{ + interface FSMResultInterface + { + void DiscoveredSIID(String SIID, NodeData type); + void NewState(String SIID, NodeState previous, NodeState current); + } +} diff --git a/MainWindow.xaml b/MainWindow.xaml new file mode 100644 index 0000000..35b78c3 --- /dev/null +++ b/MainWindow.xaml @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +