README.md

# Modbus TCP Server

## Introduction

This package implements a Modbus TCP Server as an OTP application.
 Modbus is an industrial automation communications protocol. Detailed 
protocol specifications can be found at [modbus.org][modbus_specs].

Refer to the documentation in `ModbusServer` to see what functionality
is available in this implementation.

It should be noted that Reading and Writing Files will not be in scope
of this project, unless someone else contributes the code, tests, and
documentation. I have found that Reading and Writing Files is used
very rarely, if ever, in industry. There are always alternative ways
to transfer files. Protocols such as FTP and SFTP are good examples.

Also, none of the Function codes marked as Serial Line Only in the Application
Protocol document are implemented in this server due to this server being
specifically for TCP. I would not be opposed to implementing a serial version
but it is not an immediate goal.

[modbus_specs]: http://modbus.org/specs.php

### Disclaimer

This work is completely my own and is not endorsed nor supported by my employer.

## Status

This server has a test suite with tests created directly from the Modbus 
specification. Additionally, it was tested using the Kepware Modbus TCP
OPC Server.

## Installation

The package can be installed as:

  1. Add `modbus_tcp_server` to your list of dependencies in `mix.exs`:

    ```elixir
    def deps do
      [{:modbus_tcp_server, "~> 1.0.0"}]
    end
    ```

  2. Ensure `modbus` is started before your application:

    ```elixir
    def application do
      [applications: [:modbus_tcp_server]]
    end
    ```

## Usage

### Configuration

The Modbus TCP Server database is defined through configuration files. The `Mix.Config`
format of configuration is used. There are 3 tiers of configuration files, each
one overrides the values from the previous. Currently, only Windows configuration
locations are supported (Patches Welcome!).

1. %PROGRAMDATA%/Elixir-Modbus/modbus_map.exs
2. %APPDATA%/Elixir-Modbus/modbus_map.exs
3. modbus_map.exs

Item #3 is a modbus_map.exs file in the directory where the server is started.

If item #1 or item #2 don't exist, an empty configuration is inserted and the merge
is correctly handled.

#### modbus_map.exs File Format

The modbus_map.exs files follow the `Mix.Config` format and must return a Keyword List.
The application name used in the Modbus TCP Server is :modbus_tcp_server.

The modbus_map.exs File Format is shown below.

    [
      {:modbus_tcp_server, # this line states that this configuration applies to the :modbus_tcp_server application
        [
          {:modbus_coil_database, [0, 1]}, # this line defines modbus_coil_database will contain 2 coils: 0 and 1
          {:modbus_discrete_input_database, [0, 1, 2]}, # this line defines modbus_discrete_input_database will contain 3 discrete inputs: 0, 1 and 2
          {:modbus_holding_register_database, [5]}, # this line defines modbus_holding_register_database will contain 1 discrete inputs: 5
          {:modbus_input_register_database, [5, 15]}, # this line defines modbus_input_register_database will contain 2 discrete inputs: 5 and 15
        ]
      }
    ]

#### Configuration Example

Multiple files are used for configuration in the following example. You will see
how values from more specific configuration files override those from less specific ones.

The follow block shows the contents of the %PROGRAMDATA%/Elixir-Modbus/modbus_map.exs file.

    [
      {:modbus_tcp_server, 
        [
          {:modbus_discrete_input_database, [0, 1]},
        ]
      }
    ]

Next up are the contents from %APPDATA%/Elixir-Modbus/modbus_map.exs.

    [
      {:modbus_tcp_server, 
        [
          {:modbus_input_register_database, [0, 1, 2]}
          {:modbus_discrete_input_database, [5, 6]},
        ]
      }
    ]

Finally, the modbus_map.exs from the current working directory is shown.

    [
      {:modbus_tcp_server, 
        [
          {:modbus_coil_database, 0 .. 10 |> Enum.to_list},
          {:modbus_discrete_input_database, [5, 6, 7]},
          {:modbus_holding_register_database, 0 .. 20 |> Enum.to_list},
        ]
      }
    ]

