File Coverage

blib/lib/RFID/Reader.pm
Criterion Covered Total %
statement 50 84 59.5
branch 15 32 46.8
condition 4 10 40.0
subroutine 12 19 63.1
pod 5 14 35.7
total 86 159 54.0


line stmt bran cond sub pod time code
1             package RFID::Reader;
2             $VERSION=0.005;
3             @ISA=qw(Exporter);
4             @EXPORT_OK=qw(hexdump ref_tainted);
5              
6             # Written by Scott Gifford
7             # Copyright (C) 2004-2006 The Regents of the University of Michigan.
8             # See the file LICENSE included with the distribution for license
9             # information.
10              
11             =head1 NAME
12              
13             RFID::Reader - Abstract base class for an RFID reader
14              
15             =head1 SYNOPSIS
16              
17             This abstract base class provides a general framework for a generic
18             RFID reader. To actually create a reader, you'll have to use an
19             object corresponding to the type of reader you're using.
20              
21             This documentation discusses aspects of an RFID reader that apply to
22             all readers.
23              
24             Here's an example of how you might use a class derived from this one:
25              
26             use RFID::Blammo::Reader::TCP;
27             my $reader =
28             RFID::Blammo::Reader::TCP->new(PeerAddr => 10.20.30.40,
29             PeerPort => 4001)
30             or die "Couldn't create Blammo reader";
31             my $version = $reader->get("ReaderVersion");
32             $reader->set(AntennaSequence => [ 4,3,2,1]);
33             my @tags = $reader->readtags();
34             foreach my $tag (@tags)
35             {
36             print "I see tag ",$tag->type,".",$tag->id,"\n";
37             }
38              
39             =head1 DESCRIPTION
40              
41             This abstract base class provides a general framework and some utility
42             functions for writing an RFID reader. It also provides emulation for
43             some features which may not be supported by all readers.
44              
45             Because of its general nature, many of the options and methods
46             described here may not be supported in your specific reader. They are
47             documented here so that all readers that implement these features will
48             implement them in the same manner. To make this clearer, elements of
49             this class that should work for all readers will be marked I
50             Readers>, while elements that will only work with some readeres will
51             be marked I. To find out whether your reader supports a
52             specific reader, consult its documentation.
53              
54             =cut
55              
56 8     8   24457 use strict;
  8         26  
  8         419  
57 8     8   51 use warnings;
  8         17  
  8         261  
58              
59 8     8   50 use Carp;
  8         15  
  8         18949  
