File Coverage

blib/lib/Device/Modbus/RTU/Server.pm
Criterion Covered Total %
statement 60 67 89.5
branch 8 14 57.1
condition 1 3 33.3
subroutine 13 14 92.8
pod 3 6 50.0
total 85 104 81.7


line stmt bran cond sub pod time code
1             package Device::Modbus::RTU::Server;
2              
3 1     1   23791 use parent 'Device::Modbus::Server';
  1         290  
  1         6  
4 1     1   19675 use Role::Tiny::With;
  1         5117  
  1         64  
5 1     1   995 use Data::Dumper;
  1         10022  
  1         79  
6 1     1   8 use Carp;
  1         8  
  1         55  
7 1     1   5 use strict;
  1         1  
  1         22  
8 1     1   5 use warnings;
  1         1  
  1         32  
9 1     1   13 use v5.10;
  1         4  
10              
11             with 'Device::Modbus::RTU';
12              
13             sub new {
14 1     1 1 1355 my ($class, %args) = @_;
15              
16 1         3 my $self = bless { %{$class->proto}, %args}, $class;
  1         13  
17              
18             $SIG{INT} = sub {
19 1     1   34 $self->log(2, 'Server is shutting down');
20 1         5 $self->exit;
21 1         21 };
22            
23 1         5 return $self;
24             }
25              
26             # Simply ignore requests for other units
27             sub request_for_others {
28 0     0 0 0 return;
29             }
30              
31             sub start {
32 1     1 0 2005 my $self = shift;
33              
34 1         7 $self->log(2, 'Starting server');
35 1         6 $self->open_port;
36 1         2 $self->{running} = 1;
37              
38 1         5 while ($self->{running}) {
39              
40 5839         6222 my $req_adu;
41 5839         8800 eval {
42 5839         15060 $req_adu = $self->receive_request;
43             };
44              
45 5839 100       226873 if ($@) {
46 5838 50       18700 unless ($@ =~ /^Timeout/) {
47 0         0 $self->log(2, "Error while receiving a request: $@");
48 0         0 next;
49             }
50             else {
51 5838         15732 next;
52             }
53             }
54              
55 1 50 33     7 next unless defined $req_adu && defined $req_adu->message;
56 1         20 $self->log(4, "> " . Dumper $req_adu);
57              
58             # If it is an exception object, we're done
59 1 50       13 if ($req_adu->message->isa('Device::Modbus::Exception')) {
60 0         0 $self->log(3, "Exception while waiting for requests");
61 0         0 $self->write_port($req_adu);
62 0         0 next;
63             }
64              
65             # Process request
66 1         23 my $resp = $self->modbus_server($req_adu);
67 1         146 my $resp_adu = $self->new_adu($resp);
68 1         4 $resp_adu->unit($req_adu->unit);
69 1         19 $self->log(4, "< " . Dumper $resp_adu);
70            
71             # And send the response!
72 1         12 $self->write_port($resp_adu);
73             }
74              
75 1         5 $self->disconnect;
76 1         17 $self->log(2, 'Server is down: Port is closed');
77             }
78              
79             sub exit {
80 1     1 0 2 my $self = shift;
81 1         71 $self->{running} = 0;
82             }
83              
84             # Logger routine. It will simply print messages on STDERR.
85             # It accepts a logging level and a message. If the level is equal
86             # or less than $self->log_level, the message is processed.
87             # To avoid unnecessary processing, messages that require processing can
88             # be sent in the form of a code reference to minimize performance hits.
89             # It will add a stringified level, the localtime string
90             # and caller information.
91             # It conforms to the interface provided by Net::Server; the subroutine
92             # idea comes from Log::Log4Perl
93             my %level_str = (
94             0 => 'ERROR',
95             1 => 'WARNING',
96             2 => 'NOTICE',
97             3 => 'INFO',
98             4 => 'DEBUG',
99             );
100              
101             sub log_level {
102 7     7 1 11 my ($self, $level) = @_;
103 7 50       17 if (defined $level) {
104 0         0 $self->{log_level} = $level;
105             }
106 7         21 return $self->{log_level};
107             }
108              
109             sub log {
110 7     7 1 358 my ($self, $level, $msg) = @_;
111 7 50       19 return unless $level <= $self->log_level;
112 7         288 my $time = localtime();
113 7         24 my ($package, $filename, $line) = caller;
114              
115 7 50       17 my $message = ref $msg ? $msg->() : $msg;
116            
117 7         56 print STDOUT
118             "$level_str{$level} : $time -- $0 -- $package -- $message\n";
119 7         19 return 1;
120             }
121              
122             1;
123              
124              
125             __END__