File Coverage

blib/lib/X10.pm
Criterion Covered Total %
statement 33 121 27.2
branch 0 46 0.0
condition 0 6 0.0
subroutine 11 22 50.0
pod 0 3 0.0
total 44 198 22.2


line stmt bran cond sub pod time code
1              
2             # Copyright (c) 1999-2017 Rob Fugina
3             # Distributed under the terms of the GNU Public License, Version 3.0
4              
5             package X10;
6              
7 1     1   982 use Data::Dumper;
  1         7303  
  1         59  
8 1     1   7 use File::Basename;
  1         2  
  1         90  
9 1     1   426 use FileHandle;
  1         8437  
  1         5  
10 1     1   872 use POSIX;
  1         5970  
  1         5  
11              
12 1     1   2349 use strict;
  1         2  
  1         38  
13              
14 1     1   496 use X10::Macro;
  1         2  
  1         27  
15 1     1   591 use X10::MacroProc;
  1         2  
  1         22  
16 1     1   490 use X10::SchedEvent;
  1         2  
  1         43  
17 1     1   461 use X10::Scheduler;
  1         2  
  1         33  
18 1     1   349 use X10::Server;
  1         2  
  1         31  
19              
20 1     1   4 use vars qw($VERSION);
  1         1  
  1         1162  
