File Coverage

blib/lib/Device/Modbus/Serial.pm
Criterion Covered Total %
statement 51 56 91.0
branch 5 10 50.0
condition 9 19 47.3
subroutine 8 10 80.0
pod 0 5 0.0
total 73 100 73.0


line stmt bran cond sub pod time code
1             package Device::Modbus::Serial;
2              
3 1     1   623 use Device::SerialPort;
  1         386  
  1         23  
4 1     1   6 use Carp;
  1         1  
  1         41  
5 1     1   4 use strict;
  1         2  
  1         15  
6 1     1   4 use warnings;
  1         2  
  1         38  
7              
8             our $VERSION = '0.001';
9              
10 1     1   5 use Role::Tiny;
  1         1  
  1         4  
11              
12             sub open_port {
13 2     2 0 6 my $self = shift;
14              
15             # Validate parameters
16             croak "Attribute 'port' is required for a Modbus serial client"
17 2 50       13 unless exists $self->{port};
18              
19             # Defaults related with the serial port
20 2   50     15 $self->{baudrate} //= 9600;
21 2   50     23 $self->{databits} //= 8;
22 2   50     13 $self->{parity} //= 'even';
23 2   50     18 $self->{stopbits} //= 1;
24 2   50     11 $self->{timeout} //= 10; # seconds
25              
26             # Serial Port object
27 2         12 my $serial = Device::SerialPort->new($self->{port});
28 2 50       26 croak "Unable to open serial port " . $self->{port} unless $serial;
29              
30 2         20 $serial->baudrate ($self->{baudrate});
31 2         46 $serial->databits ($self->{databits});
32 2         33 $serial->parity ($self->{parity});
33 2         36 $serial->stopbits ($self->{stopbits});
34 2         31 $serial->handshake('none');
35              
36             # char_time and read_char_time are given in milliseconds
37             $self->{char_time} =
38 2         29 1000*($self->{databits}+$self->{stopbits}+1)/ $self->{baudrate};
39              
40 2         18 $serial->read_char_time($self->{char_time});
41 2 50       30 if ($self->{baudrate} < 19200) {
42 2         16 $serial->read_const_time(3.5 * $self->{char_time});
43             }
44             else {
45 0         0 $serial->read_const_time(1.75);
46             }
47              
48 2 50       34 $serial->write_settings || croak "Unable to open port: $!";
49 2         42 $serial->purge_all;
50 2         26 $self->{port} = $serial;
51 2         7 return $serial;
52             }
53              
54             sub read_port {
55 2     2 0 5 my $self = shift;
56 2         6 my $buffer = '';
57 2         3 my $bytes = 0;
58 2         7 my $timeout = 1000 * $self->{timeout}; # Turn to milliseconds
59 2   66     5 do {
      33        
60 4         61 my $read;
61 4         14 ($bytes, $read) = $self->{port}->read(255);
62 4         44 $buffer .= $read;
63 4         22 $timeout -= $self->{port}->read_const_time + 255 * $self->{char_time};
64             } until ($timeout <= 0 || ($bytes == 0 && length($buffer) > 0));
65             # say STDERR "<$buffer>";
66 2         56 $self->{buffer} = $buffer;
67 2         8 return $buffer;
68             }
69              
70             sub write_port {
71 0     0 0 0 my ($self, $adu) = @_;
72 0         0 $self->{port}->write($adu->binary_message);
73             }
74              
75             sub disconnect {
76 0     0 0 0 my $self = shift;
77 0         0 $self->{port}->close;
78             }
79              
80             sub parse_buffer {
81 12     12 0 103 my ($self, $bytes, $pattern) = @_;
82             croak "Timeout error" unless
83 12 50 33     64 defined $self->{buffer} && length($self->{buffer}) >= $bytes;
84 12         64 return unpack $pattern, substr $self->{buffer},0,$bytes,'';
85             }
86              
87             1;