The final configuration loaded into the application will merge all 3 of these files,
with the modbus_map.exs having the highest precedence, followed by 
%APPDATA/Elixir-Modbus/modbus_map.exs, and finally by 
%PROGRAMDATA%/Elixir-Modbus/modbus_map.exs.

    [
      {:modbus_tcp_server, 
        [
          {:modbus_coil_database, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]},
          {:modbus_discrete_input_database, [5, 6, 7]},
          {:modbus_holding_register_database, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]},
          {:modbus_input_register_database, [0, 1, 2]}
        ]
      }
    ]

This example also shows that you can create the list of registers for any of the databases
using any valid elixir code. The :modbus_coil_database and :modbus_holding_register_database
use ranges and the `Enum.to_list` function to create the list of registers.

## Contributing

Contributions are welcome, and they are greatly appreciated! Every
little bit helps, and credit will always be given.

You can contribute in many ways:

### Types of Contributions

#### Report Bugs

Report bugs at [bitbucket][bitbucket].

If you are reporting a bug, please include:

* Your operating system name and version.
* Any details about your local setup that might be helpful in troubleshooting.
* Detailed steps to reproduce the bug.


#### Fix Bugs

Look through the bitbucket issues for bugs. Anything tagged with "bug"
and "help wanted" is open to whoever wants to implement a fix for it.

#### Implement Features

Look through the GitHub issues for features. Anything tagged with "enhancement"
and "help wanted" is open to whoever wants to implement it.

#### Write Documentation

Modbus TCP Server could always use more documentation, whether as part of the
official docs, in docstrings, or even on the web in blog posts, articles, and such.

#### Submit Feedback

The best way to send feedback is to file an issue at [bitbucket][bitbucket].

If you are proposing a new feature:

* Explain in detail how it would work.
* Keep the scope as narrow as possible, to make it easier to implement.
* Remember that this is a volunteer-driven project, and that contributions
  are welcome :)

### Get Started!

Ready to contribute? Here's how to set up Modbus TCP Server for local development. 

1. Fork the Modbus TCP repo on [bitbucket][bitbucket].
2. Clone your fork locally::
    
    ```bash
    $ cd path_for_the_repo
    $ hg clone hg@bitbucket.com/idahogray/Modbus-Elixir
    ```

3. Create a branch for local development::

    ```bash
    $ hg branch name-of-your-bugfix-or-feature
    ```

   Now you can make your changes locally.

4. The next step would be to run the test cases. Before you run the tests, you should ensure all dependancies are installed::

    ```bash
    $ mix deps.get
    $ mix test --no-start
    ```

5. If your contribution is a bug fix or new feature, you must add a test to the existing test suite.

6. Commit your changes and push your branch to GitHub::

    ```bash
    $ hg commit -m "Your detailed description of your changes."
    $ hg push
    ```

10. Submit a pull request through the [bitbucket][bitbucket] website.

### Pull Request Guidelines

Before you submit a pull request, check that it meets these guidelines:

1. The pull request must include tests.

2. If the pull request adds functionality, the docs should be updated. Put
   your new functionality into a function with a docstring, and add the
   feature to the list in README.rst.

[bitbucket]: https://bitbucket.org/idahogray/Modbus-Elixir

## History

* 1.0.0 (2017/01/01)
    * First release on hex

## Credits

### Development Lead

* Keith Gray <idahogray@gmail.com>

### Contributors

None yet. Why not be the first?

## Copyright and License

Copyright (c) 2016, Keith Gray.

Modbus TCP Server is licensed under the [MIT License](../LICENSE).

## Related/Similar Projects
* [Erlang Modbus Client/Server][emodbus]
* [Elixir Modbus Client][modbus]
* [An Elixir ModbusTCP client implementation][ex_modbus]

[emodbus]: https://github.com/erlscada/emodbus
[modbus]: https://hex.pm/packages/modbus
[ex_modbus]: https://hex.pm/packages/ex_modbus