Modbus-TCP library for Netduino

Here we go, after a long delay, full of promises for releasing this software earlier. My apologies on that.

Introduction.

My job is developing software for industrial applications. In such a field, the typical machine is a PLC, and the data-center is a PC/Server. However, there are thousands of small applications where a PLC+PC is just an overkill, either from the cost perspective, but yet from the complexity.

A small board like Netduino is a concrete way to fit these applications with easiness at a decent cost. The quality isn’t comparable, of course, but not always we’re asking for aerospace-safety when the controlled target is our garden sprinkler. An heating regulation, a small supervisory control, and many other ideas can effectively be realized with just this small board.

I believed on a small yet versatile library of some common protocol. Who’s working in such a field, also knows that Modbus is one of the most used worldwide. It’s primitive, poor, but really simple to implement. That was the main reason for the Modbus success. So I’ve written this piece of software because there are people asking for small solutions, and here is another one.

This library is targeted for the .Net Micro Framework (.Net MF), and in particular for the Netduino. I’d say for the Plus version only, because the only feasible implementation is based on IP. The Ethernet way comes easy to use, and offers advantages in terms of diffusion. There would be a serial RS-485 solution (Modbus-RTU), but I’m not sure to make it working with the Netduino.

Please, have a look here about the Modbus protocol variants.

Introducing the library.

As describe further in this article, the library has been designed to be enough flexible, as well as scalable.
Features:

  • Support for Modbus-TCP and UDP;
  • Support for Class 0 and Class 1 commands;
  • Both Master and Slave, even together on the same application;
  • Multi-threaded management for multiple sessions;
  • Pluggable architecture, so that new commands can be added without polluting the main code;
  • Allows the implementation of other protocols, even packed-oriented;
  • Very easy to use;
  • Totally open-source, under the Apache 2.0 license;

Limitations/known problems:

  • There’s few checking on the data incoming/outgoing. That’s for avoiding ton of code whereas not strictly necessary. These controls could be added easily, though.
  • The main limitation is on the available memory. There’s no check/bound on the incoming/outgoing data, thus the number of the I/O could be virtually as the protocol specifications say. By the way, since the Netduino has limited resources, it should be considered a small number of I/Os;
  • I tested the library using the latest official firmware (4.1.0.6), which is known having some trouble with the network layer.

The first attempt.

Although at the moment of writing this post the library seems to be the first complete Modbus implementation on top of the .Net MF ever made, the result is actually my second attempt. The first attempt was porting the excellent NModbus library to the Netduino, but it was an overkill. The conversion of a full-featured project for the standard .Net Framework is often a nightmare. The major problems aren’t the missing language features, nor the limited libraries. Instead, the real challenge is fit everything the user wants in some KB, and also consuming few RAM.
Indeed, the RAM is much like the gold using Netduino: there’s few, and you should use carefully. So, the game is a continuous balance of good-practice software patterns, and tricks to save memory. While in the ordinary framework you’re invited to always more powerful and bullet-proof languages (e.g. functional-like), here you should preserve an old-stylish way of programming, as it were an “elegant C++”.
But I hate C and C++, because they lead easily to errors. And I don’t want to spend my time catching errors, but rather targeting the application being in my mind.

Rewritten from scratch.

The second (i.e. the current) attempt has dramatically changed the library, and the original NModbus project has been dropped.

I started from the source we’re using for our professional systems, and that was much easier to adapt. That because, yes, it’s also .Net framework, but we’re using to implement the software taking care to the scalability. Most of the time we have both PC and small devices exchanging data each other, and that’s usually an hard, yet delicate task to manage.
This approach is pretty costly of design time, but it returns lot of benefits in term of portability.

The library is not just a Modbus protocol driver, rather a small platform which offers several components to combine each other. There’s a section about the available ports that can be used to physically transfer the data. Another section is related to the protocols: here is only the Modbus, but others could be added easily.

Basically there’s an abstraction over the available ports (Socket, SerialPort, etc), which make it comfortable to use always as it were the same port. The only differentiation is done about the behavior of the port, that is Client or Server.
The Client behavior sends a request, then waits for a response. The Server behavior waits for an incoming request, then elaborates it, then returns a response. Since these behaviors are very different, even on the threading usage, there are two different implementations.