21              
22             $VERSION = 0.04;
23              
24             sub new
25             {
26 0     0 0   my $type = shift;
27              
28 0           my $self = bless { @_ }, $type;
29              
30 0 0         $self->{verbose} = 1 if $self->{debug};
31 0     0     $self->{logger} = sub { $self->syslog(@_) };
  0            
32              
33 0 0         unless ($self->{controller_type})
34             {
35 0           warn "Interface type must be specified\n";
36 0           return undef;
37             }
38              
39 0           my $controller = $self->{controller_type};
40              
41 0 0         if (eval "require $controller")
42             {
43 0           $controller->import; # just in case
44             }
45             else
46             {
47 0           die "Can't load module for $controller: ", $@;
48             }
49              
50             $self->{controller} = $controller->new(
51             port => $self->{controller_port},
52             debug => $self->{debug},
53             verbose => $self->{verbose},
54 0     0     logger => sub { $self->syslog(@_) },
55 0           );
56              
57             $self->{controller}->register_listener(
58 0     0     sub { $self->syslog('info', "Event: %s", $_[0]->as_string) }
59 0           );
60              
61 0 0         if (exists $self->{devices})
62             {
63             # load device config
64             }
65              
66 0 0         if (exists $self->{schedulerconfig})
67             {
68             $self->{scheduler} = new X10::Scheduler(
69             configfile => $self->{schedulerconfig},
70             controller => $self->{controller},
71             debug => $self->{debug},
72             verbose => $self->{verbose},
73 0     0     logger => sub { $self->syslog(@_) },
74 0           latitude => 38.74274,
75             longitude => -90.560143,
76             );
77              
78 0 0         unless ($self->{scheduler})
79             {
80 0           warn "Problem creating macro processor";
81 0           return undef;
82             }
83              
84             }
85              
86 0 0         if (exists $self->{macroconfig})
87             {
88             $self->{macrop} = new X10::MacroProc(
89             configfile => $self->{macroconfig},
90             controller => $self->{controller},
91             debug => $self->{debug},
92             verbose => $self->{verbose},
93 0     0     logger => sub { $self->syslog(@_) },
94 0           );
95              
96 0 0         unless ($self->{macrop})
97             {
98 0           warn "Problem creating macro processor";
99 0           return undef;
100             }
101              
102             }
103              
104 0 0         if (exists $self->{server_port})
105             {
106             $self->{server} = new X10::Server(
107             controller => $self->{controller},
108             debug => $self->{debug},
109             verbose => $self->{verbose},
110             server_port => $self->{server_port},
111 0     0     logger => sub { $self->syslog(@_) },
112 0           );
113              
114 0 0         unless ($self->{server})
115             {
116 0           warn "Problem creating network server";
117 0           return undef;
118             }
119             }
120              
121 0           return $self;
122             }
123              
124              
125             sub run
126             {
127 0     0 0   my $self = shift;
128              
129             # this method plans to never return...
130              
131 0           $self->{running} = 1;
132              
133 0     0     $SIG{'INT'} = sub { $self->{running} = 0; };
  0            
134 0     0     $SIG{'TERM'} = sub { $self->{running} = 0; };
  0            
135              
136 0           $self->syslog('info', "%s service starting", $self->{controller_type});
137              
138 0           my $next_wakeup = 0;
139              
140             X10RUNMAINLOOP:
141 0           while ($self->{running})
142             {
143 0 0         $self->{logger}->('info', "Entering mainloop") if $self->{debug};
144              
145 0           my %fdindex;
146 0           foreach my $module (
147 0           grep { exists $self->{$_} } qw(controller server macrop)
148             )
149             {
150 0           foreach my $fd ($self->{$module}->select_fds)
151             {
152 0           $fdindex{$fd} = $self->{$module};
153             }
154             }
155              
156 0 0         $self->syslog('info', "All FDs are %s\n", join(', ', keys %fdindex)) if $self->{debug};
157              
158 0           my $rfd = '';
159 0           foreach (keys %fdindex) { vec($rfd, $_, 1) = 1; }
  0            
160              
161             # done setting up FD array
162              
163             # figure out if we have to wake up at a certain time:
164              
165 0           my $timeout = undef;
166              
167 0 0         if ($self->{scheduler})
168             {
169 0           my $next_event_time = $self->{scheduler}->next_event_time;
170              
171 0 0         if ($next_event_time)
172             {
173 0           $timeout = $next_event_time - int(time);
174 0 0         $timeout = 0 if ($timeout < 0);
175             }
176              
177 0 0 0       if ( (defined $timeout) && $next_event_time != $next_wakeup)
178             {
179 0           $next_wakeup = $next_event_time;
180 0           $self->syslog('info', "Next Scheduled Event: %s (%s seconds away)",
181             strftime("%a %b %e %H:%M %Y", localtime($next_event_time)),
182             $timeout,
183             );
184             }
185              
186             }
187              
188             # done calculating wakeup time
189              
190 0           my $readers;
191 0           my $fdcount = select($readers=$rfd, undef, undef, $timeout);
192              
193 0 0 0       if ($fdcount > 0)
    0          
194             {
195 0 0         $self->{logger}->('info', "Got %s FDs to handle", $fdcount) if $self->{debug};
196              
197 0           foreach (keys %fdindex)
198             {
199 0 0         if (vec($readers, $_, 1))
200             {
201 0 0         $self->syslog('info', "Processing input on FD %s (%s)\n", $_, $fdindex{$_}) if $self->{debug};
202 0           $fdindex{$_}->handle_input;
203             }
204             }
205              
206             }
207             elsif ($fdcount < 0 && $! != 4) # ignore Interrupted System Call
208             {
209 0           $self->{logger}->('info', "Error %d in select(): %s", $!, $!);
210             }
211              
212 0 0         if ($self->{scheduler})
213             {
214 0           $self->{scheduler}->run;
215             }
216              
217             }
218              
219 0           $self->syslog('info', "%s service shutting down", $self->{controller_type});
220              
221             }
222              
223             sub syslog
224             {
225 0     0 0   my $self = shift;
226              
227 0           my $level = shift;
228 0           my $format = shift;
229 0           my $message = sprintf($format, @_);
230              
231 0           my $facility = "local5";
232 0           my $tag = sprintf "%s[%s]",
233             basename($0, ".pl"),
234             $$,
235             ;
236              
237 0 0         if ($self->{debug})
238             {
239 0           printf "syslog message: %s\n", $message;
240             }
241             else
242             {
243 0           my $fh = new FileHandle;
244 0           $fh->open("|/usr/bin/logger -p $facility.$level -t $tag");
245 0           $fh->print($message);
246 0           $fh->close;
247             }
248             }
249              
250              
251              
252             1;
253