File Coverage

blib/lib/Device/Modbus/RTU/Server.pm
Criterion Covered Total %
statement 58 65 89.2
branch 8 14 57.1
condition 2 5 40.0
subroutine 12 13 92.3
pod 3 6 50.0
total 83 103 80.5


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