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