10 |
10 |
11 my %Objects = (); |
11 my %Objects = (); |
12 my $gotSignal = 0; |
12 my $gotSignal = 0; |
13 my $opt_async = 0; |
13 my $opt_async = 0; |
14 |
14 |
15 sub iohandler($); |
15 sub _iohandler($); |
16 sub import { $opt_async = grep { /^:async/ } @_; } |
16 sub import { $opt_async = grep { /^:async/ } @_; } |
17 |
17 |
18 # Install the signal handler only if we have passed the ':async' tag |
18 # Install the signal handler only if we have passed the ':async' tag |
19 # to the module... |
19 # to the module... |
20 INIT { $SIG{IO} = \&iohandler if $opt_async; } |
20 INIT { $SIG{IO} = \&_iohandler if $opt_async; } |
21 |
21 |
22 # Create a new object. Open all the named devices (read only) |
22 # Create a new object. Open all the named devices (read only) |
23 # and read the current values (as the driver guarantees the |
23 # and read the current values (as the driver guarantees the |
24 # very first read to succeed). |
24 # very first read to succeed). |
25 # The order depends on the order the device names are passed |
25 # The order depends on the order the device names are passed |
57 $self->{fds} = [@fds]; # list of fds |
57 $self->{fds} = [@fds]; # list of fds |
58 $self->{select} = new IO::Select(@fds); |
58 $self->{select} = new IO::Select(@fds); |
59 |
59 |
60 $self->{bits} = $idx * 16; |
60 $self->{bits} = $idx * 16; |
61 $self->{inputBits} = $inputBits; |
61 $self->{inputBits} = $inputBits; |
62 $self->{oldBits} = ""; |
62 $self->{oldBits} = undef; |
63 $self->{changedBits} = ""; |
63 $self->{changedBits} = ""; |
64 |
64 |
65 $self->{changed} = [split //, "0" x $self->{bits} ]; |
65 $self->{changed} = [split //, "0" x $self->{bits} ]; |
66 return $self; |
66 return $self; |
67 } |
67 } |
71 # race condition might occur: while we're waiting for the select() |
71 # race condition might occur: while we're waiting for the select() |
72 # to complete, the SIGIO might be catched. Both, SIGIO as well as |
72 # to complete, the SIGIO might be catched. Both, SIGIO as well as |
73 # the suddenly succeeding select() indicate a possible successful |
73 # the suddenly succeeding select() indicate a possible successful |
74 # read... But only one of them will be successful! |
74 # read... But only one of them will be successful! |
75 |
75 |
76 my ($self, $timeout) = @_; |
76 my ($self, %args) = @_; |
77 |
77 |
78 { |
78 { |
79 local $SIG{IO} = sub { $gotSignal = $_[0] } if $opt_async; |
79 local $SIG{IO} = sub { $gotSignal = $_[0] } if $opt_async; |
80 my @ready = $self->{select}->can_read($timeout); |
80 my @ready = $self->{select}->can_read($args{timeout}); |
81 |
81 |
82 if (!@ready) { |
82 if (!@ready) { |
83 warn "select() returned nothing: $!\n"; |
83 warn "select() returned nothing: $!\n"; |
84 return undef; |
84 return undef; |
85 } |
85 } |
86 |
86 |
87 $self->_read(@ready); |
87 $self->_read(@ready); |
88 } |
88 } |
89 |
89 |
90 $gotSignal and iohandler($gotSignal); |
90 $gotSignal and _iohandler($gotSignal); |
91 $self->{changedBits} = ""; |
|
92 $self->{changed} = [ split //, "0" x $self->{bits} ]; |
|
93 return split //, unpack("b*", $self->{inputBits}); |
91 return split //, unpack("b*", $self->{inputBits}); |
94 } |
92 } |
95 |
93 |
96 sub status { |
94 sub status { |
97 my $self = shift; |
95 my $self = shift; |
98 return split //, unpack("b*", $self->{inputBits}); |
96 return split //, unpack("b*", $self->{inputBits}); |
99 } |
97 } |
100 |
98 |
101 # Read *really* from the board and store the result at the proper |
99 # Read *really* from the board and store the result at the proper |
102 # element of our @inputs array. |
100 # element of our @inputs array. |
103 sub _read { |
101 sub _read($@) { |
104 my ($self, @fds) = @_; |
102 my ($self, @fds) = @_; |
105 my $val; # bit0-7 bit8-15 |
103 my $val; # bit0-7 bit8-15 |
106 |
104 |
107 foreach my $fd (@fds) { |
105 foreach my $fd (@fds) { |
108 my $idx = $self->{idx}->{$fd}; |
106 my $idx = $self->{idx}->{$fd}; |
111 } |
109 } |
112 |
110 |
113 # Now get the difference between the old bits and the current values... |
111 # Now get the difference between the old bits and the current values... |
114 # and then add these values to the array containing the change counters |
112 # and then add these values to the array containing the change counters |
115 |
113 |
|
114 $self->{oldBits} = $self->{inputBits} if not defined $self->{oldBits}; |
116 my $changedBits = $self->{inputBits} ^ $self->{oldBits}; |
115 my $changedBits = $self->{inputBits} ^ $self->{oldBits}; |
117 |
116 |
118 my @changed = split //, unpack("b*", $changedBits); |
117 my @changed = split //, unpack("b*", $changedBits); |
119 #print STDERR "o: ", unpack("b*", $self->{oldBits}), "\n"; |
118 #print STDERR "o: ", unpack("b*", $self->{oldBits}), "\n"; |
120 #print STDERR "n: ", unpack("b*", $self->{inputBits}), "\n"; |
119 #print STDERR "n: ", unpack("b*", $self->{inputBits}), "\n"; |
126 |
125 |
127 $self->{changedBits} |= $changedBits; |
126 $self->{changedBits} |= $changedBits; |
128 $self->{oldBits} = $self->{inputBits}; |
127 $self->{oldBits} = $self->{inputBits}; |
129 } |
128 } |
130 |
129 |
131 sub iohandler($) { |
130 sub _iohandler($) { |
132 # If an interrupt occurs, we've to search for the file descriptor(s) |
131 # If an interrupt occurs, we've to search for the file descriptor(s) |
133 # that caused the interrupt. This is done by a lookup in the module global |
132 # that caused the interrupt. This is done by a lookup in the module global |
134 # %Objects hash. ("fd" -> { fd => XXX, object => XXXX }) |
133 # %Objects hash. ("fd" -> { fd => XXX, object => XXXX }) |
135 |
134 |
136 my $signal = shift; |
135 my $signal = shift; |
137 |
136 |
138 # I do some magic(?) here, since the key isn't usable a a refence |
137 # I do some magic(?) here, since the key isn't usable a a refence |
139 # anymore, we stored the reference itself behind the key, as well |
138 # anymore, we stored the reference itself behind the key, as well |
140 # as the object reference... |
139 # as the object reference... |
141 |
140 |
142 |
|
143 # Now a race condition might occur. It's possible that an other |
|
144 # select() runs too (called in the read() method). |
|
145 my $select = new IO::Select(map { $Objects{$_}->{fd} } keys %Objects); |
141 my $select = new IO::Select(map { $Objects{$_}->{fd} } keys %Objects); |
146 my @ready = $select->can_read(0); |
142 my @ready = $select->can_read(0); |
147 |
143 |
148 foreach (@ready) { |
144 foreach (@ready) { |
149 my $object = $Objects{$_}->{object}; |
145 my $object = $Objects{$_}->{object}; |
197 |
198 |
198 =item new(I<device>,...) |
199 =item new(I<device>,...) |
199 |
200 |
200 Creates a new ME8100 object connected to all the listed devices. |
201 Creates a new ME8100 object connected to all the listed devices. |
201 |
202 |
202 =item read([I<timeout>]) |
203 =item read(I<[timeout =E<gt> timeout]>) |
203 |
204 |
204 Read the input from the devices. This call is guaranteed to succeede |
205 Read the input from the devices. This call is guaranteed to succeede |
205 on the first run, but every following call will block until the status |
206 on the first run, but every following call will block until the status |
206 of the input changed. (This behaviour is due to the driver.) |
207 of the input changed. (This behaviour is due to the driver.) |
207 |
208 |
208 A timeout may be passed. |
209 A timeout may be passed. |
209 |
210 |
210 Every read() resets the register for obtaining the changed bits. |
|
211 |
|
212 On success an array of the input bits is returned, otherwise undef. |
211 On success an array of the input bits is returned, otherwise undef. |
213 |
212 |
214 =item status() |
213 =item status() |
215 |
214 |
216 Returns an array with the current status of all input bits. |
215 Returns an array with the current status of all input bits. |
217 Never blocks. |
216 Never blocks. No side effects. |
218 |
217 |
219 =item changed() |
218 =item changed() |
220 |
219 |
221 Returns an array containing the number of detected changes per input |
220 In array context returns an array containing the counts of changes |
222 bit. |
221 for every single bit. In scalar context returns the total number of |
223 |
222 changes. |
224 =item iohandler(I<signal>) |
223 |
|
224 Every call resets the counter. |
|
225 |
|
226 =item _iohandler(I<signal>) |
225 |
227 |
226 For internal use only. |
228 For internal use only. |
227 |
229 |
228 =item _read() |
230 =item _read() |
229 |
231 |