File Coverage

blib/lib/Device/Modbus/RTU/Server.pm
Criterion Covered Total %
statement 63 65 96.9
branch 12 14 85.7
condition 3 5 60.0
subroutine 13 13 100.0
pod 3 6 50.0
total 94 103 91.2


line stmt bran cond sub pod time code
1             package Device::Modbus::RTU::Server;
2              
3 5     5   70333 use parent 'Device::Modbus::Server';
  5         1077  
  5         19  
4 5     5   50368 use Role::Tiny::With;
  5         16211  
  5         253  
5 5     5   2448 use Data::Dumper;
  5         26228  
  5         239  
6 5     5   21 use Carp;
  5         4  
  5         195  
7 5     5   20 use strict;
  5         5  
  5         81  
8 5     5   17 use warnings;
  5         4  
  5         1967  
9              
10             with 'Device::Modbus::RTU';
11              
12             sub new {
13 5     5 1 3656 my ($class, %args) = @_;
14              
15 5         6 my $self = bless { %{$class->proto}, %args}, $class;
  5         43  
16              
17             $SIG{INT} = sub {
18 4     4   175 $self->log(2, 'Server is shutting down');
19 4         17 $self->exit;
20 5         77 };
21            
22 5         74 return $self;
23             }
24              
25             # Simply ignore requests for other units
26             sub request_for_others {
27 1     1 0 21 return;
28             }
29              
30             sub start {
31 4     4 0 4122 my $self = shift;
32              
33 4         20 $self->log(2, 'Starting server');
34 4         19 $self->open_port;
35 4         7 $self->{running} = 1;
36              
37 4         13 while ($self->{running}) {
38              
39 10750         6908 my $req_adu;
40 10750         9174 eval {
41 10750         17925 $req_adu = $self->receive_request;
42             };
43              
44 10750 100       248284 if ($@) {
45 10746 50       29833 unless ($@ =~ /^Timeout/) {
46 0         0 $self->log(2, "Error while receiving a request: $@");
47 0         0 next;
48             }
49             else {
50 10746         18932 next;
51             }
52             }
53              
54 4 50 33     20 next unless defined $req_adu && defined $req_adu->message;
55 4         35 $self->log(4, "> " . Dumper $req_adu);
56              
57             # If it is an exception object, we're done
58 4 100       37 if ($req_adu->message->isa('Device::Modbus::Exception')) {
59 1         10 $self->log(3, "Exception while waiting for requests");
60 1         3 $self->write_port($req_adu);
61 1         17 next;
62             }
63              
64             # Process request
65 3   100     49 my $resp = $self->modbus_server($req_adu) || next;
66 2         187 my $resp_adu = $self->new_adu($resp);
67 2         4 $resp_adu->unit($req_adu->unit);
68 2         19 $self->log(4, "< " . Dumper $resp_adu);
69            
70             # And send the response!
71 2         16 $self->write_port($resp_adu);
72             }
73              
74 4         16 $self->disconnect;
75 4         33 $self->log(2, 'Server is down: Port is closed');
76             }
77              
78             sub exit {
79 4     4 0 6 my $self = shift;
80 4         33 $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 47     47 1 756 my ($self, $level) = @_;
102 47 100       87 if (defined $level) {
103 5         6 $self->{log_level} = $level;
104             }
105 47         102 return $self->{log_level};
106             }
107              
108             sub log {
109 40     40 1 4163 my ($self, $level, $msg) = @_;
110 40 100       71 return unless $level <= $self->log_level;
111 34         979 my $time = localtime();
112 34         76 my ($package, $filename, $line) = caller;
113              
114 34 100       70 my $message = ref $msg ? $msg->() : $msg;
115            
116 34         211 print STDOUT
117             "$level_str{$level} : $time -- $0 -- $package -- $message\n";
118 34         55 return 1;
119             }
120              
121             1;
122              
123              
124             __END__