File Coverage

blib/lib/Device/Modbus/Client.pm
Criterion Covered Total %
statement 80 90 88.8
branch 8 8 100.0
condition 6 6 100.0
subroutine 18 20 90.0
pod 11 12 91.6
total 123 136 90.4


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