├── Mono ├── MacSlave.7z └── LinuxSlave.7z ├── exe └── Modbus Slave Simulation.7z ├── ModbusSlaveSimulation ├── Resources │ ├── Logo.png │ ├── Modbus.dll │ ├── DarkBlue.png │ ├── log4net.dll │ ├── Unme.Common.dll │ ├── FunctionCodes.png │ ├── ModbusRTUTCP.ico │ └── README.txt ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Program.cs ├── ModbusSlaveSimulation.csproj ├── Form1.cs └── Form1.resx ├── screenshots └── Modbus Slave Simulation.png ├── LICENSE ├── ModbusSlaveSimulation.sln ├── .gitattributes ├── README.md └── .gitignore /Mono/MacSlave.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/Mono/MacSlave.7z -------------------------------------------------------------------------------- /Mono/LinuxSlave.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/Mono/LinuxSlave.7z -------------------------------------------------------------------------------- /exe/Modbus Slave Simulation.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/exe/Modbus Slave Simulation.7z -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/Logo.png -------------------------------------------------------------------------------- /screenshots/Modbus Slave Simulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/screenshots/Modbus Slave Simulation.png -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/Modbus.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/Modbus.dll -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/DarkBlue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/DarkBlue.png -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/log4net.dll -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/Unme.Common.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/Unme.Common.dll -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/FunctionCodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/FunctionCodes.png -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/ModbusRTUTCP.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GitHubDragonFly/ModbusSlaveSimulation/HEAD/ModbusSlaveSimulation/Resources/ModbusRTUTCP.ico -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GitHubDragonFly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ModbusSlaveSimulation.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29613.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModbusSlaveSimulation", "ModbusSlaveSimulation\ModbusSlaveSimulation.csproj", "{B65F0AAE-0B33-44D3-BFA1-3EB53A0CFAC5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B65F0AAE-0B33-44D3-BFA1-3EB53A0CFAC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {B65F0AAE-0B33-44D3-BFA1-3EB53A0CFAC5}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {B65F0AAE-0B33-44D3-BFA1-3EB53A0CFAC5}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {B65F0AAE-0B33-44D3-BFA1-3EB53A0CFAC5}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {4D21C88B-AC1C-4186-8723-E4E3A9AD01A5} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ModbusSlaveSimulation")] 9 | [assembly: AssemblyDescription("Modbus Slave Simulation with nModbus libraries - RTU / TCP / UDP / ASCIIoverRTU")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ModbusSlaveSimulation")] 13 | [assembly: AssemblyCopyright("Copyright © 2020 Godra")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b65f0aae-0b33-44d3-bfa1-3eb53a0cfac5")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Resources/README.txt: -------------------------------------------------------------------------------- 1 | NModbus 2 | 3 | What is it? 4 | ----------- 5 | NModbus is a C# 3.0 implementation of the Modbus protocol. 6 | 7 | More information at the NModbus project web site http://nmodbus.com/ 8 | 9 | 10 | The Latest Version 11 | ------------------ 12 | The latest binary distribution can be found on the NModbus project web site http://nmodbus.com/ 13 | 14 | The latest source for the project can be found at the NModbus project's google code page http://code.google.com/p/nmodbus/ 15 | 16 | 17 | Documentation 18 | ------------- 19 | Documentation is available in chm format (NModbus.chm) 20 | 21 | 22 | License 23 | ------- 24 | Copyright (c) 2006 Scott Alexander 25 | 26 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 27 | and associated documentation files (the "Software"), to deal in the Software without restriction, 28 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 29 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 30 | furnished to do so, subject to the following conditions: 31 | 32 | The above copyright notice and this permission notice shall be included in all copies or substantial 33 | portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 36 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 37 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 38 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 39 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace ModbusSlaveSimulation 5 | { 6 | static class Program 7 | { 8 | static Program() 9 | { 10 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 11 | } 12 | 13 | /// 14 | /// The main entry point for the application. 15 | /// 16 | [STAThread] 17 | static void Main() 18 | { 19 | Application.EnableVisualStyles(); 20 | Application.SetCompatibleTextRenderingDefault(false); 21 | Application.Run(new Form1()); 22 | } 23 | 24 | static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 25 | { 26 | if (args.Name == null) 27 | { 28 | throw new NullReferenceException("Item name is null."); 29 | } 30 | else 31 | { 32 | if (!args.Name.StartsWith("ModbusSlave") && (args.Name.StartsWith("Modbus") || args.Name.StartsWith("log4net") || args.Name.StartsWith("Unme.Common"))) 33 | { 34 | if (args.Name.Substring(0, args.Name.IndexOf(',')) == "Modbus") 35 | return System.Reflection.Assembly.Load(Properties.Resources.Modbus); 36 | if (args.Name.Substring(0, args.Name.IndexOf(',')) == "log4net") 37 | return System.Reflection.Assembly.Load(Properties.Resources.log4net); 38 | if (args.Name.Substring(0, args.Name.IndexOf(',')) == "Unme.Common") 39 | return System.Reflection.Assembly.Load(Properties.Resources.Unme_Common); 40 | } 41 | return null; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/ModbusSlaveSimulation.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B65F0AAE-0B33-44D3-BFA1-3EB53A0CFAC5} 8 | WinExe 9 | ModbusSlaveSimulation 10 | ModbusSlaveSimulation 11 | v4.0 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | Resources\ModbusRTUTCP.ico 40 | 41 | 42 | 43 | False 44 | Resources\log4net.dll 45 | False 46 | 47 | 48 | False 49 | Resources\Modbus.dll 50 | False 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | False 64 | Resources\Unme.Common.dll 65 | False 66 | 67 | 68 | 69 | 70 | Form 71 | 72 | 73 | Form1.cs 74 | 75 | 76 | 77 | 78 | Form1.cs 79 | 80 | 81 | ResXFileCodeGenerator 82 | Resources.Designer.cs 83 | Designer 84 | 85 | 86 | True 87 | Resources.resx 88 | True 89 | 90 | 91 | SettingsSingleFileGenerator 92 | Settings.Designer.cs 93 | 94 | 95 | True 96 | Settings.settings 97 | True 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reality Check 2 | Just for those of you who might be concerned about the Climate Change, here are couple of sobering insights: 3 | - Neil deGrasse Tyson's perspective on climate change: [YouTube Video](https://www.youtube.com/watch?v=tRA2SfSk2Tc) 4 | - My perspective, with statements from two AI entities: [Climate Change](https://githubdragonfly.github.io/viewers/templates/Climate%20Change.txt) 5 | 6 | # ModbusSlaveSimulation 7 | Standalone Windows app supporting Modbus RTU, TCP, UDP and ASCIIoverRTU protocols for simulation. 8 | 9 | Also included are its Mono versions for Linux and Mac OS X, these are VB Net versions so: 10 | - For Linux you will have to install `mono-complete` and `mono-vbnc` packages 11 | - Mac might be different depending on the OS X version, maybe install `mono` and `mono-basic` packages 12 | 13 | If a firewall is enabled then it might prompt you to allow this app to communicate on the network: 14 | - Normally it should be allowed to communicate on the private network otherwise it might not work properly 15 | - Do not allow public access unless you know what you are doing 16 | - Once the testing is done then remember to remove this app from the firewall's list of allowed apps 17 | 18 | The app is designed to allow running multiple instances of the app at the same time, for example: 19 | - Use the same protocol for each instance but with different port numbers, similar to: 20 | - IP 127.0.0.1 TCP Port 501 and IP 127.0.0.1 TCP Port 502 21 | - Use a mix of different protocols with help of other tools (like [com0com](https://pete.akeo.ie/search/label/com0com) for RTU protocol on Windows) 22 | 23 | The app should service requests for any valid Modbus slave ID. 24 | 25 | This is all based on modified [nModbus](https://code.google.com/p/nmodbus/) .NET 3.5 libraries: 26 | - MIT Licensed Copyright (c) 2006 Scott Alexander: 27 | - These are included as a resource for Windows version but are separate for Mono version 28 | 29 | Intended to be used as a quick testing tool: 30 | - Can be tested with its counterpart [ModbusMaster](https://github.com/GitHubDragonFly/ModbusMaster) (check the video further below) 31 | - Or maybe use the [AdvancedHMI](https://www.advancedhmi.com/) software instead since it is highly functional and free. 32 | 33 | # Screenshot 34 | 35 | ![Start Page](screenshots/Modbus%20Slave%20Simulation.png?raw=true) 36 | 37 | # Functionality 38 | - All values can be set before the connection is established - Coils, Discrete Inputs, Input Registers, Holding Registers. 39 | - The Data Grid View is set to initially show 20 rows of addresses but can be changed within the `Row Count` dropdown to show more or all rows if necessary. 40 | - In the Data Grid View, selected with the `I/O Address Range` dropdown, double-click the value to change it: 41 | - Boolean values will flip between 0 and 1 42 | - Uint16 values require unsigned integer value between 0 and 65535 43 | - Discrete Inputs and Input Registers provide `read-only` access to the Master application: 44 | - MODBUS device designated as `Master` can ONLY send requests to read these values 45 | - These values should be manipulated by the user directly in the simulator otherwise they will not be changing 46 | - Coils and Holding Registers provide `read/write` access to the Master application: 47 | - MODBUS device designated as `Master` can send requests to read these values as well as send requests to have these values be modified 48 | - These values can also be manipulated by the user directly in the simulator if necessary 49 | - For `RTU` and `ASCIIoverRTU` protocols, on a single PC, this simulator can use the help of: 50 | - [com0com](https://pete.akeo.ie/search/label/com0com) program for Windows to provide virtual serial port pairs 51 | - [tty0tty](https://github.com/freemed/tty0tty) program for Linux to provide virtual serial port pairs 52 | - Additional TextBox allows manual input of the serial port: 53 | - Mainly intended for Linux so those `tty0tty` virtual port pairs, like `/dev/tnt0` <=> `/dev/tnt1`, could be accessed 54 | - This box was removed in the Mac Mono version 55 | - The library also supports Masked Bit Write, function code 22 (0x16H or FC22). 56 | 57 | # Usage 58 | 59 | ## -> For Windows 60 | - Either use Windows executable files from the `exe` folder or follow the instructions below to build it yourself: 61 | - Download and install Visual Studio community edition (ideally 2019). 62 | - Download and extract the zip file of this project. 63 | - Open this as an existing project in Visual Studio and, on the menu, do: 64 | - Build/Build Solution (or press Ctrl-Shift-B). 65 | - Debug/Start Debugging (or press F5) to run the app. 66 | - Locate created EXE file in the `/bin/Debug` folder and copy it over to your preferred folder or Desktop 67 | - For testing RTU protocols use [com0com](https://pete.akeo.ie/search/label/com0com) to create virtual serial ports 68 | 69 | ## -> For Mono 70 | - Make sure that Mono is installed on your computer: 71 | - Both `mono-complete` and `mono-vbnc` packages for Linux 72 | - For Mac you might need to experiment, maybe `mono` and `mono-basic` packages 73 | - Download and extract the zip file of this project and locate Mono archive in the `Mono` folder. 74 | - Extract 4 files and potentially rename the newly created folder and/or exe file to something shorter if you wish (just to make the terminal navigation quicker). 75 | - Open the terminal, navigate to the folder and type: `sudo mono ModbusSlaveSimulation.exe`: 76 | - On Mac you might need to switch to the superuser `su` account 77 | - For testing RTU protocols, on Linux you can possibly install and use [tty0tty](https://github.com/freemed/tty0tty) virtual ports while on Mac the later OS X versions seem to have pseudo terminals - pairs of devices such as `/dev/ptyp3` and `/dev/ttyp3`. 78 | 79 | Note for Mac users: this was tested on an old iMac G5 PowerPC computer with Mono v2.10.2. Some odd behaviour was present in a sense that the app was loosing focus thus disrupting continuous TCP communication. There is a text box with red X that you can click to try to maintain focus (if you do something else afterwards then click it again). Since I cannot test it in any other way then it is left for you to experiment. 80 | 81 | # Video 82 | 83 | https://github.com/user-attachments/assets/3058bbad-4691-4670-95d9-b2f011199984 84 | 85 | # License 86 | Licensed under MIT license - see also the NModbus MIT License within the README.txt file inside the Resources folder. 87 | 88 | # Trademarks 89 | Any and all trademarks, either directly or indirectly mentioned in this project, belong to their respective owners. 90 | 91 | # Useful Resources 92 | The AdvancedHMI website [forum](https://www.advancedhmi.com/forum/), which is another open source project. 93 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ModbusSlaveSimulation.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ModbusSlaveSimulation.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap DarkBlue { 67 | get { 68 | object obj = ResourceManager.GetObject("DarkBlue", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap FunctionCodes { 77 | get { 78 | object obj = ResourceManager.GetObject("FunctionCodes", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Byte[]. 85 | /// 86 | internal static byte[] log4net { 87 | get { 88 | object obj = ResourceManager.GetObject("log4net", resourceCulture); 89 | return ((byte[])(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap Logo { 97 | get { 98 | object obj = ResourceManager.GetObject("Logo", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Byte[]. 105 | /// 106 | internal static byte[] Modbus { 107 | get { 108 | object obj = ResourceManager.GetObject("Modbus", resourceCulture); 109 | return ((byte[])(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). 115 | /// 116 | internal static System.Drawing.Icon ModbusRTUTCP { 117 | get { 118 | object obj = ResourceManager.GetObject("ModbusRTUTCP", resourceCulture); 119 | return ((System.Drawing.Icon)(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Looks up a localized string similar to NModbus 125 | /// 126 | ///What is it? 127 | ///----------- 128 | ///NModbus is a C# 3.0 implementation of the Modbus protocol. 129 | /// 130 | ///More information at the NModbus project web site http://nmodbus.com/ 131 | /// 132 | /// 133 | ///The Latest Version 134 | ///------------------ 135 | ///The latest binary distribution can be found on the NModbus project web site http://nmodbus.com/ 136 | /// 137 | ///The latest source for the project can be found at the NModbus project's google code page http://code.google.com/p/nmodbus/ 138 | /// 139 | /// 140 | ///Documentation 141 | ///------------- 142 | ///Documentation is available in chm forma [rest of string was truncated]";. 143 | /// 144 | internal static string README { 145 | get { 146 | return ResourceManager.GetString("README", resourceCulture); 147 | } 148 | } 149 | 150 | /// 151 | /// Looks up a localized resource of type System.Byte[]. 152 | /// 153 | internal static byte[] Unme_Common { 154 | get { 155 | object obj = ResourceManager.GetObject("Unme_Common", resourceCulture); 156 | return ((byte[])(obj)); 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\DarkBlue.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\Resources\FunctionCodes.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\Resources\log4net.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | ..\Resources\Logo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 132 | 133 | 134 | ..\Resources\Modbus.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 135 | 136 | 137 | ..\Resources\ModbusRTUTCP.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 138 | 139 | 140 | ..\Resources\README.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 141 | 142 | 143 | ..\Resources\Unme.Common.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 144 | 145 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Form1.cs: -------------------------------------------------------------------------------- 1 | // * This program is just another implementation of Modbus protocol in the form of a standalone Modbus Slave application 2 | // * supporting RTU/TCP/UDP/ASCIIoverRTU protocols. 3 | // * 4 | // * It is using modified nModbus .NET 3.5 libraries, Copyright (c) 2006 Scott Alexander ( https://code.google.com/p/nmodbus/ ), 5 | // * licensed under MIT license ( http://opensource.org/licenses/mit-license.php ) and included in the Project. 6 | // * See the README.txt file in the "Resources" folder. 7 | // * 8 | // * DataStore can be used to set values even before the connection is established. 9 | // * 10 | // * The slave is set to listen and communicate on a separate background thread in order to prevent GUI from freezing up. 11 | // * 12 | // * Register values are read and written to by the master as signed integer range -32768 to 32767. 13 | // * DataGridView is storing those same values as unsigned integer 0 to 65535 values. 14 | // * 15 | // * The program appears to be fully functional but provided AS IS (feel free to modify it but preserve all these comments). 16 | // * 17 | // * This particular version was coded in C# and designed for use in Windows and will not work as such in Mono. 18 | // * RTU/ASCIIoverRTU Modes could be used together with com0com Windows program to provide virtual serial port pairs. 19 | // * 20 | // * Since the DataGridView controls, used to display register values within the simulator window, seem to require 21 | // * rather fast computer, all instances were limited to initially have only 20 rows thus limiting the number of visible 22 | // * addresses (which should still be sufficient for simulation but can be changed via the combo box). 23 | // * 24 | // * There is also a TextBox added to allow manual input of the serial port to be used (generally for Linux usage). 25 | // * 26 | // * Currently, the simulator will service requests addressed to any slave. 27 | // * All requests will still be accessing the same data store. 28 | 29 | using Modbus.Data; 30 | using Modbus.Device; 31 | using System; 32 | using System.Drawing; 33 | using System.IO.Ports; 34 | using System.Net.Sockets; 35 | using System.Threading; 36 | using System.Net; 37 | using System.Windows.Forms; 38 | 39 | namespace ModbusSlaveSimulation 40 | { 41 | public partial class Form1 : Form 42 | { 43 | private SerialPort SerPort; 44 | private TcpListener ListenerTCP; 45 | private UdpClient ClientUDP; 46 | private ModbusSlave slave; 47 | private readonly DataStore dataStore; 48 | private readonly byte unitID = 1; 49 | private readonly Form formEditValue = new Form(); //<-| 50 | private readonly TextBox formTextbox = new TextBox(); //<-| Used to edit InputRegisters and HoldingRegisters values 51 | private readonly Button formButtonOK = new Button(); //<-| 52 | private int cellRowIndex; 53 | private int cellColIndex; 54 | private bool enableMessages = true; 55 | private bool dgvCDSet; 56 | private bool dgvIDSet; 57 | private bool dgvIRSet; 58 | private bool dgvHRSet; 59 | private Thread bckgndThread; 60 | private readonly ToolTip AllToolTip = new ToolTip(); 61 | 62 | private delegate void ListMasterRequestsCallback(string strRequest); 63 | private delegate void UpdateCoilDiscretes(int slave, int index, string value); 64 | private delegate void UpdateInputDiscretes(int slave, int index, string value); 65 | private delegate void UpdateInputRegisters(int slave, int index, string value); 66 | private delegate void UpdateHoldingRegisters(int slave, int index, string value); 67 | 68 | private static bool IsNumeric(string value) => int.TryParse(value, out _); 69 | 70 | #region "Constructor" 71 | 72 | public Form1() 73 | { 74 | InitializeComponent(); 75 | 76 | SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.SupportsTransparentBackColor, true); 77 | 78 | FormClosing += Form1_FormClosing; 79 | Load += Form1_Load; 80 | 81 | btnCloseRTUASCII.BackColor = Color.Gainsboro; 82 | btnCloseTCPUDP.BackColor = Color.Gainsboro; 83 | 84 | ModbusSlave.ModbusSlaveMessageReceived += ModbusMessageReceived; 85 | 86 | dataStore = DataStoreFactory.CreateDefaultDataStore(); 87 | dataStore.DataStoreReadFrom += DataStoreReadFrom; 88 | dataStore.DataStoreWrittenTo += DataStoreWriteTo; 89 | 90 | cbRowCount.SelectedIndex = 0; 91 | cbCommMode.SelectedIndex = 0; 92 | 93 | dgvCD.ColumnCount = 17; 94 | dgvID.ColumnCount = 17; 95 | dgvHR.ColumnCount = 11; 96 | dgvIR.ColumnCount = 11; 97 | 98 | formButtonOK.DialogResult = DialogResult.OK; 99 | formButtonOK.Text = "OK"; 100 | formEditValue.Name = "Set Value"; 101 | formEditValue.Text = "Set Value"; 102 | formEditValue.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 103 | formEditValue.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 104 | formEditValue.AcceptButton = formButtonOK; 105 | formEditValue.BackgroundImage = ModbusSlaveSimulation.Properties.Resources.DarkBlue; 106 | formEditValue.Icon = ModbusSlaveSimulation.Properties.Resources.ModbusRTUTCP; 107 | formEditValue.BackgroundImageLayout = ImageLayout.Stretch; 108 | formEditValue.Size = new Size(180, 100); 109 | formEditValue.MinimumSize = new Size(180, 100); 110 | formEditValue.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 111 | formEditValue.MinimizeBox = false; 112 | formEditValue.MaximizeBox = false; 113 | formEditValue.Controls.Add(formTextbox); 114 | formEditValue.Controls.Add(formButtonOK); 115 | formTextbox.Size = new Size(60, 25); 116 | formTextbox.MaxLength = 5; 117 | formTextbox.Location = new Point(25, 25); 118 | formButtonOK.Size = new Size(52, 25); 119 | formButtonOK.Location = new Point(formTextbox.Width + 35, 23); 120 | formButtonOK.FlatStyle = FlatStyle.Standard; 121 | formButtonOK.UseVisualStyleBackColor = false; 122 | formButtonOK.BackColor = Color.Gainsboro; 123 | formButtonOK.BringToFront(); 124 | 125 | formEditValue.Load += FormEditValue_Load; 126 | formButtonOK.Click += FormButtonOK_Click; 127 | formButtonOK.MouseHover += FormButtonOK_MouseHover; 128 | } 129 | 130 | #endregion 131 | 132 | #region "Requests / Updates" 133 | 134 | private void MasterRequests(object sender, ModbusSlaveRequestEventArgs e) 135 | { 136 | if (enableMessages) 137 | ListMasterRequests(e.Message.ToString()); 138 | } 139 | 140 | private void ListMasterRequests(string str) 141 | { 142 | if (InvokeRequired) 143 | Invoke(new ListMasterRequestsCallback(ListMasterRequests), new object[] { str }); 144 | else 145 | { 146 | ListBox1.Items.Add(str); // Add and show requests in the application window 147 | 148 | if (ListBox1.Items.Count > 2048) 149 | ListBox1.Items.RemoveAt(0); 150 | 151 | ListBox1.SelectedIndex = ListBox1.Items.Count - 1; 152 | } 153 | } 154 | 155 | private void UpdateCD(int slave, int index, string value) // Update CoilDiscretes values 156 | { 157 | if (index < 65535) 158 | { 159 | if (InvokeRequired) 160 | { 161 | Invoke(new UpdateCoilDiscretes(UpdateCD), new object[] { slave, index, value }); 162 | } 163 | else 164 | { 165 | if (value == "0") 166 | dataStore.CoilDiscretes[index + 1] = false; 167 | else 168 | dataStore.CoilDiscretes[index + 1] = true; 169 | 170 | int div = Math.DivRem(index, 16, out int reminder); 171 | 172 | if (!(div >= dgvCD.Rows.Count)) 173 | dgvCD.Rows[div].Cells[reminder + 1].Value = Convert.ToInt32(value); 174 | } 175 | } 176 | } 177 | 178 | private void UpdateID(int slave, int index, string value) // Update InputDiscretes values 179 | { 180 | if (index < 65535) 181 | { 182 | if (InvokeRequired) 183 | { 184 | Invoke(new UpdateInputDiscretes(UpdateID), new object[] { slave, index, value }); 185 | } 186 | else 187 | { 188 | if (value == "0") 189 | dataStore.InputDiscretes[index + 1] = false; 190 | else 191 | dataStore.InputDiscretes[index + 1] = true; 192 | 193 | int div = Math.DivRem(index, 16, out int reminder); 194 | 195 | if (!(div >= dgvID.Rows.Count)) 196 | dgvID.Rows[div].Cells[reminder + 1].Value = Convert.ToInt32(value); 197 | } 198 | } 199 | } 200 | 201 | private void UpdateIR(int slave, int index, string value) // Update InputRegisters values 202 | { 203 | if (index < 65535) 204 | { 205 | if (InvokeRequired) 206 | { 207 | Invoke(new UpdateInputRegisters(UpdateIR), new object[] { slave, index, value }); 208 | } 209 | else 210 | { 211 | dataStore.InputRegisters[index + 1] = Convert.ToUInt16(value); 212 | 213 | int div = Math.DivRem(index, 10, out int reminder); 214 | 215 | if (!(div >= dgvIR.Rows.Count)) 216 | dgvIR.Rows[div].Cells[reminder + 1].Value = value; 217 | } 218 | } 219 | } 220 | 221 | private void UpdateHR(int slave, int index, string value) // Update HoldingRegisters values 222 | { 223 | if (index < 65535) 224 | { 225 | if (InvokeRequired) 226 | { 227 | Invoke(new UpdateHoldingRegisters(UpdateHR), new object[] { slave, index, value }); 228 | } 229 | else 230 | { 231 | dataStore.HoldingRegisters[index + 1] = Convert.ToUInt16(value); 232 | 233 | int div = Math.DivRem(index, 10, out int reminder); 234 | 235 | if (!(div >= dgvHR.Rows.Count)) 236 | dgvHR.Rows[div].Cells[reminder + 1].Value = value; 237 | } 238 | } 239 | } 240 | 241 | #endregion 242 | 243 | #region "DataStore" 244 | 245 | private void DataStoreReadFrom(object sender, DataStoreEventArgs e) 246 | { 247 | switch (e.ModbusDataType) 248 | { 249 | case ModbusDataType.Coil: 250 | // Read CoilDiscretes values 251 | // add code here 252 | break; 253 | case ModbusDataType.Input: 254 | // Read InputDiscretes values 255 | // add code here 256 | break; 257 | case ModbusDataType.InputRegister: 258 | // Read InputRegisters values 259 | // add code here 260 | break; 261 | case ModbusDataType.HoldingRegister: 262 | // Read HoldingRegisters values 263 | // add code here 264 | break; 265 | } 266 | 267 | if (lblMessage.Text != "Comms Okay") 268 | lblMessage.Invoke((MethodInvoker)delegate { lblMessage.Text = "Comms Okay"; }); 269 | } 270 | 271 | private void DataStoreWriteTo(object sender, DataStoreEventArgs e) 272 | { 273 | int address = e.StartAddress; 274 | 275 | switch (e.ModbusDataType) 276 | { 277 | case ModbusDataType.Coil: 278 | // Write CoilDiscretes values 279 | for (int i = 0; i <= e.Data.A.Count - 1; i++) 280 | { 281 | if (e.Data.A[i]) 282 | UpdateCD(1, address, "1"); 283 | else 284 | UpdateCD(1, address, "0"); 285 | 286 | address += 1; 287 | } 288 | 289 | break; 290 | case ModbusDataType.HoldingRegister: 291 | // Write HoldingRegisters values 292 | for (int i = 0; i <= e.Data.B.Count - 1; i++) 293 | { 294 | UpdateHR(1, address, e.Data.B[i].ToString()); 295 | address += 1; 296 | } 297 | 298 | break; 299 | } 300 | 301 | if (lblMessage.Text != "Comms Okay") 302 | lblMessage.Invoke((MethodInvoker)delegate { lblMessage.Text = "Comms Okay"; }); 303 | } 304 | 305 | #endregion 306 | 307 | #region "DataGridView" 308 | 309 | //CoilDiscretes (Digital Outputs - I/O Address Range 000000) 310 | private void DataGridViewCD_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) 311 | { 312 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 4095 && e.ColumnIndex == 16)) 313 | return; 314 | 315 | lblCellNumber.Text = (Convert.ToInt32(dgvCD.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, 6)) + e.ColumnIndex - 1).ToString().PadLeft(6, '0'); 316 | } 317 | 318 | private void DataGridViewCD_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) 319 | { 320 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 4095 && e.ColumnIndex == 16)) 321 | return; 322 | 323 | dgvCD.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Convert.ToInt32(!Convert.ToBoolean(dgvCD.Rows[e.RowIndex].Cells[e.ColumnIndex].Value)); 324 | UpdateCD(1, Convert.ToInt32(16 * e.RowIndex + e.ColumnIndex - 1), dgvCD.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()); 325 | } 326 | 327 | //InputDiscretes (Digital Inputs - I/O Address Range 100000) 328 | private void DataGridViewID_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) 329 | { 330 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 4095 && e.ColumnIndex == 16)) 331 | return; 332 | 333 | lblCellNumber.Text = (Convert.ToInt32(dgvID.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, 6)) + e.ColumnIndex - 1).ToString(); 334 | } 335 | 336 | private void DataGridViewID_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) 337 | { 338 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 4095 && e.ColumnIndex == 16)) 339 | return; 340 | 341 | dgvID.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Convert.ToInt32(!Convert.ToBoolean(dgvID.Rows[e.RowIndex].Cells[e.ColumnIndex].Value)); 342 | UpdateID(1, Convert.ToInt32(16 * e.RowIndex + e.ColumnIndex - 1), dgvID.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()); 343 | } 344 | 345 | //InputRegisters (Analog Inputs - I/O Address range 300000) 346 | private void DataGridViewIR_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) 347 | { 348 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 6553 && e.ColumnIndex > 5)) 349 | return; 350 | 351 | lblCellNumber.Text = (Convert.ToInt32(dgvIR.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, 6)) + e.ColumnIndex - 1).ToString(); 352 | } 353 | 354 | private void DataGridViewIR_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) 355 | { 356 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 6553 && e.ColumnIndex > 5)) 357 | return; 358 | 359 | cellRowIndex = e.RowIndex; 360 | cellColIndex = e.ColumnIndex; 361 | 362 | DialogResult dr = formEditValue.ShowDialog(); 363 | 364 | if (dr == DialogResult.OK) 365 | { 366 | if (IsNumeric(formTextbox.Text)) 367 | { 368 | if (Convert.ToInt32(formTextbox.Text) < 0 || Convert.ToInt32(formTextbox.Text) > 65535) 369 | { 370 | MessageBox.Show("The value must be integer number 0 to 65535!"); 371 | formTextbox.Text = ""; 372 | return; 373 | } 374 | 375 | dgvIR.Rows[cellRowIndex].Cells[cellColIndex].Value = formTextbox.Text; 376 | UpdateIR(1, 10 * cellRowIndex + cellColIndex - 1, dgvIR.Rows[cellRowIndex].Cells[cellColIndex].Value.ToString()); 377 | } 378 | else 379 | MessageBox.Show("The value must be integer number 0 to 65535!"); 380 | 381 | formTextbox.Text = ""; 382 | formEditValue.Hide(); 383 | } 384 | } 385 | 386 | //Holding Registers (Analog Outputs - I/O Address Range 400000) 387 | private void DataGridViewHR_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) 388 | { 389 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 6553 && e.ColumnIndex > 5)) 390 | return; 391 | 392 | lblCellNumber.Text = (Convert.ToInt32(dgvHR.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, 6)) + e.ColumnIndex - 1).ToString(); 393 | } 394 | 395 | private void DataGridViewHR_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) 396 | { 397 | if (e.RowIndex == -1 || e.ColumnIndex == 0 || (e.RowIndex == 6553 && e.ColumnIndex > 5)) 398 | return; 399 | 400 | cellRowIndex = e.RowIndex; 401 | cellColIndex = e.ColumnIndex; 402 | 403 | DialogResult dr = formEditValue.ShowDialog(); 404 | 405 | if (dr == DialogResult.OK) 406 | { 407 | if (IsNumeric(formTextbox.Text)) 408 | { 409 | if (Convert.ToInt32(formTextbox.Text) < 0 || Convert.ToInt32(formTextbox.Text) > 65535) 410 | { 411 | MessageBox.Show("The value must be integer number 0 to 65535!"); 412 | return; 413 | } 414 | dgvHR.Rows[cellRowIndex].Cells[cellColIndex].Value = formTextbox.Text; 415 | UpdateHR(1, 10 * cellRowIndex + cellColIndex - 1, dgvHR.Rows[cellRowIndex].Cells[cellColIndex].Value.ToString()); 416 | } 417 | else 418 | MessageBox.Show("The value must be integer number 0 to 65535!"); 419 | 420 | formTextbox.Text = ""; 421 | formEditValue.Hide(); 422 | } 423 | } 424 | 425 | #endregion 426 | 427 | #region "Private Methods" 428 | 429 | private void AddRowsColumnsdgvCD(int RowCount) 430 | { 431 | if (!dgvCDSet) 432 | { 433 | // Set address column labels and set all valid cell values to dataStore values 434 | for (int i = 0; i <= RowCount - 1; i++) 435 | { 436 | if (i < 17) 437 | dgvCD.Columns[i].HeaderCell.Style.BackColor = Color.LightSeaGreen; 438 | 439 | for (int j = 0; j <= 16; j++) 440 | { 441 | if (i == 4095 && j > 15) 442 | break; 443 | 444 | if (j == 0) 445 | { 446 | //Show address range up to 065535 447 | if (i == 4095) 448 | dgvCD.Rows[i].Cells[j].Value = "0" + (16 * i + 1).ToString().PadLeft(5, '0') + "-" + "0" + (16 * i + 15).ToString().PadLeft(5, '0'); 449 | else 450 | dgvCD.Rows[i].Cells[j].Value = "0" + (16 * i + 1).ToString().PadLeft(5, '0') + "-" + "0" + (16 * i + 16).ToString().PadLeft(5, '0'); 451 | } 452 | else 453 | { 454 | if (dataStore.CoilDiscretes[i * 16 + j]) 455 | dgvCD.Rows[i].Cells[j].Value = 1; 456 | else 457 | dgvCD.Rows[i].Cells[j].Value = 0; 458 | } 459 | } 460 | } 461 | dgvCDSet = true; 462 | } 463 | } 464 | 465 | private void AddRowsColumnsdgvID(int RowCount) 466 | { 467 | if (!dgvIDSet) 468 | { 469 | // Set address column labels and set all valid cell values to dataStore values 470 | for (int i = 0; i <= RowCount - 1; i++) 471 | { 472 | if (i < 17) 473 | dgvID.Columns[i].HeaderCell.Style.BackColor = Color.SeaGreen; 474 | 475 | for (int j = 0; j <= 16; j++) 476 | { 477 | if (i == 4095 && j > 15) 478 | break; 479 | 480 | if (j == 0) 481 | { 482 | //Show address range up to 165535 483 | if (i == 4095) 484 | dgvID.Rows[i].Cells[j].Value = "1" + (16 * i + 1).ToString().PadLeft(5, '0') + "-" + "1" + (16 * i + 15).ToString().PadLeft(5, '0'); 485 | else 486 | dgvID.Rows[i].Cells[j].Value = "1" + (16 * i + 1).ToString().PadLeft(5, '0') + "-" + "1" + (16 * i + 16).ToString().PadLeft(5, '0'); 487 | } 488 | else 489 | { 490 | if (dataStore.InputDiscretes[i * 16 + j]) 491 | dgvID.Rows[i].Cells[j].Value = 1; 492 | else 493 | dgvID.Rows[i].Cells[j].Value = 0; 494 | } 495 | } 496 | } 497 | dgvIDSet = true; 498 | } 499 | } 500 | 501 | private void AddRowsColumnsdgvIR(int RowCount) 502 | { 503 | if (!dgvIRSet) 504 | { 505 | // Set address column labels and set all valid cell values to dataStore values 506 | for (int i = 0; i <= RowCount - 1; i++) 507 | { 508 | if (i < 11) 509 | dgvIR.Columns[i].HeaderCell.Style.BackColor = Color.SteelBlue; 510 | 511 | for (int j = 0; j <= 10; j++) 512 | { 513 | if (i == 6553 && j > 5) 514 | break; 515 | 516 | if (j == 0) 517 | { 518 | //Show address range up to 365535 519 | if (i == 6553) 520 | dgvIR.Rows[i].Cells[j].Value = "3" + (10 * i + 1).ToString().PadLeft(5, '0') + "-" + "3" + (10 * i + 5).ToString().PadLeft(5, '0'); 521 | else 522 | dgvIR.Rows[i].Cells[j].Value = "3" + (10 * i + 1).ToString().PadLeft(5, '0') + "-" + "3" + (10 * i + 10).ToString().PadLeft(5, '0'); 523 | } 524 | else 525 | dgvIR.Rows[i].Cells[j].Value = dataStore.InputRegisters[i * 10 + j]; 526 | } 527 | } 528 | dgvIRSet = true; 529 | } 530 | } 531 | 532 | private void AddRowsColumnsdgvHR(int RowCount) 533 | { 534 | if (!dgvHRSet) 535 | { 536 | // Set address column labels and set all valid cell values to dataStore values 537 | for (int i = 0; i <= RowCount - 1; i++) 538 | { 539 | if (i < 11) 540 | dgvHR.Columns[i].HeaderCell.Style.BackColor = Color.LightSteelBlue; 541 | 542 | for (int j = 0; j <= 10; j++) 543 | { 544 | if (i == 6553 && j > 5) 545 | break; 546 | 547 | if (j == 0) 548 | { 549 | //Show address range up to 465535 550 | if (i == 6553) 551 | dgvHR.Rows[i].Cells[j].Value = "4" + (10 * i + 1).ToString().PadLeft(5, '0') + "-" + "4" + (10 * i + 5).ToString().PadLeft(5, '0'); 552 | else 553 | dgvHR.Rows[i].Cells[j].Value = "4" + (10 * i + 1).ToString().PadLeft(5, '0') + "-" + "4" + (10 * i + 10).ToString().PadLeft(5, '0'); 554 | } 555 | else 556 | dgvHR.Rows[i].Cells[j].Value = dataStore.HoldingRegisters[i * 10 + j]; 557 | } 558 | } 559 | dgvHRSet = true; 560 | } 561 | } 562 | 563 | private void Form1_Load(object sender, EventArgs e) 564 | { 565 | cbBaud.SelectedIndex = 15; 566 | cbDataBits.SelectedIndex = 3; 567 | cbParity.SelectedIndex = 0; 568 | cbStopBits.SelectedIndex = 0; 569 | 570 | GetSerialPorts(); 571 | 572 | btnCloseRTUASCII.Enabled = false; 573 | 574 | cbIO.SelectedIndex = 0; 575 | 576 | dgvCD.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 577 | dgvID.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 578 | dgvHR.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 579 | dgvIR.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 580 | AddRowsColumnsdgvCD(Convert.ToInt32(cbRowCount.SelectedItem)); 581 | AddRowsColumnsdgvID(Convert.ToInt32(cbRowCount.SelectedItem)); 582 | AddRowsColumnsdgvIR(Convert.ToInt32(cbRowCount.SelectedItem)); 583 | AddRowsColumnsdgvHR(Convert.ToInt32(cbRowCount.SelectedItem)); 584 | 585 | Focus(); 586 | } 587 | 588 | private void Form1_FormClosing(object sender, FormClosingEventArgs e) 589 | { 590 | if (bckgndThread != null) 591 | { 592 | if (bckgndThread.IsAlive) 593 | bckgndThread.Join(10); 594 | 595 | bckgndThread = null; 596 | } 597 | 598 | if (SerPort != null) 599 | { 600 | if (SerPort.IsOpen) 601 | { 602 | SerPort.DiscardInBuffer(); 603 | SerPort.DiscardOutBuffer(); 604 | SerPort.Close(); 605 | } 606 | 607 | SerPort.Dispose(); 608 | } 609 | 610 | if (formEditValue != null) 611 | { 612 | formEditValue.Close(); 613 | formEditValue.Dispose(); 614 | } 615 | } 616 | 617 | private void FormEditValue_Load(object sender, EventArgs e) 618 | { 619 | formTextbox.Focus(); 620 | } 621 | 622 | private void FormButtonOK_Click(object sender, EventArgs e) 623 | { 624 | formEditValue.DialogResult = DialogResult.OK; 625 | } 626 | 627 | private void FormButtonOK_MouseHover(object sender, EventArgs e) 628 | { 629 | formTextbox.Focus(); 630 | } 631 | 632 | private void ButtonOpenRTUASCII_Click(object sender, EventArgs e) 633 | { 634 | SerPort = new SerialPort(); 635 | 636 | if (!string.IsNullOrWhiteSpace(tbManualCOM.Text)) 637 | SerPort.PortName = tbManualCOM.Text; 638 | else 639 | SerPort.PortName = cbPort.SelectedItem.ToString(); 640 | 641 | SerPort.BaudRate = Convert.ToInt32(cbBaud.SelectedItem.ToString()); 642 | SerPort.Parity = (Parity)cbParity.SelectedIndex; 643 | SerPort.DataBits = Convert.ToInt32(cbDataBits.SelectedItem.ToString()); 644 | SerPort.StopBits = (StopBits)cbStopBits.SelectedIndex + 1; 645 | SerPort.Handshake = Handshake.None; 646 | SerPort.DtrEnable = true; 647 | SerPort.RtsEnable = true; 648 | 649 | try 650 | { 651 | SerPort.Open(); 652 | } 653 | catch (Exception ex) 654 | { 655 | MessageBox.Show(ex.ToString()); 656 | return; 657 | } 658 | 659 | if (cbCommMode.SelectedIndex == 0) //RTU 660 | slave = ModbusSerialSlave.CreateRtu(unitID, SerPort); 661 | else if (cbCommMode.SelectedIndex == 3) //ASCIIoverRTU 662 | slave = ModbusSerialSlave.CreateAscii(unitID, SerPort); 663 | 664 | slave.ModbusSlaveRequestReceived += MasterRequests; 665 | slave.DataStore = dataStore; 666 | 667 | btnOpenRTUASCII.Enabled = false; 668 | btnOpenRTUASCII.BackColor = Color.Gainsboro; 669 | btnCloseRTUASCII.Enabled = true; 670 | btnCloseRTUASCII.BackColor = Color.LightSteelBlue; 671 | btnRefresh.Enabled = false; 672 | btnRefresh.BackColor = Color.Gainsboro; 673 | 674 | cbPort.Enabled = false; 675 | cbBaud.Enabled = false; 676 | cbDataBits.Enabled = false; 677 | cbParity.Enabled = false; 678 | cbStopBits.Enabled = false; 679 | cbCommMode.Enabled = false; 680 | cbRowCount.Enabled = false; 681 | tbManualCOM.Enabled = false; 682 | 683 | bckgndThread = new Thread(BckgndThreadTask) { IsBackground = true }; 684 | bckgndThread.Start(); 685 | } 686 | 687 | private void ButtonOpenTCPUDP_Click(object sender, EventArgs e) 688 | { 689 | int tcpPort = int.Parse(tbPort.Text); 690 | IPAddress ipAddr = new IPAddress(0); 691 | IPHostEntry IPHE = null; 692 | try 693 | { 694 | if (IPAddress.TryParse(tbIP.Text, out ipAddr)) 695 | { 696 | if (cbCommMode.SelectedIndex == 1) //TCP 697 | ListenerTCP = new TcpListener(ipAddr, tcpPort); 698 | else if (cbCommMode.SelectedIndex == 2) //UDP 699 | ClientUDP = new UdpClient(new IPEndPoint(ipAddr, tcpPort)); 700 | } 701 | else 702 | { 703 | IPHE = Dns.GetHostEntry(tbIP.Text); 704 | 705 | if (cbCommMode.SelectedIndex == 1) //TCP 706 | ListenerTCP = new TcpListener(IPHE.AddressList[1], tcpPort); 707 | else if (cbCommMode.SelectedIndex == 2) //UDP 708 | ClientUDP = new UdpClient(new IPEndPoint(IPHE.AddressList[1], tcpPort)); 709 | } 710 | } 711 | catch (Exception) 712 | { 713 | MessageBox.Show("Invalid IP address or hostname!"); 714 | return; 715 | } 716 | 717 | if (cbCommMode.SelectedIndex == 1) //TCP 718 | slave = ModbusTcpSlave.CreateTcp(unitID, ListenerTCP); 719 | else if (cbCommMode.SelectedIndex == 2) //UDP 720 | slave = ModbusUdpSlave.CreateUdp(unitID, ClientUDP); 721 | 722 | slave.ModbusSlaveRequestReceived += MasterRequests; 723 | slave.DataStore = dataStore; 724 | 725 | btnOpenTCPUDP.Enabled = false; 726 | btnOpenTCPUDP.BackColor = Color.Gainsboro; 727 | 728 | btnCloseTCPUDP.Enabled = true; 729 | btnCloseTCPUDP.BackColor = Color.LightSteelBlue; 730 | 731 | tbIP.Enabled = false; 732 | tbPort.Enabled = false; 733 | cbCommMode.Enabled = false; 734 | cbRowCount.Enabled = false; 735 | 736 | bckgndThread = new Thread(BckgndThreadTask) { IsBackground = true }; 737 | bckgndThread.Start(); 738 | } 739 | 740 | private void ButtonCloseRTUASCII_Click(object sender, EventArgs e) 741 | { 742 | if (SerPort != null) 743 | { 744 | if (SerPort.IsOpen) 745 | { 746 | SerPort.DiscardInBuffer(); 747 | SerPort.DiscardOutBuffer(); 748 | SerPort.Close(); 749 | } 750 | 751 | SerPort.Dispose(); 752 | } 753 | 754 | if (slave != null) 755 | { 756 | slave.Transport.Dispose(); 757 | slave.StopListen(); 758 | slave.Dispose(); 759 | } 760 | 761 | btnOpenRTUASCII.Enabled = true; 762 | btnOpenRTUASCII.BackColor = Color.LightSteelBlue; 763 | 764 | btnCloseRTUASCII.Enabled = false; 765 | btnCloseRTUASCII.BackColor = Color.Gainsboro; 766 | 767 | btnRefresh.Enabled = true; 768 | btnRefresh.BackColor = Color.LightSteelBlue; 769 | 770 | cbPort.Enabled = true; 771 | cbBaud.Enabled = true; 772 | cbDataBits.Enabled = true; 773 | cbParity.Enabled = true; 774 | cbStopBits.Enabled = true; 775 | cbCommMode.Enabled = true; 776 | cbRowCount.Enabled = true; 777 | tbManualCOM.Enabled = true; 778 | } 779 | 780 | private void ButtonCloseTCPUDP_Click(object sender, EventArgs e) 781 | { 782 | if (slave != null) 783 | { 784 | slave.Transport.Dispose(); 785 | slave.StopListen(); 786 | slave.Dispose(); 787 | } 788 | 789 | btnOpenTCPUDP.Enabled = true; 790 | btnOpenTCPUDP.BackColor = Color.LightSteelBlue; 791 | btnCloseTCPUDP.Enabled = false; 792 | btnCloseTCPUDP.BackColor = Color.Gainsboro; 793 | 794 | tbIP.Enabled = true; 795 | tbPort.Enabled = true; 796 | cbCommMode.Enabled = true; 797 | cbRowCount.Enabled = true; 798 | } 799 | 800 | private void BckgndThreadTask() 801 | { 802 | try 803 | { 804 | slave.Listen(); 805 | } 806 | catch (Exception) 807 | { 808 | } 809 | 810 | bckgndThread = null; 811 | } 812 | 813 | private void ButtonRefresh_Click(object sender, EventArgs e) 814 | { 815 | GetSerialPorts(); 816 | } 817 | 818 | private void GetSerialPorts() 819 | { 820 | string[] portnames = SerialPort.GetPortNames(); 821 | cbPort.Items.Clear(); 822 | 823 | if (portnames.Length == 0) 824 | { 825 | cbPort.Items.Add("none found"); 826 | btnOpenRTUASCII.Enabled = false; 827 | } 828 | else 829 | { 830 | foreach (string sPort in portnames) 831 | { 832 | cbPort.Items.Add(sPort); 833 | } 834 | 835 | btnOpenRTUASCII.Enabled = true; 836 | } 837 | 838 | cbPort.Sorted = true; 839 | cbPort.SelectedIndex = 0; 840 | } 841 | 842 | private void ComboBoxIO_SelectedIndexChanged(object sender, EventArgs e) 843 | { 844 | if (cbIO.SelectedIndex == 0) 845 | dgvCD.BringToFront(); 846 | else if (cbIO.SelectedIndex == 1) 847 | dgvID.BringToFront(); 848 | else if (cbIO.SelectedIndex == 2) 849 | dgvIR.BringToFront(); 850 | else 851 | dgvHR.BringToFront(); 852 | 853 | lblCellNumber.Text = ""; 854 | Invalidate(); 855 | } 856 | 857 | private void ComboBoxRowCount_SelectedIndexChanged(object sender, EventArgs e) 858 | { 859 | dgvCDSet = false; 860 | dgvIDSet = false; 861 | dgvIRSet = false; 862 | dgvHRSet = false; 863 | 864 | if (cbRowCount.SelectedItem.ToString() == "MAX") 865 | { 866 | dgvCD.RowCount = 4096; 867 | dgvID.RowCount = 4096; 868 | dgvHR.RowCount = 6554; 869 | dgvIR.RowCount = 6554; 870 | AddRowsColumnsdgvCD(4096); 871 | AddRowsColumnsdgvID(4096); 872 | AddRowsColumnsdgvIR(6554); 873 | AddRowsColumnsdgvHR(6554); 874 | } 875 | else 876 | { 877 | dgvCD.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 878 | dgvID.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 879 | dgvHR.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 880 | dgvIR.RowCount = Convert.ToInt32(cbRowCount.SelectedItem); 881 | AddRowsColumnsdgvCD(Convert.ToInt32(cbRowCount.SelectedItem)); 882 | AddRowsColumnsdgvID(Convert.ToInt32(cbRowCount.SelectedItem)); 883 | AddRowsColumnsdgvIR(Convert.ToInt32(cbRowCount.SelectedItem)); 884 | AddRowsColumnsdgvHR(Convert.ToInt32(cbRowCount.SelectedItem)); 885 | } 886 | 887 | Invalidate(); 888 | } 889 | 890 | private void ComboBoxCommMode_SelectedIndexChanged(object sender, EventArgs e) 891 | { 892 | if (cbCommMode.SelectedIndex == 0 || cbCommMode.SelectedIndex == 3) //RTU or ASCIIoverRTU 893 | { 894 | gbRTU.Enabled = true; 895 | gbRTU.BringToFront(); 896 | gbTCP.Enabled = false; 897 | gbTCP.SendToBack(); 898 | } 899 | else //TCP or UDP 900 | { 901 | gbTCP.Enabled = true; 902 | gbTCP.BringToFront(); 903 | gbRTU.Enabled = false; 904 | gbRTU.SendToBack(); 905 | } 906 | } 907 | 908 | private void ListBox1_DoubleClick(object sender, EventArgs e) 909 | { 910 | enableMessages = !enableMessages; 911 | } 912 | 913 | private void CheckBox1_CheckedChanged(object sender, EventArgs e) 914 | { 915 | if (CheckBox1.Checked) 916 | ListBox1.Show(); 917 | else 918 | { 919 | ListBox1.Hide(); 920 | ListBox1.Items.Clear(); 921 | } 922 | } 923 | 924 | private void TextBoxManualCOM_TextChanged(object sender, EventArgs e) 925 | { 926 | if (!string.IsNullOrWhiteSpace(tbManualCOM.Text)) 927 | btnOpenRTUASCII.Enabled = true; 928 | else 929 | btnOpenRTUASCII.Enabled = false; 930 | } 931 | 932 | private void ModbusMessageReceived(object sender, Modbus.ModbusMessagesEventArgs e) 933 | { 934 | if (e.Message == "Master closed Socket connection.") 935 | { 936 | slave.StopListen(); 937 | slave.Listen(); 938 | } 939 | 940 | if (lblMessage.InvokeRequired) 941 | lblMessage.Invoke((MethodInvoker)delegate { lblMessage.Text = e.Message; }); 942 | else 943 | lblMessage.Text = e.Message; 944 | } 945 | 946 | #endregion 947 | 948 | #region "ToolTips" 949 | 950 | private void ButtonCloseRTUASCII_MouseHover(object sender, EventArgs e) 951 | { 952 | if (btnCloseRTUASCII.Enabled) 953 | AllToolTip.SetToolTip(btnCloseRTUASCII, "Close serial port."); 954 | } 955 | 956 | private void ButtonOpenRTUASCII_MouseHover(object sender, EventArgs e) 957 | { 958 | if (btnOpenRTUASCII.Enabled) 959 | AllToolTip.SetToolTip(btnOpenRTUASCII, "Open serial port with currently selected parameters."); 960 | } 961 | 962 | private void ButtonRefresh_MouseHover(object sender, EventArgs e) 963 | { 964 | AllToolTip.SetToolTip(btnRefresh, "Refresh serial ports list."); 965 | } 966 | 967 | private void LabelManual_MouseHover(object sender, EventArgs e) 968 | { 969 | AllToolTip.SetToolTip(lblManual, "Set COM port manually."); 970 | } 971 | 972 | private void LabelRowCount_MouseHover(object sender, EventArgs e) 973 | { 974 | AllToolTip.SetToolTip(lblRowCount, "Number of rows visible in the DataGridView."); 975 | } 976 | 977 | private void CheckBox1_MouseHover(object sender, EventArgs e) 978 | { 979 | AllToolTip.SetToolTip(CheckBox1, "Show/Hide messages window."); 980 | } 981 | 982 | private void GroupBoxFC_MouseHover(object sender, EventArgs e) 983 | { 984 | AllToolTip.SetToolTip(gbFC, "Function Code 15 - Write Multiple Coils" + Environment.NewLine + "Function Code 16 - Write Multiple Registers" + Environment.NewLine + "Function Code 22 - Masked Bit Write" + Environment.NewLine + "Function Code 23 - ReadWrite Multiple Registers"); 985 | } 986 | 987 | private void ListBox1_MouseHover(object sender, EventArgs e) 988 | { 989 | AllToolTip.SetToolTip(ListBox1, "Double click to pause showing incoming master request messages."); 990 | } 991 | 992 | private void PictureBox1_MouseHover(object sender, EventArgs e) 993 | { 994 | AllToolTip.SetToolTip(PictureBox1, "https://code.google.com/p/nmodbus/"); 995 | } 996 | 997 | #endregion 998 | } 999 | } 1000 | -------------------------------------------------------------------------------- /ModbusSlaveSimulation/Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | 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 200 | 201 | 202 | 203 | True 204 | 205 | 206 | True 207 | 208 | 209 | True 210 | 211 | 212 | True 213 | 214 | 215 | True 216 | 217 | 218 | True 219 | 220 | 221 | True 222 | 223 | 224 | True 225 | 226 | 227 | True 228 | 229 | 230 | True 231 | 232 | 233 | True 234 | 235 | 236 | True 237 | 238 | 239 | True 240 | 241 | 242 | True 243 | 244 | 245 | True 246 | 247 | 248 | True 249 | 250 | 251 | True 252 | 253 | 254 | True 255 | 256 | 257 | True 258 | 259 | 260 | True 261 | 262 | 263 | True 264 | 265 | 266 | True 267 | 268 | 269 | True 270 | 271 | 272 | True 273 | 274 | 275 | True 276 | 277 | 278 | True 279 | 280 | 281 | True 282 | 283 | 284 | True 285 | 286 | 287 | True 288 | 289 | 290 | True 291 | 292 | 293 | True 294 | 295 | 296 | True 297 | 298 | 299 | True 300 | 301 | 302 | True 303 | 304 | 305 | True 306 | 307 | 308 | True 309 | 310 | 311 | True 312 | 313 | 314 | True 315 | 316 | 317 | True 318 | 319 | 320 | True 321 | 322 | 323 | True 324 | 325 | 326 | True 327 | 328 | 329 | True 330 | 331 | 332 | True 333 | 334 | 335 | True 336 | 337 | 338 | True 339 | 340 | 341 | True 342 | 343 | 344 | True 345 | 346 | 347 | True 348 | 349 | 350 | True 351 | 352 | 353 | True 354 | 355 | 356 | True 357 | 358 | 359 | True 360 | 361 | 362 | True 363 | 364 | 365 | True 366 | 367 | 368 | True 369 | 370 | 371 | 372 | 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 636 | 637 | 638 | 639 | 640 | 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 705 | rkJggg== 706 | 707 | 708 | 709 | 710 | AAABAAEAICAQAAEABADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAAAAAAAAAAAAAAAAAA 711 | AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP// 712 | AAD///8AAADMzMwAAAAAAAAADMzAAAAAzMzMwAAAAAAAAAzMzAAADMwAAMwAAAAMwAAMzAzAAMzAAAAM 713 | wAAADMAADMwAwAzAAAAAAMwAAAzAAAzMAAwMwAAAAAAMwAAMzAAMzAAADAAAAAAAAMwADMzADMwAAMwA 714 | AAAAAADMAAzAwAzMAADAAAAAAAAADMAMwMwMzAAAwAAAAAAAAAzADMDMDMwAAMAAAAAAAAAAzAzADAzM 715 | AADAAAAAAAAAAMwMwAzMzAAAwAAAAAAAAAAMzMAAzMwAAMAAAAAAAAAADMzAAMzMAADAAAAAAAAAAADM 716 | wAAMzAAAzAAAAAAAAAAAzMAAAMwAAAwAAAAAAAwAAMzAAADMwAAMAAAAAADMAADMwAAAzMAADMAAAAAM 717 | wAAAzMAAAAzAAAzAAAAADMAAAMzAAAAAwAAAzAAADMAAAADMwAAAAMwAAMwAAAzAAAAAzMAAAADMAAAM 718 | zMzMAAAAAAzAAAAADMAAAMzMwAAAAAAMwAAAAAzAAAAAAAAAAAAADMAAAAAAzAAAAAAAAAAAAAzAAAAA 719 | AMwAAAAAAAAAAAAAwAAAAAAMAAAAAAAAAAAAAMAAAAAADAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAA 720 | wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwP/+H8B//g+PP54nH5+eNn/Pnjp/5 721 | 44+//OGPP/zlj3/+ZI9//mSPf/8mj3//Jg9//4cPf/+HD3//x48//8fPv/vHx7/zx8ef58fnn+fH98+f 722 | x/PPn8fz4D/n+fB/5/n//+f8///n/P//9/7///f+///3////9////////////w== 723 | 724 | 725 | --------------------------------------------------------------------------------