Modbus I/O
Modbus master
The modbus master is actually three modules, one each for Modbus/RTU,
Modbus/ASCII and Modbus/TCP. When you're running the demo, don't forget to
select the correct module in the [PLC]
section of the config.
[PLC]
# Uncomment the modbus protocol version you wish to run...
module modbus_m "../../io/modbus/modbus_m_rtu"
#module modbus_m "../../io/modbus/modbus_m_asc"
#module modbus_m "../../io/modbus/modbus_m_tcp"
Configuration
The configuration consists of three tables:
- network
- connection information (serial port or TCP address)
- node
- the devices connected to each network (modbus ID)
- map
- the usual mapping of actual I/O to MatPLC points (registers)
Network configuration table
This specifies the connection information - serial port or TCP address, and
any associated settings. There can be any number of these - one module may
talk to several serial ports or several TCP slaves; on the other hand,
having a separate module for each port or each TCP address will allow the
slaves to be contacted simultaneously rather than one by one.
The format of the table is:
network <network_name> <protocol>
<parameters>
<network_name>
- The name used to refer to this
network in the rest of this config.
<protocol>
- {rtu | ascii | tcp}
This must agree
with the module being used.
<parameters>
- These depend on the type of
network:
- For rtu and ascii networks
[device <filename>]
[baudrate <x>]
[parity {even|odd|none}]
[data_bits <x>]
[stop_bits <x>]
[ignore_echo {true|false}]
[timeout <x>]
[send_retries <x>]
- For tcp networks
[host <x>]
- the IP address or DNS name of the
slave
[port <x>]
- x is either the port number on which
the slave is listening, or the service name, which will be mapped onto the
port number according the configuration in the /etc/services file
(FIXME - what is the default?)
[timeout <x>]
- (FIXME - what does this do? what is the default?)
[send_retries <x>]
- (FIXME - what does this do? what is the default?)
[TCP_close {true | false}]
- true
- (default) Close the connection after each scan. This is
slightly slower, as the connection must be re-established at the
beginning of the next scan.
- false
- Keep the connection open between scans. However, some slaves
may only support a limited number of simultaneous masters, and this will
keep one of those limited slots occupied for as long as this module is
running, potentially blocking out other masters.
The openmodbus specification sugests that all TCP connections
should be closed if they are going to stay idle for longer than 1 second,
so that you should set TCP_close
to true
if the
scan time for this module is longer than a second, and false
if it's shorter. In practice, the important consideration will be how many
masters are accessing this slave, compared with the slave's "maximum
simultaneous masters" specification, and the relative priority between
those masters.
# Sample network configurations...
network rtu_net rtu device /dev/ttyS1 baudrate 9600 parity none data_bits 8 stop_bits 1 ignore_echo false timeout 1.5 send_retries 2
network asc_net ascii device /dev/ttyS1 baudrate 9600 parity none data_bits 8 stop_bits 1 ignore_echo false timeout 1.5 send_retries 2
network tcp_net tcp host localhost port 502 timeout .1 send_retries 1 TCP_close true
Node address table
This is a fairly simple table, giving names to all the nodes based on their
Modbus ID.
Each line has the form:
node <slave_name> <network_name>
<slave_addr>
<slave_name>
- The name used to refer to this slave
node in the rest of the config.
<network_name>
- The name of the network, as
declared in the
network
table (above).
<slave_addr>
- The modbus slave ID, 0..255
# Sample slave configurations...
node speed_drive tcp_net 34
node digital_IO rtu_net 0
node analog_IO asc_net 23
Mapping table
Each line has the form:
map [inv | invert] {in | out}
<slave>.<reg_type>.<reg_addr>
<matplc point>
inv
invert
- (optional) invert the value being read
from/writen to physical IO
in
- copy from the Modbus device to the MatPLC point
out
- copy the state of the MatPLC point to the Modbus
device
<slave>
- the name of the slave node, as it appears in the node address table.
<reg_type>
- Which register type (data table) to
access, according to this table:
type | data table | long address | in/out | Modbus fn. used | Amount of
data read/written |
in | out |
in_bit | Discrete Input | 1xxxx
| must be mapped in | 0x02 | - | The number of bits transfered is the
same as the number of bits in the MatPLC point being mapped. The address
given in the mapping is the adress of the first bit. |
out_bit | Coil | 0xxxx | may be
mapped in or out | 0x01 | 0x0F
(15) |
in_word | Input Register | 3xxxx
| must be mapped in | 0x04 | - | If MatPLC point being mapped has 16
or less bits, 1 word will be trnsferred. If it has between 17 and 32, 2
words will be transferred. The address given in the mapping is the
adress of the first word. |
out_word | Holding Register | 4xxxx
| may be mapped in or
out | 0x03 | 0x10 (16) |
<reg_addr>
- 1..10000
Note that, as per the standard, <reg_addr>
is 1-based.
If your documentation lists Modbus addresses starting with 0, you will have
to add 1 to each of them.
<matplc point>
- the MatPLC point to map
# Sample IO table
map out digital_IO.out_bit.1 L1
map out digital_IO.out_bit.2 L2
map out digital_IO.out_bit.3 L3
map out digital_IO.out_bit.4 L4
Error logging
The first time an error occurs (timeout, received invalid response frame,
received error frame, etc...) when communicating with a device, this will
be logged as an error at level 2. All subsequent errors for the same device
will be logged as an error at level 3. When a device comes back up, this
will be logged as an error at level 2.
Modbus slave
The modbus slave module is partially implemented and has not undergone serious testing.
Currently, it supports TCP/IP transport only. Furthermore, functions
0x03, 0x04, and 0x06 only are available.
Access control of MatPLC points through Modbus slave is based on the standard MatPLC architectural concept: in order to write to a point the Modbus slave must be the owner of this point.
The modbus slave module, whose default name is "modbus_s", should be enabled in the MatPLC configuration
with a "module" keyword and the path to the module's executable. Note that the ASCII AND RTU versions are not implemented yet and their instances below are for illustration only.
[PLC]
# Uncomment the modbus protocol version you wish to run...
module modbus_s "../../io/modbus/modbus_s_tcp"
#module modbus_s "../../io/modbus/modbus_s_asc"
#module modbus_s "../../io/modbus/modbus_s_tru"
Configuration
The configuration consists of two tables:
- endpoint
- connection information
- map
- the mapping of actual I/O to MatPLC points (registers)
Endpoint configuration table
This configures endpoints that MatPLC will listen on for incoming requests - TCP address and any associated settings. There can be any number of these - one module may
listen on several interfaces.
The format of the table is:
endpoint <network_name> <protocol>
<parameters>
<network_name>
- The name used to refer to this
network in the rest of this config.
<protocol>
- {rtu | ascii | tcp}
This must agree
with the module being used (tcp is the only option currently supported).
<parameters>
- These depend on the type of
network:
- For tcp networks
[host <x>]
- the IP address or DNS name of the
interface to listen on. 0.0.0.0 stands for INADDR_ANY.
[port <x>]
- x is either the port number on which
the slave is listening, or the service name, which will be mapped onto the
port number according the configuration in the /etc/services file
(FIXME - what is the default?)
[address <x>]
- Modbus slave address.
[connections <x>]
- The number of simultaneous incomming connections to accept.
[mode <x>]
- The mode in which the slave is run: 0 - async, 1 - sync. The default value is 0
# Sample endpoint configuration...
endpoint tcp_net tcp host 0.0.0.0 port 5502 address 34 mode 0 connections 1
Mapping table
The object data size is determined by the invoked modbus function. For instance, if a coil reading is requested a single bit of the mapped MatPLC point will be transmitted. Likewise, in register operations, the data object size is 16 bits. Therefore, in order to transmit an entire MatPLC point of maximum size (32 bits) two register operations are needed. Alternatively, a multiple register function may be utilized (currently not supported).
Each line has the form:
map slave
<shift>.<matplc point>
<shift>
The number of bits to shift a MatPLC point right before
mapping it to a modbus type on reading or the number of bits to shift a modbus type right before mapping it to a MatPLC point on writing. The following aliases are available: "high" for 16 and "low" for 0.
<matplc point>
the MatPLC point to map
Useful links
- Modbusfw - Modbus/TCP Filtering on Linux Firewalls
- A set of kernel patches for Linux Netfilter to allow firewall policy
decisions (DROP, DENY, ALLOW, etc.) to be made based on Modbus/TCP header
values including modbus function code, providing better access control than
simply blocking port 502. However, as of Sep 2003 this is an initial
prototype release and they've done only limited testing so any feedback,
new feature requests, and/or help with development is appreciated. See http://modbusfw.sourceforge.net
for details.
$Date: 2004/12/28 05:32:11 $