Client port diagram

Server port diagram

The user application uses a certain port over a well defined protocol. In the case of the Modbus protocol, the client application should create a command, and submit to the server via the chosen port. However, the submitted command has to be properly encoded upon the Modbus specification, so that the request will flow through the port as a byte stream. Similarly, when the response originated by the server is incoming from the port as a byte stream, has to be decoded back. At this point the client application has its response ready to be used. This process of encoding/decoding is performed by the protocol layer, which is logically pipelined as the data flow perspective.

The bridge pattern gives the decoupling benefits as soon you are facing the problem to use the same protocol on different ports. For better clarifying the problem, let’s consider the “classic” Modbus protocol (Modbus-RTU), which is originally targeted for serial ports. This protocol has a different encoding than the Modbus-TCP, which relies on the intrinsic reliability of the TCP/IP transport. By the way, there is a particular “derivation” of the Modbus, which is called “Modbus over TCP”. It’s basically the same encoding of the RTU, but using the TCP/IP as transport layer. If you wish to have the ability to use the same Modbus encoding, using either the serial port or the socket, then the bridge pattern solves this problem perfectly.

The protocol diagram

The same consideration is about the “codec“, which stands for “COder+DECoder”. Basically the component that has to encode/decode the user’s command upon the protocol specification. The bridge approach has been used for the codec as well. That gives the ability to change the kind of encoding/decoding without changing either the user’a application, nor the port section.
The Modbus codec diagram

The Modbus specifications define a series of generic commands, which have been subdivided in “classes” of importance.
The first two classes of commands should cover most of the applications, but it’s easy to add any other command, as well as replace an existent implementation. That’s because there are many different custom extensions, details and something like that, created along the experience of the big-Co’s working with Modbus. So that I wanted to favor the “pluggability” of the commands, instead of the compactness of the code.

The Modbus commands are part of the Modbus codec, and they are offered as the “Command” behavioral pattern. They’re basically an array of a Modbus command abstraction. Since every command function is identified by a well precise code, the proper command handler should be placed in the right cell.

The test bench.

At the moment, the library is still under development, and under test. Thus, it might be some bug or improvement.
Anyway, there are several tests to be performed: both for the master/client way and for the slave/server way.
The Netduino itself sees a very little hardware connected: just four push-buttons, and four leds. A button simulates an input to be read by the Netduino application, while a led yields the symmetric information: an output driven by the same application.

The Netduino Plus test bench

