Device::Modbus::Server - Base class for Device::Modbus server objects
#! /usr/bin/env perl use Device::Modbus::TCP::Server; use strict; use warnings; use v5.10; { package My::Unit; our @ISA = ('Device::Modbus::Unit'); sub init_unit { my $unit = shift; # Zone addr qty method # ------------------- ---- --- --------- $unit->get('holding_registers', 2, 1, 'get_addr_2'); } sub get_addr_2 { my ($unit, $server, $req, $addr, $qty) = @_; $server->log(4,"Executed server routine for address 2"); return 6; } } my $server = Device::Modbus::TCP::Server->new( log_level => 4, log_file => 'logfile' ); my $unit = My::Unit->new(id => 3); $server->add_server_unit($unit); $server->start;
This document describes functionalities common to both Modbus RTU and Modbus TCP servers. Constructors are documented in Device::Modbus::RTU::Server and Device::Modbus::TCP::Server.
First, we will briefly describe the data model inherent to the protocol. This is the base for building the functionalities that the server will expose. Then, these functionalities need to be attached to the server, which must finally be started.
The Modbus protocol communicates a client with a unit in a server. A unit may offer functionalities in one to four different zones of different types:
Discrete inputs
Discrete outputs (or coils)
Input registers
Holding registers
Client requests are sent to a particular server unit, and they specify the data zone they are directed to, the address which will be affected, and the number of data points they refer to. Write requests include also the transmitted values.
In Device::Modbus, a unit is represented by an object which inherits from Device::Modbus::Unit. Each object maps requests to exposed functions. To execute a function, a request must match its address zone, its set of valid addresses, and the quantity of data that the function can take or return. For example, the unit in the synopsis responds only to requests for reading a single register in address 2 of the Holding registers zone.
To define a unit, you must start with a class that inherits from Device::Modbus::Unit. This class must implement a method called init_unit, which is responsible of defining the mapping to the exposed class methods.
init_unit
Requests may either get data from the server or they may put data into the server. get and put are the methods used to define the mapping to the functionality exposed by the server. Both methods receive the same arguments: a zone, an address definition, a quantity of data definition, and the name of a class method or a code reference.
get
put
I think the best explanation is an example:
package My::Unit; use parent 'Device::Modbus::Unit'; sub init_unit { my $unit = shift; # Zone addr qty method # ------------------- ---- --- --------- $unit->get('holding_registers', 2, 1, 'get_some_data'); $unit->put('holding_registers', 0, 1, 'save_some_data'); }
Here, init_unit exposes two methods from My::Unit. get_some_data reacts only to reading requests; save_some_data, to writing requests. They both act on the holding_registers zone. get_some_data will be executed only for requests for a single register at address two; save_some_data reacts to writing requests on address zero, also for a single register.
My::Unit
get_some_data
save_some_data
holding_registers
Let's go over the different arguments for get and put. The zones that you can use are:
Readable and writable; bit-addressable
Readable only; bit-addressable
Readable only; register-addressable
Readable and writable; register-addressable
Addresses must be between 0 and 65536. However, they can be defined in any of the following ways:
The next argument, the quantity of data that the class method may receive or return, is defined using the same rules as addresses.
Finally, you can either use the name of a class method, or a code reference to define the functionality exposed by the unit.
These are more examples:
# Zone addr qty method # ------------------- --------- ------ -------------------- $unit->get('holding_registers', '1-5', 5, sub { [ 6 x 5 ] }); $unit->get('input_registers', '6-8, 10', 4, sub { [ 3 x 4 ] }); $unit->put('holding_registers', 33, 1, sub { return 19 }); $unit->put('discrete_coils', 1, '*', 'save_any';
Once a request for a given method is received, the server will execute it with the following arguments:
A reference to the unit object
A reference to the server object
The received request object
The requested address number
The quantity of data requested
In addition to this, write requests include the values sent by the client in an array reference. For example:
sub write_data { my ($unit, $server, $req, $addr, $qty, $val) = @_; ... } sub read_single { my ($unit, $server, $req, $addr, $qty) = @_; ... return $value; } sub read_data { my ($unit, $server, $req, $addr, $qty) = @_; ... return @values; }
Note that routines which handle reading requests must return the exact number of requested registers or bits. Values are returned as arrays, not as array references. Register values must be numbers between 0 and 65536; bits are simply true and false values.
Aside from your unit class, you must instantiate a server. Server construction methods depend on the communication channel that you will be using. Device::Modbus::RTU::Server communicates via the serial port; Device::Modbus::TCP::Server uses TCP/IP sockets. Please read the documentation in those modules to construct your server.
Once your unit class is defined, it must be instantiated and added to a server. Then, the server must be started. From the synopsis:
my $unit = My::Unit->new(id => 3); $server->add_server_unit($unit); $server->start;
In this example, the unit object is added to the server as unit number three. You can add any number of units to a server.
And that is all it takes.
This module is part of the Device::Modbus distribution. Server constructors are documented in Device::Modbus::RTU::Server and Device::Modbus::TCP::Server.
I have written some examples in my blog, http://7mavida.com/tag/Device::Modbus.
Julio Fraire, <julio.fraire@gmail.com>
Copyright (C) 2015 by Julio Fraire This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14.2 or, at your option, any later version of Perl 5 you may have available.
To install Device::Modbus, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Device::Modbus
CPAN shell
perl -MCPAN -e shell install Device::Modbus
For more information on module installation, please visit the detailed CPAN module installation guide.