Device-Modbus

 view release on metacpan or  search on metacpan

lib/Device/Modbus.pm  view on Meta::CPAN

    'Write Multiple Coils'          => 0x0F,
    'Write Multiple Registers'      => 0x10,
    'Read/Write Multiple Registers' => 0x17,
);

our %function_for = reverse %code_for;

#### Helper methods

# Receives an array reference of bit values and builds an array
# of 8-bit numbers. Each number starts with the lower address
# in the LSB.
# Returns the quantity of bits packed and a reference to the array
# of 8-bit numbers
sub flatten_bit_values {
    my ($self, $values) = @_;

    # Values must be either 1 or 0
    my @values = map { $_ ? 1 : 0 } @{$values};

    # Turn the values array into an array of binary numbers
    my @values_binary;
    while (@values) {
        push @values_binary, pack 'b*', join '', splice @values, 0, 8;
    }
    return \@values_binary;
}

# Receives a quantity of bits and an array of 8-bit numbers.
# The numbers are exploded into an array of bit values.
# The numbers start with the lower address in the LSB,
# and the first number contains the lower address.
# Returns an array of ones and zeros.
sub explode_bit_values {
    my ($self, @values) = @_;
    @values = map {split //, unpack 'b8', pack 'v', $_} @values;
    return @values;
}

1;

lib/Device/Modbus/Request.pm  view on Meta::CPAN

=back

=head4 * Read/Write Multiple Registers

This is function number 0x17. It requires the following arguments:

=over

=item read_address

The address where you want to start reading registers. As usual, it must be a number between 0 and 65535.

=item read_quantity

A number up to 125. This is the number of registers that will be read.

=item write_address

The address where you want to start writing register values. Again, it must be a number between 0 and 65535.

=item values

You can enter up to 121 values in an array reference. Each value will be coded in a 16-bit word, so they must be between 0 and 65535.

=back

=head2 pdu

This method returns the binary representation of the request. Before sending it to a server (or to a slave, which amounts to the same), you must wrap the PDU within a protocol header and footer. See the ADU methods of the clients for this.

lib/Device/Modbus/Server.pm  view on Meta::CPAN

 }
 
 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;


=head1 DESCRIPTION

This document describes functionalities common to both Modbus RTU and Modbus TCP servers. Constructors are documented in L<Device::Modbus::RTU::Server> and L<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.

=head1 THE MODBUS DATA MODEL

The Modbus protocol communicates a client with a I<unit> in a server. A unit may offer functionalities in one to four different zones of different types:

=over

=item * Discrete inputs

=item * Discrete outputs (or coils)

t/lib/Test/Server.pm  view on Meta::CPAN


use parent 'Device::Modbus::Server';
use strict;
use warnings;


sub log_level {
    return 2;
}

sub start {
    print STDERR "# Required by Device::Modbus::Server\n";
}

my %level_str = (
    0 => 'ERROR',
    1 => 'WARNING',
    2 => 'NOTICE',
    3 => 'INFO',
    4 => 'DEBUG',
);

t/server.t  view on Meta::CPAN

    use_ok 'Device::Modbus::ADU';
    use_ok 'TestServer';
}

{
    my $server = TestServer->new();
    ok $server->DOES('Device::Modbus::Server'),
        'The server object plays Device::Modbus::Server';

    is_deeply $server->units, {},
        'Units are saved in a hash reference which starts empty';

    eval { $server->init_server; };
    like $@, qr{Server must be initialized},
        'Initialization method must be subclassed';
}

{
    package My::Unit;
    use Test::More;
    our @ISA = ('Device::Modbus::Unit');

t/units.t  view on Meta::CPAN


    my $unit = Device::Modbus::Unit->new(id => 3);

    isa_ok $unit, 'Device::Modbus::Unit';
    is  $unit->id, 3,
        'Unit created successfully and ID is correct';

    is ref $unit->routes->{'holding_registers:read'}, 'ARRAY',
        'Addresses will be stored in a hash of array refs';
    is scalar @{$unit->routes->{'holding_registers:read'}}, 0,
        'The arrays start empty';

    #                Zone           addr  qty    method
    #           ------------------- ----- --- -----------------
    $unit->get('holding_registers', '1-5', 5,  sub { return 6 });

    is scalar @{$unit->routes->{'holding_registers:read'}}, 1,
        'Added an address to the holding_registers:read array';

    my $match = $unit->route('holding_registers', 'read', 3, 5);

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 1.734 second using v1.00-cache-2.02-grep-82fe00e-cpan-f5108d614456 )