Here is all about the hardware configuration of the Netduino:

    public class Program
    {
        private static InputPort[] _inputs = new InputPort[4];
        private static OutputPort[] _coils = new OutputPort[4];


        public static void Main()
        {
            //setup the board IP
            NetworkInterface.GetAllNetworkInterfaces()[0]
                .EnableStaticIP("192.168.0.99", "255.255.255.0", "192.168.0.1");

            string localip = NetworkInterface.GetAllNetworkInterfaces()[0]
                .IPAddress;

            Debug.Print("The local IP address of your Netduino Plus is " + localip);

            //define coils and inputs
            _inputs[0] = new InputPort(Pins.GPIO_PIN_D0, true, Port.ResistorMode.PullUp);
            _inputs[1] = new InputPort(Pins.GPIO_PIN_D1, true, Port.ResistorMode.PullUp);
            _inputs[2] = new InputPort(Pins.GPIO_PIN_D2, true, Port.ResistorMode.PullUp);
            _inputs[3] = new InputPort(Pins.GPIO_PIN_D3, true, Port.ResistorMode.PullUp);

            _coils[0] = new OutputPort(Pins.GPIO_PIN_D4, false);
            _coils[1] = new OutputPort(Pins.GPIO_PIN_D5, false);
            _coils[2] = new OutputPort(Pins.GPIO_PIN_D6, false);
            _coils[3] = new OutputPort(Pins.GPIO_PIN_D7, false);

            // ...

        }

As stated from the beginning, the library offers at the moment only the Modbus-IP (TCP and UDP) version, thus there is an Ethernet cable connected to the board, toward my home ADSL modem-router. My PC is also connected to the same router.

I could have used my own PC as Modbus-slave, running any simulator application. However, I wanted do more realistic the test, by using a real hardware. In the following picture there is the complete hardware bench used for the Master-TCP/UDP test.
The actual target I/O device is one of our’s production models. It offers many I/Os, both discrete and analog, and embeds several complex functions (not involved in this test, though). It’s targeted for heavy/hard working environments, and high reliability. It can communicate via RS485 using Modbus-RTU.

The complete test bench, together with the I/O device used as slave

Since at the moment there’s no support for the RS485 by the Netduino, there’s a Modbus gateway which acts as a bridge between the Ethernet (Modbus-TCP/UDP) and the RS485 (Modbus-RTU). The small display/keypad wired to the gateway is needed for its configuration, such as the IP.

Further details in the specific test sections.

Testing the Netduino as Modbus master.

In this case, the Netduino hosts a small application which posts a command cyclically, and waits for the response.

In the following snippet, there’s the source code of the client/Master-TCP application. In this example the Netduino cyclically reads its push-buttons state, and sends them as “Write Multiple Registers” command. The particular I/O device being used drives its outputs by writing on certain registers. Thus, the effect is activating an output of the device by pressing a push-button.

            //create a TCP socket
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                //refine the socket settings
                socket.SetSocketOption(
                    SocketOptionLevel.Tcp,
                    SocketOptionName.NoDelay,
                    true
                    );

                socket.SendTimeout = 2000;
                socket.ReceiveTimeout = 2000;

                //try the connection against the remote device
                var remoteip = new byte[4] { 192, 168, 0, 60 };
                var ipaddr = new IPAddress(remoteip);
                var ept = new IPEndPoint(ipaddr, 502);
                socket.Connect(ept);

                //create a wrapper around the socket
                ICommClient portClient = socket.GetClient();

                //create a client driver
                var driver = new ModbusClient(new ModbusTcpCodec());
                driver.Address = 1;

                while (true)
                {
                    //compose the Modbus command to be submitted
                    var command = new ModbusCommand(ModbusCommand.FuncWriteMultipleRegisters);
                    command.Offset = 49;
                    command.Count = 4;

                    //attach the Netduino's input values as data
                    command.Data = new ushort[4];
                    for (int i = 0; i < 4; i++)
                        command.Data[i] = (ushort)(_inputs[i].Read() ? 0 : 1);

                    //execute the command synchronously
                    CommResponse result = driver
                        .ExecuteGeneric(portClient, command);

                    if (result.Status == CommResponse.Ack)
                    {
                        //command successfully
                    }
                    else
                    {
                        //some error
                        Debug.Print("Error=" + command.ExceptionCode);
                    }

                    //just a small delay
                    Thread.Sleep(1000);
                }
            }

It may be noticed that the socket connection is trivial, and supposed to be working at startup. A more reliable way should loop over a failed connection, then perform another attempt.

For the client/Master-UDP application, the source code is pretty similar. I changed the kind of command just to test something different. Here the Netduino application asks cyclically for a bunch of registers, then displays their content.

            //create a UDP socket
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                //try the connection against the remote device
                var remoteip = new byte[4] { 192, 168, 0, 60 };
                var ipaddr = new IPAddress(remoteip);
                var ept = new IPEndPoint(ipaddr, 502);
                socket.Connect(ept);

                //create a wrapper around the socket
                ICommClient portClient = socket.GetClient();

                //create a client driver
                var driver = new ModbusClient(new ModbusTcpCodec());
                driver.Address = 1;

                while (true)
                {
                    //compose the Modbus command to be submitted
                    var command = new ModbusCommand(ModbusCommand.FuncReadMultipleRegisters);
                    command.Offset = 0;
                    command.Count = 16;

                    //execute the command synchronously
                    CommResponse result = driver
                        .ExecuteGeneric(portClient, command);

                    if (result.Status == CommResponse.Ack)
                    {
                        //command successfully
                        Debug.Print("Success!");
                        for (int i = 0; i < command.Count; i++)
                            Debug.Print("Reg#" + i + "=" + command.Data[i]);
                    }
                    else
                    {
                        //some error
                        Debug.Print("Error=" + command.ExceptionCode);
                    }

                    //just a small delay
                    Thread.Sleep(1000);
                }
            }

