File Coverage

blib/lib/ControlX10/CM17.pm
Criterion Covered Total %
statement 57 57 100.0
branch 27 30 90.0
condition n/a
subroutine 5 5 100.0
pod 0 3 0.0
total 89 95 93.6


line stmt bran cond sub pod time code
1             package ControlX10::CM17;
2              
3 1     1   2490 use strict;
  1         2  
  1         34  
4 1     1   5 use vars qw($VERSION $DEBUG @ISA @EXPORT @EXPORT_OK);
  1         3  
  1         893  
5              
6             require Exporter;
7              
8             @ISA = qw(Exporter);
9             @EXPORT= qw( send_cm17 );
10             @EXPORT_OK= qw();
11             ($VERSION) = q$Revision: 0.07 $ =~ /: (\S+)/; # Note: cvs version reset when we moved to sourceforge
12             $DEBUG = 0;
13              
14             #-----------------------------------------------------------------------------
15             #
16             # An X10 firecracker interface, used by Misterhouse ( http://misterhouse.net )
17             #
18             # Uses the Windows or Posix SerialPort.pm functions by Bill Birthisel,
19             # available on CPAN
20             # Protocol documented at: http://www.x10.com/manuals/cm17a_proto.txt
21             # http://www.excel.net/~dpeterse/cm17a.htm
22             #
23             #-----------------------------------------------------------------------------
24              
25             my %table_hcodes = qw(A 01100 B 01110 C 01000 D 01010 E 10000 F 10010 G 10100 H 10110
26             I 11100 J 11110 K 11000 L 11010 M 00000 N 00010 O 00100 P 00110);
27              
28             my %table_dcodes = qw(1J 00000000000 1K 00000100000 2J 00000010000 2K 00000110000
29             3J 00000001000 3K 00000101000 4J 00000011000 4K 00000111000
30             5J 00001000000 5K 00001100000 6J 00001010000 6K 00001110000
31             7J 00001001000 7K 00001101000 8J 00001011000 8K 00001111000
32             9J 10000000000 9K 10000100000 AJ 10000010000 AK 10000110000
33             BJ 10000001000 BK 10000101000 CJ 10000011000 CK 10000111000
34             DJ 10001000000 DK 10001100000 EJ 10001010000 EK 10001110000
35             FJ 10001001000 FK 10001101000 GJ 10001011000 GK 10001111000
36             L 00010001000 M 00010011000 O 00010010000 N 00010100000 P 00010000000);
37              
38             sub send_cm17 {
39 15 50   15 0 864 return unless ( 2 == @_ );
40 15         52 return ControlX10::CM17::send (@_);
41             }
42              
43             sub send {
44 23     23 0 110 my ($serial_port, $house_code) = @_;
45            
46 23         255 my ($house, $code) = $house_code =~ /(\S)(\S+)/;
47              
48 23 50       119 if (exists $main::config_parms{debug}) {
49 23 100       101 $DEBUG = ($main::config_parms{debug} eq 'X10') ? 1 : 0;
50             }
51 23 100       79 print "CM17: $serial_port house=$house code=$code\n" if $DEBUG;
52            
53 23         61 my $data = $table_hcodes{$house};
54 23 100       55 unless ($data) {
55 1         7 print "CM17.pm error. Invalid house code: $house\n";
56 1         6 return;
57             }
58             # Check for +-## brighten/dim commands (e.g. 7+5 F-95)
59             # Looks like it takes 7 levels to go full bright/dim (14%).
60 22 100       67 if ($code =~ /(\S)([\+\-])(\d+)/) {
61 2         12 my $device= $1;
62 2         6 my $dir = $2;
63 2         6 my $level = $3;
64 2         5 my $ok;
65 2 50       8 print "Running CM17 dim/bright loop: device=$device $dir=$dir level=$level\n" if $DEBUG;
66             # The CM17 dim/bright has not device address, so we must first
67             # address the device (need to make sure it is on anyway)
68 2         37 &send($serial_port, $house . $device . 'J');
69 2 100       41 my $code = ($dir eq '+') ? 'L' : 'M';
70 2         39 while ($level >= 0) {
71 5         46 $ok = &send($serial_port, $house . $code);
72 5         165 $level -= 14;
73             }
74 2         35 return $ok;
75             }
76              
77             # Check for #J/#K or L/M/O/N
78 20         50 my $data2 = $table_dcodes{$code};
79 20 100       52 $data2 = $table_dcodes{substr($code, 1)} unless $data2;
80              
81 20 100       49 unless ($data2) {
82 2         15 print "CM17.pm error. Invalid device code: $code.\n";
83 2         11 return;
84             }
85             # Header + data + footer = 40 bits
86 18         188 &send_bits($serial_port, '1101010110101010' . $data . $data2 . '10101101');
87             }
88              
89             sub send_bits {
90 18     18 0 40 my ($serial_port, $bits) = @_;
91 18         365 my @bits = split //, $bits;
92              
93             # Reset the device
94 18         101 $serial_port->dtr_active(0);
95 18         84 $serial_port->rts_active(0);
96 18         1803277 select (undef, undef, undef, .100); # How long??
97              
98              
99             # Turn the device on
100 18         312 $serial_port->dtr_active(1);
101 18         159 $serial_port->rts_active(1);
102 18         3608494 select (undef, undef, undef, .20); # How long??
103              
104 18 100       460 print "CM17: Sending: " if $DEBUG;
105 18         135 while (@bits) {
106 720         1411 my $bit = shift @bits;
107            
108 720 100       1336 if ($bit) {
109 324         976 $serial_port->pulse_dtr_off(1);
110 324 100       2335 print "1" if $DEBUG;
111             }
112             else {
113 396         938 $serial_port->pulse_rts_off(1);
114 396 100       2340 print "0" if $DEBUG;
115             }
116             }
117             # Leave the device on till switch occurs ... emperically derived
118             # - 50->70 ms seemed to be the minnimum
119 18         79 $serial_port->dtr_active(1);
120 18         96 $serial_port->rts_active(1);
121 18         2711483 select (undef, undef, undef, .150);
122              
123 18 100       175 print " done\n" if $DEBUG;
124              
125             # Turn the device off
126 18         278 $serial_port->dtr_active(0);
127 18         160 $serial_port->rts_active(0);
128              
129             }
130              
131             1; # for require
132             __END__