line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
3
|
|
|
3
|
|
2066
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
100
|
|
2
|
3
|
|
|
3
|
|
13
|
use warnings; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
160
|
|
3
|
|
|
|
|
|
|
package Device::RFXCOM::Decoder::Visonic; |
4
|
|
|
|
|
|
|
$Device::RFXCOM::Decoder::Visonic::VERSION = '1.163170'; |
5
|
|
|
|
|
|
|
# ABSTRACT: Device::RFXCOM::Decoder::Visonic decode Visonic RF messages |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
3
|
|
|
3
|
|
52
|
use 5.006; |
|
3
|
|
|
|
|
10
|
|
9
|
3
|
|
|
3
|
|
12
|
use constant DEBUG => $ENV{DEVICE_RFXCOM_DECODER_VISONIC_DEBUG}; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
203
|
|
10
|
3
|
|
|
3
|
|
14
|
use Carp qw/croak/; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
156
|
|
11
|
3
|
|
|
3
|
|
15
|
use Device::RFXCOM::Decoder qw/hi_nibble lo_nibble/; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
225
|
|
12
|
|
|
|
|
|
|
our @ISA = qw(Device::RFXCOM::Decoder); |
13
|
3
|
|
|
3
|
|
16
|
use Device::RFXCOM::Response::Security; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
78
|
|
14
|
3
|
|
|
3
|
|
14
|
use Device::RFXCOM::Response::Sensor; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
1901
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my %bits = ( 36 => 'powercode', 66 => 'codesecure' ); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub decode { |
20
|
44
|
|
|
44
|
1
|
79
|
my ($self, $parent, $message, $bytes, $bits, $result) = @_; |
21
|
44
|
100
|
|
|
|
231
|
my $method = $bits{$bits} or return; |
22
|
6
|
|
|
|
|
30
|
return $self->$method($parent, $message, $bytes, $bits, $result); |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub codesecure { |
27
|
3
|
|
|
3
|
1
|
10
|
my ($self, $parent, $message, $bytes, $bits, $result) = @_; |
28
|
|
|
|
|
|
|
# parity check? |
29
|
|
|
|
|
|
|
|
30
|
3
|
|
|
|
|
21
|
my $code = |
31
|
|
|
|
|
|
|
sprintf '%02x%02x%02x%02x', |
32
|
|
|
|
|
|
|
$bytes->[0], $bytes->[1], $bytes->[2], $bytes->[3]; |
33
|
|
|
|
|
|
|
|
34
|
3
|
|
|
|
|
18
|
my $device = |
35
|
|
|
|
|
|
|
sprintf 'codesecure.%02x%02x%02x%x', |
36
|
|
|
|
|
|
|
$bytes->[4], $bytes->[5], $bytes->[6], hi_nibble($bytes->[7]); |
37
|
|
|
|
|
|
|
my $event = |
38
|
|
|
|
|
|
|
{ 0x1 => "light", |
39
|
|
|
|
|
|
|
0x2 => "arm-away", |
40
|
|
|
|
|
|
|
0x4 => "disarm", |
41
|
|
|
|
|
|
|
0x8 => "arm-home", |
42
|
3
|
|
|
|
|
31
|
}->{lo_nibble($bytes->[7])}; |
43
|
3
|
100
|
|
|
|
229
|
unless ($event) { |
44
|
|
|
|
|
|
|
# probably invalid message |
45
|
|
|
|
|
|
|
# TOFIX: figure out parity check so this isn't required |
46
|
1
|
|
|
|
|
7
|
return; |
47
|
|
|
|
|
|
|
} |
48
|
2
|
|
|
|
|
9
|
my $repeat = $bytes->[8]&0x4; |
49
|
2
|
|
|
|
|
4
|
my $low_bat = $bytes->[8]&0x8; |
50
|
2
|
|
|
|
|
13
|
my %args = |
51
|
|
|
|
|
|
|
( |
52
|
|
|
|
|
|
|
event => $event, |
53
|
|
|
|
|
|
|
device => $device, |
54
|
|
|
|
|
|
|
); |
55
|
2
|
100
|
|
|
|
11
|
$args{repeat} = 1 if ($repeat); |
56
|
2
|
100
|
|
|
|
5
|
push @{$result->{messages}}, |
|
2
|
|
|
|
|
118
|
|
57
|
|
|
|
|
|
|
Device::RFXCOM::Response::Security->new(%args), |
58
|
|
|
|
|
|
|
Device::RFXCOM::Response::Sensor->new(device => $device, |
59
|
|
|
|
|
|
|
measurement => 'battery', |
60
|
|
|
|
|
|
|
value => $low_bat ? 10 : 90, |
61
|
|
|
|
|
|
|
units => '%'); |
62
|
2
|
|
|
|
|
17
|
return 1; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub powercode { |
67
|
3
|
|
|
3
|
1
|
9
|
my ($self, $parent, $message, $bytes, $bits, $result) = @_; |
68
|
3
|
|
|
|
|
4
|
my $parity; |
69
|
3
|
|
|
|
|
12
|
foreach (0 .. 3) { |
70
|
12
|
|
|
|
|
31
|
$parity ^= hi_nibble($bytes->[$_]); |
71
|
12
|
|
|
|
|
29
|
$parity ^= lo_nibble($bytes->[$_]); |
72
|
|
|
|
|
|
|
} |
73
|
3
|
100
|
|
|
|
10
|
unless ($parity == hi_nibble($bytes->[4])) { |
74
|
1
|
|
|
|
|
4
|
warn |
75
|
|
|
|
|
|
|
sprintf("Possible Visonic powercode with parity error %x != %x\n", |
76
|
|
|
|
|
|
|
$parity, hi_nibble($bytes->[4])); |
77
|
1
|
|
|
|
|
12
|
return; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
2
|
|
|
|
|
17
|
my $device = sprintf('powercode.%02x%02x%02x', |
81
|
|
|
|
|
|
|
$bytes->[0], $bytes->[1], $bytes->[2]); |
82
|
2
|
100
|
|
|
|
10
|
$device .= 's' unless ($bytes->[3] & 0x4); # suffix s for secondary contact |
83
|
2
|
|
|
|
|
4
|
my $restore = $bytes->[3] & 0x8; |
84
|
2
|
|
|
|
|
3
|
my $event = $bytes->[3] & 0x10; |
85
|
2
|
|
|
|
|
3
|
my $low_bat = $bytes->[3] & 0x20; |
86
|
2
|
|
|
|
|
3
|
my $alert = $bytes->[3] & 0x40; |
87
|
2
|
|
|
|
|
4
|
my $tamper = $bytes->[3] & 0x80; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# I assume $event is to distinguish whether it's a new event or just a |
90
|
|
|
|
|
|
|
# heartbeat message? |
91
|
2
|
100
|
|
|
|
14
|
my %args = |
92
|
|
|
|
|
|
|
( |
93
|
|
|
|
|
|
|
event => $alert ? 'alert' : 'normal', |
94
|
|
|
|
|
|
|
device => $device, |
95
|
|
|
|
|
|
|
); |
96
|
2
|
100
|
|
|
|
8
|
$args{restore} = 1 if ($restore); |
97
|
2
|
100
|
|
|
|
6
|
$args{tamper} = 1 if ($tamper); |
98
|
2
|
100
|
|
|
|
4
|
push @{$result->{messages}}, |
|
2
|
|
|
|
|
20
|
|
99
|
|
|
|
|
|
|
Device::RFXCOM::Response::Security->new(%args), |
100
|
|
|
|
|
|
|
Device::RFXCOM::Response::Sensor->new(device => $device, |
101
|
|
|
|
|
|
|
measurement => 'battery', |
102
|
|
|
|
|
|
|
value => $low_bat ? 10 : 90, |
103
|
|
|
|
|
|
|
units => '%'); |
104
|
2
|
|
|
|
|
17
|
return 1; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
1; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
__END__ |