| 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; |