Same as the TCP way: the example program won’t make any further attempt in case of connection dropped. My deal was just to test the protocol library, not the host application.

Testing the Netduino as Modbus slave.

In this case I had no concrete hardware for the simulation, thus I used a specific software running in my PC.
I must confess that there are several software for the simulation, but either they are not free, or they are pretty limited on their functionality. For testing our devices we needed something pretty easy to work on, yet enough flexible as functionality. For instance, most of the simulators consider the TCP transport only, or a limited set of commands. So, we built our own application for testing most of the Modbus stuffs.

The Modbus master simulator

The application code for making the Netduino as Modbus-TCP server is much shorter than the master way.

            //create a TCP socket
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                //place it as listener on the port 502 (standard Modbus)
                var ept = new IPEndPoint(IPAddress.Any, 502);
                socket.Listen(10);

                //create a server driver
                var server = new ModbusServer(new ModbusTcpCodec());
                server.Address = 1;

                while (true)
                {
                    //wait for an incoming connection
                    var listener = socket.GetTcpListener(server);
                    listener.ServeCommand += new ServeCommandHandler(listener_ServeCommand);
                    listener.Start();

                    Thread.Sleep(1);
                }
            }

It worth to be noticed that each connection creates a secondary socket (similarly as in a web server), and the process of listening to incoming data is performed on a separate thread. Until there are incoming requests, the thread is kept running, as well as the socket connection. Once a timeout expires after a silent/idle period, the socket will be closed, and the thread will die.

Here follows the UDP-slave version, which is slightly different, mainly because there’s no connection in the UDP technique. Instead, the listener should be only one (for each port), and the listening session is held running endlessly.

            //create a UDP socket
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                //bind it to the port 502 (standard Modbus)
                var ept = new IPEndPoint(IPAddress.Any, 502);
                socket.Bind(ept);

                //create a server driver
                var server = new ModbusServer(new ModbusTcpCodec());
                server.Address = 1;

                //listen for an incoming request
                var listener = socket.GetUdpListener(server);
                listener.ServeCommand += new ServeCommandHandler(listener_ServeCommand);
                listener.Start();

                Thread.Sleep(Timeout.Infinite);
            }

Both in the TCP and UDP slave examples, there’s no an explicit control over the session abortion. As stated, the host application could close anytime the listening session. However, this functionality is not shown despite its availability.

Demo of the test.

Coming soon.

Conclusions.

Netduino is a small board tailored mainly for simple projects, whereas the reliability over the environment is not an issue. Adding the Modbus protocol might sound odd, because that’s a protocol for professional/industrial systems. However, my goal is not to get the Netduino into the high-end world. Rather, is adding a convenient interface for plugging a variety of smart sensors commonly found in the market. In this case the Modbus library gives you an help more.

The software is hosted in the Codeplex repository here.

13 thoughts on “Modbus-TCP library for Netduino

  1. Josh

    I have downloaded the code for this project, but I am a new user to visual studio and I don’t know which files I need to open in order to run the sample code. Can you help with this?

  2. Ombre

    Thank you Mario for this awesome project, just what i needed and works like a charm. a short notice: when using the netduino 2 as a Modbus TCP slave (UDP) the analog read function at “FuncReadInputRegisters” returns a double value between 0 and 1 (at least it does for me), so when converted into ushort, the analog value is converted to 0 almost every time which is not good. But its just a minor issue. Thank you again! You’ve just saved me from a lot of work😀.

    • Mario Vernari

      Sorry for the delay, but I was in holiday!
      The command handlers are fully customizable: that’s the way they are “outside” the library. That is, you should write/adjust their code upon the real I/Os and the desired data.

    • Mario Vernari

      Any Netduino board is OS-less, and relies over a special, tiny .Net framework, which offers a small subset of libraries than the regular (desktop) one.
      You cannot run any PC app on a so small board.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s