File Coverage

blib/lib/Device/Modbus/Unit.pm
Criterion Covered Total %
statement 44 44 100.0
branch 16 16 100.0
condition 6 6 100.0
subroutine 11 11 100.0
pod 0 7 0.0
total 77 84 91.6


line stmt bran cond sub pod time code
1             package Device::Modbus::Unit;
2              
3 5     5   29399 use Device::Modbus::Unit::Route;
  5         9  
  5         135  
4 5     5   20 use Carp;
  5         7  
  5         249  
5 5     5   20 use strict;
  5         6  
  5         83  
6 5     5   15 use warnings;
  5         4  
  5         2098  
7              
8              
9             sub new {
10 5     5 0 1796 my ($class, %args) = @_;
11             croak "Missing required parameter: id"
12 5 100       101 unless defined $args{id};
13 4         21 my %routes = (
14             'discrete_coils:read' => [],
15             'discrete_coils:write' => [],
16             'discrete_inputs:read' => [],
17             'input_registers:read' => [],
18             'holding_registers:read' => [],
19             'holding_registers:write' => [],
20             );
21 4         22 return bless { %args, routes => \%routes }, $class;
22             }
23              
24             sub id {
25 3     3 0 614 my $self = shift;
26 3         14 return $self->{id};
27             }
28              
29             sub routes {
30 4     4 0 9 my $self = shift;
31 4         18 return $self->{routes};
32             }
33              
34             sub init_unit {
35 1     1 0 75 croak "Device::Modbus::Unit subclasses must implement init_unit";
36             }
37              
38             sub put {
39 9     9 0 1372 my ($self, $zone, $address, $qty, $method) = @_;
40 9 100       27 if (!ref $method) {
41 7         26 $method = $self->can($method); # returns a ref to method
42             }
43 9 100 100     254 croak "'put' could not resolve a code reference for address $address in zone $zone"
44             unless ref $method && ref $method eq 'CODE';
45              
46 7         34 my $addr = Device::Modbus::Unit::Route->new(
47             address => $address,
48             zone => $zone,
49             quantity => $qty,
50             read_write => 'write',
51             routine => $method
52             );
53            
54 7         8 push @{$self->{routes}->{"$zone:write"}}, $addr;
  7         30  
55             }
56              
57             sub get {
58 11     11 0 1036 my ($self, $zone, $address, $qty, $method) = @_;
59 11 100       31 if (!ref $method) {
60 9         24 $method = $self->can($method); # returns a ref to method
61             }
62 11 100 100     212 croak "'get' could not resolve a code reference for address $address in zone $zone"
63             unless ref $method && ref $method eq 'CODE';
64              
65 9         31 my $route = Device::Modbus::Unit::Route->new(
66             address => $address,
67             zone => $zone,
68             quantity => $qty,
69             read_write => 'read',
70             routine => $method
71             );
72            
73 9         6 push @{$self->{routes}->{"$zone:read"}}, $route;
  9         33  
74             }
75              
76             # Tests a requested zone, address, qty against existing addresses.
77             # Returns the first successful match. Returns the Modbus error number
78             # otherwise (3 for invalid qty and 2 for invalid address)
79             sub route {
80 22     22 0 1294 my ($self, $zone, $mode, $addr, $qty) = @_;
81 22         47 my $addresses = $self->{routes}->{"$zone:$mode"};
82 22 100       46 return 1 unless @$addresses;
83              
84 20         18 my $match;
85 20         27 foreach my $address (@$addresses) {
86 26 100       53 next unless $address->test_route($addr);
87 13         14 $match = $address;
88 13 100       22 return $match if $match->test_quantity($qty);
89             }
90              
91             # return 3 if defined $match; # Address matched, not quantity # INCORRECT
92 8         18 return 2; # Did not match
93             }
94              
95             1;