60              
61             # Prototype
62             sub uniq(&@);
63              
64             sub _init
65             {
66 1     1   744 my $self = shift;
67              
68 1 50       8 if ($ENV{RFID_DEBUG})
69             {
70 0         0 warn "Turning on debugging.\n";
71 0         0 $self->set(Debug => $ENV{RFID_DEBUG});
72             }
73 1         5 $self;
74             }
75              
76              
77             =head2 Methods
78              
79             =cut
80              
81              
82             # We should emulate:
83             # Mask
84              
85             =head3 set
86              
87             This method must be supported by I.
88              
89             Set one or more properties associated with a reader. Depending on
90             implementation, this may send one or more commands to the reader, set
91             an internal flag, or take some other action.
92              
93             This method takes a hash with the properties to be set as keys, and
94             their new values as values. It returns a list of errors that occured;
95             if no errors occured, it will return an empty list. In a scalar
96             context, that evaluates to the number of errors that occured, so you
97             can test for errors like this:
98              
99             my @errs = $reader->set(SomeVariable => "New Value") == 0
100             or die "Couldn't set SomeVariable: @errs";
101              
102             See L for the properties that can be set.
103              
104             =cut
105              
106             sub set
107             {
108 2     2 1 3 my $self = shift;
109 2         6 my(%p)=@_;
110 2         3 my @errs;
111              
112 2         9 while(my($k,$v) = each(%p))
113             {
114 2 100       7 if ($k eq 'UniqueTags')
    50          
115             {
116 1         5 $self->{_unique_tags} = $v;
117             }
118             elsif ($k eq 'Debug')
119             {
120 0         0 $self->{_debug} = $v;
121             }
122             else
123             {
124 1         5 push(@errs,"Unknown setting '$k'\n");
125             }
126             }
127 2         8 @errs;
128             }
129              
130             =head3 get
131              
132             This method must be supported by I.
133              
134             Get various properties of the reader or the internal state of the
135             object. This method takes a list of parameters whose values you'd
136             like to get. In a list context, it returns a hash with the parameters
137             you asked for as the keys, and their values as the values. In a
138             scalar context, it returns the value of the last property requested.
139             If a value for the requested property can't be found, it is set to
140             C.
141              
142             For example:
143              
144             my $ReaderVersion = $reader->get('ReaderVersion');
145             my %props = $reader->get(qw(ReaderVersion AntennaSequence ));
146              
147             See L for the properties that can be retreived
148             with I.
149              
150             =cut
151              
152             sub get
153             {
154 3     3 1 7 my $self = shift;
155 3         5 my %ret;
156              
157 3         38 foreach my $var (@_)
158             {
159 3 100       13 if ($var eq 'UniqueTags')
    50          
160             {
161 2   100     15 $ret{$var} = $self->{_unique_tags}||0;
162             }
163             elsif ($var eq 'Debug')
164             {
165 0   0     0 $ret{$var} = $self->{_unique_tags}||0;
166             }
167             }
168 3 50       654 if (wantarray)
169             {
170 0         0 return %ret;
171             }
172             else
173             {
174             # Return last value
175 3         17 return $ret{$_[$#_]};
176             }
177             }
178              
179             =head3 readtags
180              
181             This method must be supported by I.
182              
183             Read all of the tags in the reader's field, honoring any settings
184             affecting the reading and filtering of tags. This returns a (possibly
185             empty) list of L objects (or objects derived from
186             this type) . For example:
187              
188             my @tags = $reader->readtags();
189             foreach my $tag (@tags)
190             {
191             print "I see tag ",$tag->type,".",$tag->id,"\n";
192             }
193              
194             In the event of a serious error, this method will raise an exception
195             with C. If you want your program to keep going in the face of
196             serious errors, you should catch the exception with C.
197              
198             Parameters are a hash-style list of parameters that should be
199             L for just this read.
200              
201             =cut
202              
203             sub readtags
204             {
205 0     0 1 0 croak "readtags is not implemented in abstract base clase ".__PACKAGE__;
206             }
207              
208              
209             =head3 sleeptags
210              
211             This method is supported by I.
212              
213             Request that all tags addressed by the reader go to sleep, causing
214             them to ignore all requests from the reader until they are
215             L. Which tags are addressed by the reader is
216             affected by various settings, possibly including L and
217             L.
218              
219             Parameters are a hash-style list of parameters that should be
220             L for just this read.
221              
222             In the event of a serious error, this method will raise an exception
223             with C. If you want your program to keep going in the face of
224             serious errors, you should catch the exception with C.
225              
226             =cut
227              
228             sub sleeptags
229             {
230 0     0 1 0 croak "sleeptags is not implemented in abstract base clase ".__PACKAGE__;
231             }
232              
233             =head3 waketags
234              
235             Request that all tags addressed by the reader which are currently
236             L wake up, causing them to once again pay attention
237             to requests from the reader. Which tags are addressed by the reader
238             is affected by various settings, possibly including L and
239             L.
240              
241             Parameters are a hash-style list of parameters that should be
242             L for just this read.
243              
244             In the event of a serious error, this method will raise an exception
245             with C. If you want your program to keep going in the face of
246             serious errors, you should catch the exception with C.
247              
248             =cut
249              
250             sub waketags
251             {
252 0     0 1 0 croak "waketags is not implemented in abstract base clase ".__PACKAGE__;
253             }
254              
255              
256              
257             #####
258             # Functions for use by derived classes.
259             #####
260              
261             # Push the current values for various settings onto an internal stack,
262             # then set them to their new values. popoptions will restore the
263             # original values.
264             sub pushoptions
265             {
266 0     0 0 0 my $self = shift;
267 0         0 my(%p)=@_;
268              
269 0         0 my %prev;
270 0         0 while (my($k,$v)=each(%p))
271             {
272             # Get the option
273 0         0 my $curval = $self->get($k);
274 0 0       0 defined($curval)
275             or croak "Couldn't get initial value of '$k'!\n";
276 0         0 $prev{lc $k} = $curval;
277             }
278 0         0 push(@{$self->{_option_stack}},\%prev);
  0         0  
279 0         0 $self->set(%p);
280             }
281              
282             # Restore values set by pushoptions.
283             sub popoptions
284             {
285 0     0 0 0 my $self = shift;
286              
287 0 0       0 my $prev = pop(@{$self->{_option_stack}})
  0         0  
288             or croak "No options to pop!!";
289 0         0 $self->set(%$prev);
290             }
291              
292             # Functions for use by derived classes.
293             sub filter_tags
294             {
295 2     2 0 3 my $self = shift;
296 2         5 my @tags = @_;
297              
298 2 100 66     15 if ($self->{_unique_tags} || $self->{_combine_antennas})
299             {
300 3     3   8 @tags = uniq { $a->tagcmp($b) }
301 1         7 sort { $a->tagcmp($b) }
  5         13  
302             @tags;
303            
304             # This is never used, but the code is written already, so it's
305             # here as a placeholder in case it's implemented later.
306 1 50       7 if ($self->{_combine_antennas})
307             {
308 0         0 my $lasttag;
309 0         0 foreach my $i (0..$#tags)
310             {
311 0 0 0     0 if (defined($lasttag) and ($tags[$i]->id eq $lasttag))
312             {
313 0         0 splice(@tags,$i,1);
314             }
315             }
316             }
317             }
318 2         12 @tags;
319             }
320              
321             # Utility Functions
322             sub sortcmp
323             {
324 3     3 0 3 my $sub = shift;
325 3         6 local($a,$b)=@_;
326 3         6 $sub->();
327             }
328              
329             sub uniq(&@)
330             {
331 1     1 0 3 my($cmpsub, @list)=@_;
332 1 50       4 my $last = shift @list
333             or return ();
334 1         2 my @ret =($last);
335 1         3 foreach (@list)
336             {
337 3 100       6 push(@ret,$_)
338             unless sortcmp($cmpsub,$_,$last)==0;
339 3         6 $last = $_;
340             }
341 1         3 @ret;
342             }
343              
344             # Internal debugging function.
345             sub debug
346             {
347 8 50   8 0 41 return unless $_[0]->{_debug};
348              
349 0         0 my $self = shift;
350 0 0       0 if ($_[0] =~ /^\d+$/)
351             {
352 0 0       0 return unless $self->{_debug} >= $_[0];
353 0         0 shift;
354             }
355 0         0 warn((caller(1))[3],": ",@_);
356             }
357              
358             # Return the current debug level
359             sub debuglevel
360             {
361 0     0 0 0 my $self = shift;
362 0         0 $self->{_debug};
363             }
364              
365             sub hexdump
366             {
367 0     0 0 0 join(' ',unpack("H2 " x length($_[0]),$_[0]),'');
368             }
369              
370             # From perlsec(1)
371             sub ref_tainted {
372 7     7 0 67 return ! eval { eval("#" . substr(${$_[0]}, 0, 0)); 1 };
  7         16  
  7         1312  
  4         31  
373             }
374              
375             =head2 Properties
376              
377             There are various properties that are managed by the L and
378             L methods. Some of these settings will cause one or more
379             commands to be sent to the reader, while other will simply return the
380             internal state of the object. The value for a property is often a
381             string, but can also be an arrayref or hashref.
382              
383             =head3 AntennaSequence
384              
385             I.
386              
387             An arrayref of the antenna names that should be queried, and in what
388             order. RFID drivers can name their antennas any way they like, though
389             often they will be numbers. For example:
390              
391             $reader->set(AntennaSequence => [0,1,2,3]);
392              
393             The default AntennaSequence is reader-specific.
394              
395             =head3 Debug
396              
397             I.
398              
399             Control the amount of debugging information sent to C. A
400             higher value for this property will cause more information to be
401             output.
402              
403             =head3 Mask
404              
405             I.
406              
407             Set or get a bitmask for the tags. After setting the mask, all
408             commands will only apply to tags whose IDs match the given mask.
409              
410             The mask format is a string beginning with the bits of the tag as a
411             hex number, optionally followed by a slash and the size of the mask,
412             optionally followed by the bit offset in the tag ID where the
413             comparison should start. For example, to look for 8 ones at the end
414             of a tag, you could use:
415              
416             $reader->set(Mask => 'ff/8/88');
417              
418             A zero-length mask (which matches all tags) is represented by an empty
419             string.
420              
421             =head3 UniqueTags
422              
423             I, possibly through emulation.
424              
425             A boolean value controlling whether duplicate tags should be removed
426             from the list returned by L.
427              
428             =head1 SEE ALSO
429              
430             L, L, L,
431             L, The manual for
432             your particular RFID driver class.
433              
434             =head1 AUTHOR
435              
436             Scott Gifford Egifford@umich.eduE, Esgifford@suspectclass.comE
437              
438             Copyright (C) 2004-2006 The Regents of the University of Michigan.
439              
440             See the file LICENSE included with the distribution for license
441             information.
442              
443             =cut
444              
445              
446             1;
447