File Coverage

blib/lib/Device/Modbus/Client.pm
Criterion Covered Total %
statement 73 83 87.9
branch 18 18 100.0
condition 21 21 100.0
subroutine 17 19 89.4
pod 11 12 91.6
total 140 153 91.5


line stmt bran cond sub pod time code
1             package Device::Modbus::Client;
2              
3 4     4   64562 use Device::Modbus;
  4         6  
  4         99  
4 4     4   1094 use Device::Modbus::Request;
  4         7  
  4         78  
5 4     4   1044 use Device::Modbus::Response;
  4         7  
  4         90  
6 4     4   18 use Device::Modbus::Exception;
  4         4  
  4         59  
7              
8 4     4   13 use Carp;
  4         3  
  4         158  
9 4     4   12 use strict;
  4         4  
  4         59  
10 4     4   10 use warnings;
  4         4  
  4         2318  
11              
12             ### Request building
13              
14             sub read_coils {
15 2     2 1 555 my ($self, %args) = @_;
16 2         5 $args{function} = 'Read Coils';
17 2         11 return Device::Modbus::Request->new(%args);
18             }
19              
20             sub read_discrete_inputs {
21 1     1 1 367 my ($self, %args) = @_;
22 1         2 $args{function} = 'Read Discrete Inputs';
23 1         5 return Device::Modbus::Request->new(%args);
24             }
25              
26             sub read_input_registers {
27 1     1 1 347 my ($self, %args) = @_;
28 1         2 $args{function} = 'Read Input Registers';
29 1         5 return Device::Modbus::Request->new(%args);
30             }
31              
32             sub read_holding_registers {
33 4     4 1 1528 my ($self, %args) = @_;
34 4         7 $args{function} = 'Read Holding Registers';
35 4         16 return Device::Modbus::Request->new(%args);
36             }
37              
38             sub write_single_coil {
39 2     2 1 870 my ($self, %args) = @_;
40 2         6 $args{function} = 'Write Single Coil';
41 2         11 return Device::Modbus::Request->new(%args);
42             }
43              
44             sub write_single_register {
45 3     3 1 821 my ($self, %args) = @_;
46 3         8 $args{function} = 'Write Single Register';
47 3         15 return Device::Modbus::Request->new(%args);
48             }
49              
50             sub write_multiple_coils {
51 1     1 1 346 my ($self, %args) = @_;
52 1         2 $args{function} = 'Write Multiple Coils';
53 1         4 return Device::Modbus::Request->new(%args);
54             }
55              
56             sub write_multiple_registers {
57 2     2 1 874 my ($self, %args) = @_;
58 2         4 $args{function} = 'Write Multiple Registers';
59 2         9 return Device::Modbus::Request->new(%args);
60             }
61              
62             sub read_write_registers {
63 2     2 1 817 my ($self, %args) = @_;
64 2         4 $args{function} = 'Read/Write Multiple Registers';
65 2         10 return Device::Modbus::Request->new(%args);
66             }
67              
68             ### Send request
69             sub send_request {
70 0     0 1 0 my ($self, $request) = @_;
71 0         0 my $adu = $self->new_adu($request);
72 0         0 $self->write_port($adu);
73             }
74              
75             ### Response parsing
76              
77             # Parse the Application Data Unit
78             sub receive_response {
79 0     0 1 0 my $self = shift;
80 0         0 $self->read_port;
81 0         0 my $adu = $self->new_adu();
82 0         0 $self->parse_header($adu);
83 0         0 $self->parse_pdu($adu);
84 0         0 $self->parse_footer($adu);
85 0         0 return $adu;
86             }
87              
88             sub parse_pdu {
89 21     21 0 239 my ($self, $adu) = @_;
90 21         18 my $response;
91            
92 21         37 my $code = $self->parse_buffer(1,'C');
93              
94 20 100 100     286 if ($code == 0x01 || $code == 0x02) {
    100 100        
    100 100        
    100 100        
    100 100        
95             # Read coils and discrete inputs
96 4         8 my ($byte_count) = $self->parse_buffer(1, 'C');
97 4 100       78 croak "Invalid byte count: <$byte_count>"
98             unless $byte_count > 0;
99              
100 3         7 my @values = $self->parse_buffer($byte_count, 'C*');
101 3         23 @values = Device::Modbus->explode_bit_values(@values);
102              
103 3         15 $response = Device::Modbus::Response->new(
104             code => $code,
105             bytes => $byte_count,
106             values => \@values
107             );
108             }
109             elsif ($code == 0x03 || $code == 0x04 || $code == 0x17) {
110             # Read holding and input registers; read/write registers
111 6         10 my ($byte_count) = $self->parse_buffer(1, 'C');
112              
113 6 100 100     236 croak "Invalid byte count: <$byte_count>"
      100        
114             unless $byte_count > 0 && $byte_count <= 250 && $byte_count % 2 == 0;
115              
116 3         6 my @values = $self->parse_buffer($byte_count, 'n*');
117              
118 3         21 $response = Device::Modbus::Response->new(
119             code => $code,
120             bytes => $byte_count,
121             values => \@values
122             );
123             }
124             elsif ($code == 0x05 || $code == 0x06) {
125             # Write single coil and single register
126 3         7 my ($address, $value) = $self->parse_buffer(4, 'n*');
127              
128 3 100       17 if ($code == 0x05) {
129 2 100       4 $value = 1 if $value;
130             }
131              
132 3         8 $response = Device::Modbus::Response->new(
133             code => $code,
134             address => $address,
135             value => $value
136             );
137             }
138             elsif ($code == 0x0F || $code == 0x10) {
139             # Write multiple coils, multiple registers
140 2         4 my ($address, $qty) = $self->parse_buffer(4, 'n*');
141              
142 2         14 $response = Device::Modbus::Response->new(
143             code => $code,
144             address => $address,
145             quantity => $qty
146             );
147             }
148 45         54 elsif (grep { $code == $_ } 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x8F, 0x90, 0x97) {
149 1         4 my ($exc_code) = $self->parse_buffer(1, 'C');
150            
151 1         11 $response = Device::Modbus::Exception->new(
152             code => $code,
153             exception_code => $exc_code
154             );
155             }
156             else {
157 4         432 croak "Unimplemented function: <$code>";
158             }
159              
160 12         24 $adu->message($response);
161 12         17 return $response;
162             }
163              
164             1;
165             __END__