File Coverage

blib/lib/Protocol/Modbus/Request.pm
Criterion Covered Total %
statement 53 55 96.3
branch 8 10 80.0
condition 11 16 68.7
subroutine 13 13 100.0
pod 0 9 0.0
total 85 103 82.5


line stmt bran cond sub pod time code
1             package Protocol::Modbus::Request;
2              
3 5     5   22 use strict;
  5         10  
  5         146  
4 5     5   23 use warnings;
  5         8  
  5         158  
5 5     5   4623 use overload '""' => \&stringify;
  5         1105  
  5         50  
6 5     5   365 use overload 'eq' => \=
  5         8  
  5         26  
7              
8             sub equals {
9 3     3 0 8 my ($x, $y) = @_;
10 3         8 $x->stringify() eq $y->stringify(); # or "$x" == "$y"
11             }
12              
13             sub new {
14 12     12 0 33 my ($obj, %args) = @_;
15 12   33     53 my $class = ref($obj) || $obj;
16 12         58 my $self = {_options => {%args},};
17 12         75 bless $self, $class;
18             }
19              
20             sub stringify {
21 36     36 0 2791 my $self = $_[0];
22 36         78 my $pdu = $self->pdu();
23 36         138 my $str = 'ModbusRequest PDU(' . unpack('H*', $pdu) . ')';
24 36         245 return ($str);
25             }
26              
27             sub pdu {
28 54     54 0 4414 my $self = $_[0];
29 54         116 my @struct = $self->structure();
30 54         101 my $args = $self->{_options};
31 54         102 my $func = $self->function();
32 54         184 my $pdu = pack('C', $func);
33              
34 54         94 for (@struct) {
35 108         119 my $ptype = $_;
36 108         104 my ($pname, $pbytes, $pformat) = @{&Protocol::Modbus::PARAM_SPEC->[$ptype]};
  108         311  
37              
38             #warn('adding ', $pname, '(', $args->{$pname},') for ', $pbytes, ' bytes with pack format (', $pformat, ')');
39 108         341 $pdu .= pack($pformat, $args->{$pname});
40             }
41              
42             # Add optional header/trailer for (for Modbus/TCP, Modbus/RTU protocol flavours)
43 54         118 $pdu = $self->header() . $pdu . $self->trailer();
44              
45 54         186 return ($pdu);
46             }
47              
48             # Get/set request additional header (for TCP/IP, RTU protocol flavours)
49             sub header {
50 60     60 0 150 my $self = shift;
51 60 100       133 if (@_) {
52 6         12 $self->{_header} = $_[0];
53             }
54 60   100     273 return ($self->{_header} || '');
55             }
56              
57             # Get/set request additional trailer (for RTU?)
58             # TODO
59             sub trailer {
60 54     54 0 64 my $self = shift;
61 54 50       106 if (@_) {
62 0         0 $self->{_trailer} = $_[0];
63             }
64 54   50     263 return ($self->{_trailer} || '');
65             }
66              
67             # Given function code, return its structure (parameters)
68             sub structure {
69 54     54 0 59 my $self = $_[0];
70 54         94 my $func = $self->function();
71 54         84 my @params = ();
72              
73             # Multiple read requests
74 54 100 66     498 if ( $func == &Protocol::Modbus::FUNC_READ_COILS
    100 100        
    50 66        
75             || $func == &Protocol::Modbus::FUNC_READ_INPUTS
76             || $func == &Protocol::Modbus::FUNC_READ_HOLD_REGISTERS
77             || $func == &Protocol::Modbus::FUNC_READ_INPUT_REGISTERS)
78             {
79 36         157 @params = (&Protocol::Modbus::PARAM_ADDRESS, &Protocol::Modbus::PARAM_QUANTITY);
80             }
81              
82             # Single write requests
83             elsif ($func == &Protocol::Modbus::FUNC_WRITE_COIL) {
84 13         64 @params = (&Protocol::Modbus::PARAM_ADDRESS, &Protocol::Modbus::PARAM_VALUE,);
85             }
86              
87             # Single write of register
88             elsif ($func == &Protocol::Modbus::FUNC_WRITE_REGISTER) {
89 5         18 @params = (&Protocol::Modbus::PARAM_ADDRESS, &Protocol::Modbus::PARAM_VALUE,);
90             }
91             else {
92 0         0 warn("UNIMPLEMENTED REQUEST");
93             }
94              
95 54         134 return (@params);
96             }
97              
98             sub function {
99 108     108 0 119 my $self = $_[0];
100 108         521 return $self->{_options}->{function};
101             }
102              
103             sub options {
104 6     6 0 7 my $self = $_[0];
105 6         18 return $self->{_options};
106             }
107              
108             1;