File Coverage

blib/lib/RFID/Matrics/Reader.pm
Criterion Covered Total %
statement 263 470 55.9
branch 79 220 35.9
condition 22 99 22.2
subroutine 46 76 60.5
pod 4 27 14.8
total 414 892 46.4


line stmt bran cond sub pod time code
1             package RFID::Matrics::Reader;
2             our $VERSION = '0.002';
3             @ISA = qw(RFID::Reader Exporter);
4 4     4   26 use strict;
  4         11  
  4         299  
5            
6             # Written by Scott Gifford
7             # Copyright (C) 2004 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::Matrics::Reader - Abstract base class for a Matrics RFID reader
14            
15             =head1 SYNOPSIS
16            
17             This abstract base class provides most of the methods required for
18             interfacing Perl with a Matrics RFID reader. To actually create an
19             object, use
20             L or
21             L. It is based
22             on L.
23            
24             use RFID::Matrics::Reader::Serial;
25             my $reader =
26             RFID::Matrics::Reader::Serial->new(Port => $com_port_object,
27             Node => 4,
28             Antenna => 1)
29             or die "Couldn't create reader object\n";
30            
31             my @err = $reader->set(PowerLevel => 0xff,
32             Environment => 4) == 0
33             or die "Couldn't set params: @err\n";
34            
35             my @tags = $reader->readtags;
36             foreach my $tag (@tags)
37             {
38             my $tag_info = $tag->get('Antenna','ID','Type');
39             print "I see tag $tag_info{Type}.$tag_info{ID} ".
40             "at antenna $tag_info{Antenna}.\n";
41             }
42            
43             =head1 DESCRIPTION
44            
45             This abstract base class implements the commands for communicating
46             with a Matrics reader. It is written according to the specifications
47             in Matrics' I
48             Specification>, using version 2.8 from October 19th 2003. It was
49             tested with an RDR-001 model reader.
50            
51             To actually create a reader object, use
52             L or
53             L. Those
54             classes inherit from this one.
55            
56             This class inherits some methods and settings from
57             L.
58            
59             =cut
60            
61 4     4   5781 use RFID::Reader qw(hexdump);
  4         6977  
  4         372  
62 4     4   38 use Exporter;
  4         8  
  4         160  
63 4     4   25 use Carp qw(cluck croak carp);
  4         7  
  4         590  
64 4     4   27 use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS);
  4         10  
  4         474  
65             # You shouldn't use the antenna constants anymore, just use numbers 1-4.
66             @EXPORT_OK = qw(MATRICS_ANT_1 MATRICS_ANT_2 MATRICS_ANT_3 MATRICS_ANT_4 hexdump);
67             %EXPORT_TAGS = (ant => [ qw(MATRICS_ANT_1 MATRICS_ANT_2 MATRICS_ANT_3 MATRICS_ANT_4)]);
68            
69 4     4   2458 use RFID::Matrics::CRC qw(crc);
  4         8  
  4         466  
70 4     4   4916 use RFID::EPC::Tag;
  4         27021  
  4         245  
71 4     4   3105 use RFID::Matrics::Tag;
  4         13  
  4         203  
72            
73 4     4   26 use constant MATRICS_ANT_1 => 0xa0;
  4         8  
  4         196  
74 4     4   21 use constant MATRICS_ANT_2 => 0xb0;
  4         7  
  4         159  
75 4     4   20 use constant MATRICS_ANT_3 => 0xc0;
  4         7  
  4         379  
76 4     4   21 use constant MATRICS_ANT_4 => 0xd0;
  4         6  
  4         36458  
77            
78             our %antname = (
79             &MATRICS_ANT_1 => 1,
80             &MATRICS_ANT_2 => 2,
81             &MATRICS_ANT_3 => 3,
82             &MATRICS_ANT_4 => 4,
83             );
84            
85             our %paramblock_setting = (power_level => 1,
86             environment => 1,
87             );
88             our %paramblock_rename = (PowerLevel => 'power_level',
89             Environment => 'environment',
90             Mask => 'Mask',
91             );
92             our %readerstatus_rename = (ReaderVersion => 'version',
93             ReaderSerialNum => 'serialnum',
94             );
95            
96             our %antid = (1 => MATRICS_ANT_1,
97             2 => MATRICS_ANT_2,
98             3 => MATRICS_ANT_3,
99             4 => MATRICS_ANT_4);
100            
101             # Initializer used by derived objects
102             sub _init
103             {
104 3     3   2008341 my $self = shift;
105 3         33 my(%p)=@_;
106            
107 3   66     47 $self->{default_node} = $p{Node}||$p{node};
108 3 50 33     73 $self->{timeout} = $p{timeout}||$p{Timeout}
109             unless ($self->{timeout});
110            
111             # This can't be set again, so let's delete it.
112 3         10 delete $p{node};
113 3         88 delete $p{Node};
114            
115 3         73 my @errs = $self->set(%p);
116 3 50       11 if (grep { $_ !~ /Unknown setting/ } @errs)
  5         45  
117             {
118 0         0 die "Error setting properties: @errs\n";
119             }
120            
121 3   66     25 $self->{default_antenna} = $p{Antenna}||$p{antenna};
122 3 50       18 if (!defined($self->{default_antenna}))
123             {
124 0 0       0 if (defined($self->{_antenna_sequence}))
125             {
126 0         0 $self->{default_antenna} = $self->{_antenna_sequence}[0];
127             }
128             else
129             {
130 0         0 $self->{default_antenna} = 1;
131             }
132             }
133 3 50       17 $self->{_antenna_sequence} = [$self->{default_antenna}]
134             if (!$self->{_antenna_sequence});
135            
136            
137 3 50 33     76 $self->stop_constant_read(node => $self->{default_node})
138             if ($self->{default_node} and (!$p{noinit}));
139            
140 3         30 $self->SUPER::_init(%p);
141             }
142            
143            
144            
145            
146             =head2 METHODS
147            
148             =cut
149            
150             our %_errmsgs = (
151             0xF0 => "READER - Invalid command parameter(s)",
152             0xF1 => "READER - Insufficient data",
153             0xF2 => "READER - Command not supported",
154             0xF3 => "READER - Antenna Fault (not present or shorted)",
155             0xF4 => "READER - DSP Timeout",
156             0xF5 => "READER - DSP Error",
157             0xF6 => "READER - DSP Idle",
158             0xF7 => "READER - Zero Power",
159             0xFF => "READER - Undefined error",
160             );
161            
162             # Prototype
163             sub uniq(&@);
164            
165             sub _setdefaults
166             {
167 36     36   56 my $self = shift;
168 36         41 my($p)=@_;
169 36 100       104 $p->{node} = $self->{default_node}
170             unless defined($p->{node});
171 36 100       102 $p->{antenna} = $self->{default_antenna}
172             unless defined($p->{antenna});
173 36 100 66     358 $p->{antenna} = $antid{$p->{antenna}}
174             if (defined($p->{antenna}) and $p->{antenna} < 10);
175 36         59 $p;
176             }
177            
178             sub _makepacket
179             {
180 15     15   23 my $self = shift;
181 15         542 my(%p)=@_;
182 15         46 $self->_setdefaults(\%p);
183            
184 15   100     67 $p{data}||="";
185 15         338 my $packet = pack("CCCa*",$p{node},length($p{data})+5,$p{cmd},$p{data});
186 15         94 return pack("Ca*v",1,$packet,crc($packet));
187             }
188            
189             sub _parsepacket
190             {
191 17     17   27 my $self = shift;
192 17         26 my($packet)=@_;
193 17         23 my %dat;
194             my $sof;
195            
196 17         25 my $dl = length($packet)-7;
197 17         188 ($sof,@dat{qw(node len cmd status data crc)}) = unpack("CCCCCa${dl}v",$packet);
198 17 50       50 unless ($sof==1)
199             {
200 0         0 return $self->error("No start of frame byte in packet!");
201             }
202 17 50       77 unless (crc(substr($packet,1,-2)) == $dat{crc})
203             {
204 0         0 return $self->error("Bad CRC in packet!\n");
205             }
206 17 50 33     182 if ( ($dat{status} & 0x80)==0x80 or ($dat{status} & 0xC0)==0xC0)
207             {
208 0         0 my $ec = unpack("C",$dat{data});
209 0         0 return $self->error($_errmsgs{$ec},$ec);
210             }
211 17         98 return \%dat;
212             }
213            
214             sub _getpacket
215             {
216 17     17   26 my($self)=@_;
217 17 50       78 my $data = $self->_readbytes(3)
218             or die "Couldn't read data: $!\n";
219 17 50       1280 length($data) == 3
220             or die "Data short read!\n";
221 17         67 my($sof,$addr,$len)=unpack("CCC",$data);
222            
223 17 50       57 my $moredata = $self->_readbytes($len-2)
224             or die "Couldn't read data: $!\n";
225 17 50       509 length($moredata) == ($len-2)
226             or die "Data short read!\n";
227            
228 17 50       60 $self->debug(" RECV: ",hexdump($data.$moredata),"\n")
229             if ($self->{_debug});
230 17         64 return $data.$moredata;
231             }
232            
233             sub _sendpacket
234             {
235 15     15   27 my $self = shift;
236 15         23 my($data)=@_;
237            
238 15 50       41 $self->debug(" SEND: ",hexdump($data),"\n")
239             if ($self->{_debug});
240 15 50       109 $self->_writebytes($data)
241             or die "Couldn't write to COM port: $^E";
242             }
243            
244             sub _do_something
245             {
246 15     15   26 my $self = shift;
247 15         66 my($cmd_sub,$resp_sub,%p)=@_;
248 15         21 my @ret ;
249            
250 15 50       64 my $cmd = $cmd_sub->($self,%p)
251             or return undef;
252 15 50       212 $self->_sendpacket($cmd)
253             or die "Couldn't write command: $!\n";
254            
255 15         4488 while(1)
256             {
257 17 50       138 my $resp = $self->_getpacket()
258             or die "Couldn't read response: $!\n";
259 17 50       67 my $pr = $resp_sub->($self,$resp)
260             or return undef;
261 17         27 push(@ret,$pr);
262 17 100       57 last unless ($pr->{status} & 0x01);
263             }
264 15 100       179 return wantarray?@ret:$ret[0];
265             }
266            
267             =head3 get
268            
269             Get various properties of the reader or the internal state of the
270             object. The syntax is described in L
271             method|RFID::Reader/get> documentation. See L
272             and L for the properties
273             that can be retreived.
274            
275             =cut
276            
277             sub get
278             {
279 4     4 1 8197 my $self = shift;
280 4         14 my %get;
281             my %ret;
282 0         0 my %paramblocks;
283 0         0 my $readerstatus;
284            
285 4         17 foreach my $g (@_)
286             {
287 6 100 33     64 if ($paramblock_rename{$g} or ($g =~ /^(\w+)_Antenna(\d+)$/ and $paramblock_rename{$1}))
    50 66        
    50          
288             {
289 4         13 my($ant,$asv);
290 4 50       31 if ($paramblock_rename{$g})
291             {
292 4         15 $ant = $self->{default_antenna};
293 4         7 $asv = $paramblock_rename{$g};
294             }
295             else
296             {
297 0         0 $ant = $2;
298 0         0 $asv = $paramblock_rename{$1};
299             }
300 4 100       23 if (!$paramblocks{$ant})
301             {
302 2 50       34 $paramblocks{$ant} = $self->getparamblock(antenna => $antid{$ant})
303             or die "Couldn't getparamblock for antenna $ant!";
304             }
305 4 50       9 if ($g eq 'Mask')
306             {
307 0         0 my $masktype = $paramblocks{$ant}{filter_type};
308 0 0       0 if ($masktype == 0)
309             {
310 0         0 $ret{$g}='';
311             }
312             else
313             {
314 0         0 my $mask = bin2hex_big_endian($paramblocks{$ant}{filter_bits});
315 0         0 $mask =~ s/\s//g;
316 0 0       0 if ($masktype == 1)
    0          
    0          
317             {
318 0         0 $ret{$g} = substr($mask,0,2)."/8";
319             }
320             elsif ($masktype == 2)
321             {
322 0         0 $ret{$g} = substr($mask,0,10)."/40";
323             }
324             elsif ($masktype == 3)
325             {
326 0         0 $ret{g} = substr($mask,0,16)."/64";
327             }
328             else
329             {
330             # Error
331 0         0 $ret{g} = undef;
332             }
333             }
334             }
335             else
336             {
337 4         15 $ret{$g} = $paramblocks{$ant}{$asv};
338             }
339             }
340             elsif ($g eq 'AntennaSequence')
341             {
342 0         0 $ret{$g} = [$self->{_antenna_sequence}];
343             }
344             elsif ($readerstatus_rename{$g})
345             {
346 2 50       9 if (!$readerstatus)
347             {
348 2         3 my %p;
349 2         7 $self->_setdefaults(\%p);
350 2 50       29 $readerstatus = $self->getreaderstatus(%p)
351             or die "Couldn't get reader status: $self->{error}";
352             }
353 2         11 $ret{$g}=$readerstatus->{$readerstatus_rename{$g}};
354             }
355             else
356             {
357 0         0 croak "Unknown setting '$g'";
358             }
359             }
360 4 100       19 if (wantarray)
361             {
362 2         22 return %ret;
363             }
364             else
365             {
366             # Return last value
367 2         20 return $ret{$_[$#_]};
368             }
369            
370             }
371            
372             sub getparamblock
373             {
374 4     4 0 8 my $self = shift;
375 4         15 my(%p)=@_;
376 4         14 $self->_setdefaults(\%p);
377 4         17 $self->_do_something(\&_cmd_getparamblock,\&_resp_getparamblock,@_);
378             }
379            
380            
381             sub _cmd_getparamblock
382             {
383 4     4   8 my $self = shift;
384 4         97 my(%p)=@_;
385 4         90 $self->_setdefaults(\%p);
386 4         30 $self->_makepacket(%p,
387             cmd => 0x24,
388             data => pack("C",$p{antenna}),
389             );
390             }
391            
392             sub _resp_getparamblock
393             {
394 4     4   6 my $self = shift;
395 4 50       28 my $pp = $self->_parsepacket(@_)
396             or return undef;
397 4         52 (@$pp{qw(power_level environment combine_antenna_bits protocol_speed filter_type tagtype reserved_bits filter_bits reserved_bits)}) =
398             unpack("CCa1CCCa2a8a*",$pp->{data});
399 4         22 $pp->{combine_antenna}=[];
400 4         8 my $ca = ord $pp->{combine_antenna_bits};
401 4         11 foreach my $i (0..3)
402             {
403 16         36 my @antarr = (MATRICS_ANT_1, MATRICS_ANT_2, MATRICS_ANT_3, MATRICS_ANT_4);
404 16 50       52 if ($ca & (1 << $i))
405             {
406 0         0 push(@{$pp->{combine_antenna}},$antarr[$i]);
  0         0  
407             }
408             }
409 4         13 $pp;
410             }
411            
412            
413             =head3 set
414            
415             Set one or more properties associated with a reader. Depending on
416             implementation, this may send one or more commands to the reader, set
417             an internal flag, or take some other action.
418            
419             This method takes a hash with the properties to be set as keys, and
420             their new values as values. It returns a list of errors that occured;
421             if no errors occured, it will return an empty list. In a scalar
422             context, that evaluates to the number of errors that occured, so you
423             can test for errors like this:
424            
425             my @errs = $reader->set(SomeVariable => "New Value") == 0
426             or die "Couldn't set SomeVariable: @errs";
427            
428             See L for the properties that can be set.
429            
430             =cut
431            
432             sub set
433             {
434 5     5 1 10 my $self = shift;
435 5         22 my(%p)=@_;
436 5         10 my %antset;
437             my %ant_specific;
438 0         0 my %unknown;
439 0         0 my @errs;
440            
441             # First pass through settings.
442             # Settings that can be grouped into a single command are collected,
443             # and set efficiently in a second pass.
444 5         25 while(my($k,$v)=each(%p))
445             {
446 12 100 33     109 if ($paramblock_rename{$k} or ($k =~ /^(\w+)_Antenna(\d+)$/ and $paramblock_rename{$1}))
    50 66        
    50          
    50          
447             {
448 4         6 my($ant,$param);
449 4 50       13 if ($paramblock_rename{$k})
450             {
451 4         10 ($ant,$param)=('ALL',$paramblock_rename{$k});
452             }
453             else
454             {
455 0         0 ($ant,$param)=($2,$paramblock_rename{$1});
456             }
457 4 50       12 if ($param eq 'Mask')
458             {
459 0 0       0 if ($v eq '')
460             {
461 0         0 $antset{$ant}{filter_type}=0;
462 0         0 $antset{$ant}{filter_bits}="\0"x8;
463             }
464             else
465             {
466 0         0 my($mask,$len,$start)=split(/\//,$v);
467 0 0       0 if ($start)
468             {
469 0         0 push(@errs,"Matrics reader doesn't support mask start bit");
470 0         0 next;
471             }
472 0 0       0 if (!defined($len))
473             {
474 0         0 $len = length($mask) * 4;
475             }
476 0         0 $antset{$ant}{filter_bits} = hex2bin_big_endian($mask);
477 0 0       0 if ($len == 0)
    0          
    0          
    0          
478             {
479 0         0 $antset{$ant}{filter_type} = 0;
480             }
481             elsif ($len == 8)
482             {
483 0         0 $antset{$ant}{filter_type} = 1;
484             }
485             elsif ($len == 40)
486             {
487 0         0 $antset{$ant}{filter_type} = 2;
488             }
489             elsif ($len == 64)
490             {
491 0         0 $antset{$ant}{filter_type} = 3;
492             }
493             else
494             {
495 0         0 push(@errs,"Matrics reader only supports mask len of 0, 8, 40, and 64.");
496 0         0 next;
497             }
498 0         0 $antset{$ant}{filter_bits} = substr($antset{$ant}{filter_bits},0,$len/8) . "\0" x (8-($len/8));
499             }
500             }
501 4         52 $antset{$ant}{$param} = $v;
502             }
503             elsif ($k eq 'AntennaSequence')
504             {
505 0         0 $self->{_antenna_sequence} = $v;
506             }
507             elsif ($k eq 'node')
508             {
509 0         0 push(@errs, "Can't set node (yet)!");
510 0         0 next;
511             }
512             elsif ($k eq 'baudrate')
513             {
514 0         0 push(@errs,"Can't set baudrate (yet)!");
515 0         0 next;
516             }
517             else
518             {
519 8         34 $unknown{$k}=$v;
520             }
521             }
522 5 100       25 if (keys %unknown)
523             {
524 3         51 push(@errs,$self->SUPER::set(%unknown));
525             }
526            
527             # Copy options for all antennas into each individual antenna
528 5         113 while (my($k,$v)=each(%{$antset{ALL}}))
  9         62  
529             {
530 4         7 foreach my $a (@{$self->{_antenna_sequence}})
  4         17  
531             {
532 4         18 $antset{$a}{$k} = $v;
533             }
534             }
535            
536 5         22 foreach my $ant (1..4)
537             {
538 20 100       79 if ($antset{$ant})
539             {
540 2         7 $antset{$ant}{antenna} = $antid{$ant};
541 2         8 $self->_setdefaults($antset{$ant});
542 2 50       12 $self->changeparamblock(%{$antset{$ant}})
  2         46  
543             or push(@errs, "Error changing params: $self->{error}");
544             }
545             }
546 5         36 @errs;
547             }
548            
549            
550             sub setparamblock
551             {
552 2     2 0 6 my $self = shift;
553 2         25 my(%p)=@_;
554 2         9 $self->_setdefaults(\%p);
555            
556 2         16 $self->_do_something(\&_cmd_setparamblock,\&_resp_setparamblock,@_);
557             }
558            
559             sub _cmd_setparamblock
560             {
561 2     2   3 my $self = shift;
562 2         22 my(%p)=@_;
563            
564 2 50 50     30 $self->_makepacket(%p,
    50 50        
      50        
      50        
565             cmd => 0x23,
566             data => pack("CCCCCCCCCCx2a8x16",
567             $self->_make_confwhich_ant(\%p), # Returns 4 bytes
568             defined($p{power_level})?$p{power_level}:0xff,
569             defined($p{environment})?$p{environment}:0x00,
570             $self->_make_combine_antenna_bits(\%p),
571             $p{protocol_speed}||0,
572             $p{filter_type}||0,
573             $p{tagtype}||0,
574             $p{filter_bits}||"\0"x8,
575             )
576             );
577             }
578            
579             sub _resp_setparamblock
580             {
581 2     2   5 my $self = shift;
582 2 50       6 my $pp = $self->_parsepacket(@_)
583             or return undef;
584             }
585            
586             sub changeparamblock
587             {
588 2     2 0 4 my $self = shift;
589 2         18 my(%p)=@_;
590 2         7 $self->_setdefaults(\%p);
591            
592 2 50       9 croak "changeparamblock: The required parameter 'antenna' is missing.\n"
593             unless ($p{antenna});
594 2 50       9 my $curparam = $self->getparamblock(@_)
595             or return undef;
596 2 50       10 if ($p{combine_antennas})
597             {
598 0         0 delete $curparam->{combine_antenna_bits};
599             }
600 2         25 return $self->setparamblock(%$curparam, @_);
601             }
602            
603             =head3 readtags
604            
605             Read all of the tags in the reader's field, honoring any settings
606             affecting the reading and filtering of tags. This returns a (possibly
607             empty) list of tags, which will be of type
608             L or
609             L. See L
610             readtags method documentation|RFID::Reader/readtags> for more
611             information.
612            
613             =cut
614            
615             sub readtags
616             {
617 2     2 1 6898 my $self = shift;
618 2         4 my @tags;
619            
620 2         4 foreach my $ant (@{$self->{_antenna_sequence}})
  2         18  
621             {
622 2         16 my $r = $self->readfullfield(antenna => $ant);
623 2 50       10 push(@tags,@{$r->{tags}})
  2         14  
624             if ($r->{tags});
625             }
626 2         52 return $self->filter_tags(@tags);
627             }
628            
629             sub readfullfield
630             {
631 2     2 0 5 my $self = shift;
632 2 50       15 my @resp = $self->_do_something(\&_cmd_readfullfield,\&_resp_readfullfield,@_)
633             or return undef;
634 2         5 my $ret = shift(@resp);
635 2         4 foreach my $r (@resp)
636             {
637 2         5 $ret->{numtags} += $r->{numtags};
638 2         13 push(@{$ret->{tags}}, @{$r->{tags}});
  2         7  
  2         19  
639             }
640 2         11 $ret;
641             }
642            
643             sub _cmd_readfullfield
644             {
645 2     2   5 my $self = shift;
646 2         7 my(%p)=@_;
647 2         10 $self->_setdefaults(\%p);
648            
649 2         16 $self->_makepacket(%p,
650             cmd => 0x22,
651             data => pack("C",$p{antenna}),
652             );
653             }
654            
655             sub _resp_readfullfield
656             {
657 4     4   7 my $self = shift;
658 4 50       14 my $pp =$self->_parsepacket(@_)
659             or return undef;
660 4         9 my $dc = $pp->{data};
661 4         35 (@$pp{qw(antenna numtags)}) = unpack("CC",substr($dc,0,2,""));
662 4         83 $pp->{tags} = [$self->_parsetags($pp->{numtags},$dc,Antenna => $antname{$pp->{antenna}})];
663 4         14 $pp;
664             }
665            
666             sub readfullfield_unique
667             {
668 0     0 0 0 my $self = shift;
669 0         0 my $pp = $self->readfullfield(@_);
670            
671 0     0   0 @{$pp->{utags}} = uniq { $a->tagcmp($b) }
  0         0  
672 0         0 sort { $a->tagcmp($b) }
  0         0  
673 0         0 @{$pp->{tags}};
674 0         0 $pp->{unumtags}=scalar(@{$pp->{utags}});
  0         0  
675 0         0 $pp;
676             }
677            
678             sub start_constant_read
679             {
680 0     0 0 0 my $self = shift;
681 0         0 my(%p)=@_;
682 0         0 $self->_setdefaults(\%p);
683            
684 0         0 my $cmd = $self->_cmd_start_constant_read(%p);
685 0 0       0 $self->_sendpacket($cmd)
686             or die "Couldn't read command: $!\n";
687 0         0 $self->{_constant_read}{$p{node}}=1;
688             }
689            
690             sub _cmd_start_constant_read
691             {
692 0     0   0 my $self = shift;
693 0         0 my(%p)=@_;
694            
695 0         0 $self->_setdefaults(\%p);
696             # $antflag{$_}=1
697             # foreach grep { defined } ($p{antenna1}||$p{antenna}||MATRICS_ANT_1,
698             # @$p{qw(antenna2 antenna3 antenna4)});
699 0 0 0     0 $self->_makepacket(%p,
    0 0        
    0 0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
700             cmd => 0x25,
701             data => pack("CCCCCCCCCCCCa8",
702             $p{antenna1}||$p{antenna}||0,
703             $p{antenna2}||0,
704             $p{antenna3}||0,
705             $p{antenna4}||0,
706             $p{antenna1_power}||0xff,
707             $p{antenna2_power}||$p{antenna2}?0xff:0,
708             $p{antenna3_power}||$p{antenna3}?0xff:0,
709             $p{antenna4_power}||$p{antenna4}?0xff:0,
710             $p{dwell_time}||150,
711             $p{channel}||8,
712             $p{maskbits}||0,$p{masktype}||0,
713             $p{mask}||"\0\0\0\0\0\0\0\0",
714             ),
715             );
716             }
717            
718             sub _epc_parsetags
719             {
720 0     0   0 my $self = shift;
721 0         0 my($count,$dc,%tagprops)=@_;
722 0         0 my @tags;
723            
724 0         0 foreach my $i (1..$count)
725             {
726 0         0 my $type = ord(substr($dc,0,1));
727 0         0 my $tag;
728 0 0       0 if ($type == 0x0C)
729             {
730             # Proprietary Matrics Tag
731 0         0 $tag = RFID::Matrics::Tag->new(id => bin2hex_little_endian(unpack("a8",substr($dc,1,8))),
732             %tagprops);
733             }
734             else
735             {
736             # EPC tag
737 0         0 $tag = RFID::EPC::Tag->new(id => bin2hex_little_endian(unpack("a12",substr($dc,0,13))),
738             %tagprops);
739             }
740 0         0 push(@tags,$tag);
741             }
742 0         0 @tags;
743             }
744            
745             sub constant_read
746             {
747 0     0 0 0 my $self = shift;
748 0         0 my(%p)=@_;
749            
750 0         0 $self->_setdefaults(\%p);
751            
752 0 0       0 croak "Please call start_constant_read before constant_read\n"
753             unless ($self->{_constant_read}{$p{node}});
754            
755 0 0       0 my $resp = $self->_getpacket()
756             or die "Couldn't read response: $!\n";
757 0         0 my $pr = $self->_resp_constant_read($resp);
758 0         0 return $pr;
759             }
760            
761             sub _resp_constant_read
762             {
763 0     0   0 my $self = shift;
764            
765 0         0 my $pp = $self->_parsepacket(@_);
766 0 0       0 if (!$pp)
767             {
768 0         0 return { numtags => 0,
769             tags => [],
770             error => $self->{error},
771             errcode => $self->{errcode},
772             };
773            
774             }
775            
776 0 0       0 if ($pp->{error})
777             {
778 0         0 $pp->{numtags} = 0;
779 0         0 $pp->{tags} = [];
780 0         0 return $pp;
781             }
782 0         0 my $dc = $pp->{data};
783 0         0 @$pp{qw(antenna numtags)} = unpack("CC",substr($dc,0,2,""));
784 0         0 $pp->{tags} = [$self->_parsetags($pp->{numtags},$dc)];
785 0         0 return $pp;
786             }
787            
788             sub _parsetags
789             {
790 4     4   7 my $self = shift;
791 4         14 my($count,$dc,%tagprops)=@_;
792 4         14 my @tags;
793            
794 4         20 foreach my $i (1..$count)
795             {
796 10         30 my $type_len_bits = unpack("C",substr($dc,0,1,""));
797 10 50       35 my $len = ($type_len_bits & 0x10) ? 12 : 8;
798 10         14 my $type = ($type_len_bits & 0x0f);
799 10         28 my $id_bits = unpack("a*",substr($dc,0,$len,""));
800 10         12 my $tag;
801 10 100       22 if ($type == 0)
802             {
803             # EPC tag
804 2         10 $tag = RFID::EPC::Tag->new(id => bin2hex_little_endian($id_bits),
805             %tagprops);
806             }
807             else
808             {
809             # Proprietary Matrics Tag
810 8         26 $tag = RFID::Matrics::Tag->new(id => bin2hex_little_endian($id_bits),
811             %tagprops);
812             }
813 10         136 push(@tags,$tag);
814             }
815 4         44 @tags;
816             }
817            
818             sub stop_constant_read
819             {
820 3     3 0 5 my $self = shift;
821 3         18 my(%p)=@_;
822            
823 3         39 $self->_setdefaults(\%p);
824 3         19 delete $self->{_constant_read}{$p{node}};
825 3         58 $self->_do_something(\&_cmd_stop_constant_read,\&_resp_stop_constant_read,@_);
826             }
827            
828            
829             sub _cmd_stop_constant_read
830             {
831 3     3   5 my $self = shift;
832 3         7 my(%p)=@_;
833            
834 3         44 $self->_makepacket(%p,
835             cmd => 0x26,
836             data => "",
837             );
838             }
839            
840             sub _resp_stop_constant_read
841             {
842 3     3   7 my $self = shift;
843 3 50       36 my $pp = $self->_parsepacket(@_)
844             or return undef;
845 3         12 return $pp;
846             }
847            
848             sub stop_all_constant_read
849             {
850 0     0 0 0 my $self = shift;
851            
852 0 0 0     0 if ($self->{_constant_read} && $self->_connected)
853             {
854 0         0 foreach my $node (keys %{$self->{_constant_read}})
  0         0  
855             {
856 0         0 $self->stop_constant_read(node => $node);
857             }
858             }
859 0         0 1;
860             }
861            
862             sub _make_confwhich_ant
863             {
864 2     2   5 my $self = shift;
865 2         10 my($p)=@_;
866 2         4 my %antflag;
867            
868            
869 2         7 foreach my $a (grep { defined($p->{"antenna".$_}) }
  8         31  
870             (1..4))
871             {
872 0         0 $antflag{$antid{$a}} = 1;
873             }
874 2 50       10 if (!(keys %antflag))
875             {
876 2   50     16 $antflag{$p->{antenna}||MATRICS_ANT_1} = 1;
877             }
878 2 50       43 return ($antflag{MATRICS_ANT_1()}?1:0,
    50          
    50          
    50          
879             $antflag{MATRICS_ANT_2()}?1:0,
880             $antflag{MATRICS_ANT_3()}?1:0,
881             $antflag{MATRICS_ANT_4()}?1:0,
882             );
883             }
884            
885             sub _make_combine_antenna_bits
886             {
887 2     2   5 my $self = shift;
888 2         8 my($p)=@_;
889 2         8 my %antbit = (
890             MATRICS_ANT_1() => 1,
891             MATRICS_ANT_2() => 2,
892             MATRICS_ANT_3() => 4,
893             MATRICS_ANT_4() => 8,
894             );
895            
896 2 50       8 if (!$p->{combine_antenna_bits})
897             {
898 0         0 my $cab = 0;
899 0 0       0 if ($p->{combine_antennas})
900             {
901 0         0 $cab |= $antbit{$_}
902 0         0 foreach (@{$p->{combine_antennas}});
903             }
904 0         0 $p->{combine_antenna_bits}=chr($cab);
905             }
906 2         59 return ord($p->{combine_antenna_bits});
907             }
908            
909             sub epc_readfullfield
910             {
911 0     0 0 0 my $self = shift;
912 0         0 my(%p)=@_;
913 0         0 $self->_setdefaults(\%p);
914            
915 0 0       0 my @resp = $self->_do_something(\&_cmd_epc_readfullfield,
916             \&_resp_epc_readfullfield,
917             %p)
918             or return undef;
919            
920 0         0 my $ret = shift(@resp);
921 0         0 foreach my $r (@resp)
922             {
923 0         0 $ret->{numtags} += $r->{numtags};
924 0         0 push(@{$ret->{tags}},@{$r->{tags}});
  0         0  
  0         0  
925             }
926 0         0 $ret;
927             }
928            
929             sub _cmd_epc_readfullfield
930             {
931 0     0   0 my $self = shift;
932 0         0 my(%p)=@_;
933            
934 0         0 $self->_makepacket(%p,
935             cmd => 0x10,
936             data => pack("C",$p{antenna}),
937             );
938             }
939            
940             sub _resp_epc_readfullfield
941             {
942 0     0   0 my $self = shift;
943 0 0       0 my $pp = $self->_parsepacket(@_)
944             or return undef;
945 0         0 my $dc = $pp->{data};
946 0         0 (@$pp{qw(antenna numtags)}) = unpack("CC",substr($dc,0,2,""));
947 0         0 $pp->{tags} = [$self->_epc_parsetags($pp->{numtags},$dc)];
948 0         0 $pp;
949             }
950            
951             sub epc_readfullfield_unique
952             {
953 0     0 0 0 my $self = shift;
954 0         0 my $ret = $self->epc_readfullfield;
955            
956 0     0   0 @{$ret->{utags}} = uniq { $a->tagcmp($b) }
  0         0  
957 0         0 sort { $a->tagcmp($b) }
  0         0  
958 0         0 @{$ret->{tags}};
959 0         0 $ret->{unumtags}=scalar(@{$ret->{utags}});
  0         0  
960            
961 0         0 $ret;
962             }
963            
964             sub epc_getparamblock
965             {
966 0     0 0 0 my $self = shift;
967 0         0 $self->_do_something(\&_cmd_epc_getparamblock,\&_resp_epc_getparamblock,@_);
968             }
969            
970             sub _cmd_epc_getparamblock
971             {
972 0     0   0 my $self = shift;
973 0         0 my(%p)=@_;
974            
975 0         0 $self->_makepacket(%p,
976             cmd => 0x16,
977             data => pack("C",$p{antenna}),
978             );
979             }
980            
981             sub _resp_epc_getparamblock
982             {
983 0     0   0 my $self = shift;
984 0 0       0 my $pp = $self->_parsepacket(@_)
985             or return undef;
986            
987 0         0 @$pp{qw(power_level environment combine_antenna_bits protocol_speed filter_type reserved1_bits filter_bits reserved2_bits)} =
988             unpack("CCCCCa3a8a16",$pp->{data});
989 0         0 $pp;
990             }
991            
992             sub epc_setparamblock
993             {
994 0     0 0 0 my $self = shift;
995 0         0 $self->_do_something(\&_cmd_epc_setparamblock,\&_resp_epc_setparamblock,@_);
996             }
997            
998             sub _cmd_epc_setparamblock
999             {
1000 0     0   0 my $self = shift;
1001 0         0 my(%p)=@_;
1002            
1003            
1004 0 0 0     0 $self->_makepacket(%p,
      0        
      0        
      0        
      0        
      0        
1005             cmd => 0x15,
1006             data => pack("CCCCCCCCCa3a8a16",
1007             $self->_make_confwhich_ant(\%p), # Returns 4 bytes
1008             defined($p{power_level})?$p{power_level}:0xff,
1009             $p{environment}||0x00,
1010             $self->_make_combine_antenna_bits(\%p),
1011             $p{protocol_speeed}||0x00,
1012             $p{filter_type}||0x00,
1013             $p{reserved1_bits}||("\0"x3),
1014             $p{filter_bits}||("\0"x8),
1015             $p{reserved2_bits}||("\0"x16),
1016             )
1017             );
1018             }
1019            
1020             sub _resp_epc_setparamblock
1021             {
1022 0     0   0 my $self = shift;
1023            
1024 0 0       0 my $pp = $self->_parsepacket(@_)
1025             or return undef;
1026             }
1027            
1028            
1029             sub epc_changeparamblock
1030             {
1031 0     0 0 0 my $self = shift;
1032 0         0 my(%p)=@_;
1033            
1034 0 0       0 croak "changeparam: The required parameter 'antenna' is missing.\n"
1035             unless ($p{antenna});
1036 0 0       0 my $curparam = $self->epc_getparamblock(@_)
1037             or return undef;
1038 0         0 return $self->epc_setparamblock(%$curparam, @_);
1039             }
1040            
1041             sub setnodeaddress
1042             {
1043 0     0 0 0 my $self = shift;
1044 0         0 my(%p)=@_;
1045            
1046 0   0     0 my $node = $p{oldnode}||0xFF;
1047 0 0 0     0 if ($p{oldnode}==0xFF or !$p{oldnode})
1048             {
1049             # No response to broadcast commands, just send it.
1050 0 0       0 my $cmd = _cmd_setnodeaddress($self, @_)
1051             or return undef;
1052 0 0       0 $self->_sendpacket($cmd)
1053             or die "Couldn't write command: $!\n";
1054 0         0 return { noresponse => 1 };
1055             }
1056             else
1057             {
1058 0         0 $self->_do_something(\&_cmd_setnodeaddress,\&_resp_setnodeaddress,@_);
1059             }
1060             }
1061            
1062             sub _cmd_setnodeaddress
1063             {
1064 0     0   0 my $self = shift;
1065 0         0 my(%p)=@_;
1066 0         0 $self->_setdefaults(\%p);
1067            
1068 0 0       0 if (!$p{serialnum_bits})
1069             {
1070 0 0       0 defined($p{serialnum}) or return $self->error("Missing required parameter serialnum or serialnum_bits");
1071 0         0 $p{serialnum_bits} = hex2bin_little_endian($p{serialnum});
1072             }
1073 0 0 0     0 $p{newnode} or $p{node} or return $self->error("Missing required parameter newnode or node");
1074            
1075 0   0     0 $self->_makepacket(%p,
      0        
1076             node => $p{oldnode}||0xFF,
1077             cmd => 0x12,
1078             data => pack("Ca8",
1079             $p{newnode}||$p{node},
1080             $p{serialnum_bits},
1081             ),
1082             );
1083             }
1084            
1085             sub _resp_setnodeaddress
1086             {
1087 0     0   0 my $self = shift;
1088 0 0       0 my $pp = $self->_parsepacket(@_)
1089             or return undef;
1090             }
1091            
1092             sub getreaderstatus
1093             {
1094 2     2 0 6 my $self = shift;
1095 2         10 $self->_do_something(\&_cmd_getreaderstatus,\&_resp_getreaderstatus,@_);
1096             }
1097            
1098             sub _cmd_getreaderstatus
1099             {
1100 2     2   11 my $self = shift;
1101 2         6 my(%p)=@_;
1102            
1103 2         12 $self->_makepacket(%p,
1104             cmd => 0x14,
1105             );
1106             }
1107            
1108             sub _resp_getreaderstatus
1109             {
1110 2     2   6 my $self = shift;
1111 2 50       8 my $pp = $self->_parsepacket(@_)
1112             or return undef;
1113            
1114 2         42 @$pp{qw(serialnum_bits version_major version_minor version_eng
1115             reset_flag combine_antenna_bits antenna_status_bits
1116             last_error reserved)} =
1117             unpack("a8CCCCa4a4Ca11",$pp->{data});
1118 2         17 $pp->{version}=join(".",@$pp{qw(version_major version_minor version_eng)});
1119 2         11 $pp->{serialnum} = bin2hex_little_endian($pp->{serialnum_bits});
1120 2         9 $pp;
1121             }
1122            
1123             sub getnodeaddress
1124             {
1125 2     2 0 8 my $self = shift;
1126 2         20 $self->_do_something(\&_cmd_getnodeaddress,\&_resp_getnodeaddress,@_);
1127             }
1128            
1129            
1130             sub _cmd_getnodeaddress
1131             {
1132 2     2   5 my $self = shift;
1133 2         7 my(%p)=@_;
1134            
1135 2 50       9 if (!$p{serialnum_bits})
1136             {
1137 2 50       11 defined($p{serialnum}) or return $self->error("Missing required parameter serialnum or serialnum_bits");
1138 2         29 $p{serialnum_bits} = hex2bin_little_endian($p{serialnum});
1139             }
1140 2         17 $self->_makepacket(%p,
1141             node => 0xff,
1142             cmd => 0x19,
1143             data => pack("a8",
1144             $p{serialnum_bits},
1145             ),
1146             );
1147             }
1148            
1149             sub _resp_getnodeaddress
1150             {
1151 2     2   4 my $self = shift;
1152 2 50       8 my $pp = $self->_parsepacket(@_)
1153             or return undef;
1154             }
1155            
1156             # NOT FINISHED
1157             our %baudnum = (
1158             230400 => 0,
1159             115200 => 1,
1160             57600 => 2,
1161             38400 => 3,
1162             19200 => 4,
1163             9600 => 5,
1164             );
1165            
1166            
1167             sub _cmd_setbaudrate
1168             {
1169 0     0   0 my $self = shift;
1170 0         0 my(%p)=@_;
1171            
1172 0 0       0 if (!$p{baudrate_bits})
1173             {
1174 0 0       0 defined($p{baudrate}) or return $self->error("Missing required parameter baudrate");
1175 0 0       0 defined($p{baudrate_bits}=$baudnum{$p{baudrate}})
1176             or return $self->error("Invalid baud rate.");
1177             }
1178 0         0 $self->_makepacket(%p,
1179             cmd => 0x1D,
1180             data => pack("C",$p{baudrate_bits}),
1181             );
1182            
1183             }
1184            
1185             sub _resp_setbaudrate
1186             {
1187 0     0   0 my $self = shift;
1188 0 0       0 my $pp = $self->_parsepacket(@_)
1189             or return undef;
1190             }
1191            
1192             sub setbaudrate
1193             {
1194 0     0 0 0 my $self = shift;
1195            
1196 0         0 $self->_do_something(\&_cmd_setbaudrate,\&_resp_setbaudrate,@_);
1197             }
1198            
1199            
1200             =head3 finish
1201            
1202             Perform any cleanup tasks for the reader. In particular, shut off any
1203             constant reads that are currently running.
1204            
1205             =cut
1206            
1207             sub finish
1208             {
1209 0     0 1 0 my $self = shift;
1210 0 0       0 $self->stop_all_constant_read()
1211             or warn "Couldn't stop all constant readers: $!\n";
1212             }
1213            
1214             sub error
1215             {
1216 0     0 0 0 my $self = shift;
1217 0         0 my($em,$ec)=@_;
1218            
1219 0         0 $self->{error}=$em;
1220 0 0       0 $self->{errcode}=defined($ec)?$ec:1;
1221 0         0 $self->debug("Error: $em\n");
1222 0         0 return undef;
1223             }
1224            
1225             # Convert a hex string to binary, LSB first
1226             sub hex2bin_little_endian
1227             {
1228 2     2 0 5 my $hex = $_[0];
1229 2         7 $hex =~ tr/0-9a-fA-F//cd;
1230 2         30 pack("C*",map { hex } reverse unpack("a2"x(length($hex)/2),$hex));
  16         40  
1231             }
1232            
1233             sub hex2bin_big_endian
1234             {
1235 0     0 0 0 my $hex = $_[0];
1236 0         0 $hex =~ tr/0-9a-fA-F//cd;
1237 0         0 pack("C*",map { hex } unpack("a2"x(length($hex)/2),$hex));
  0         0  
1238             }
1239            
1240             sub bin2hex_little_endian
1241             {
1242 12     12 0 100 unpack("H*",pack("C*",reverse(unpack("C*",$_[0]))));
1243             }
1244            
1245             sub bin2hex_big_endian
1246             {
1247 0     0 0   unpack("H*",$_[0]);
1248             # my @a = split(//,$_[0]);
1249             # sprintf "%02x" x scalar(@a), map {ord} @a;
1250             }
1251            
1252             =head2 Properties
1253            
1254             =head3 Antenna
1255            
1256             The default antenna for get operations; see also
1257             L. This defaults to 1 if it is not
1258             set.
1259            
1260             =head3 AntennaSequence
1261            
1262             An arrayref of the antennas that should be queried, and in what order.
1263             The antenna names for a 4-port Matrics reader are simply 1, 2, 3, and
1264             4. For example:
1265            
1266             $reader->set(AntennaSequence => [1,2,3,4]);
1267            
1268             The default AntennaSequence is the L.
1269            
1270             =head3 Debug
1271            
1272             Control the amount debugging information sent to C. A higher
1273             value for this property will cause more information to be output.
1274            
1275             =head3 UniqueTags
1276            
1277             A boolean value controlling whether duplicate tags should be removed
1278             from the list returned by L.
1279            
1280             =head3 Environment
1281            
1282             How long an antenna should try to read tags during a
1283             L command, between 0 and 4. 0 will read for a very
1284             short time, and is appropriate for environments where tags come and go
1285             very quickly, and it's OK if you miss a tag somtimes. 4 will read for
1286             longer, and is appropriate where tags stay relatively static and you
1287             want the reader to try its best to find all of them.
1288            
1289             When this item is retreived, you get the value for the default
1290             antenna. When it's set, it's set for all of the antennas in the
1291             L. To set the level for only one
1292             antenna, use C>, where C> is the number
1293             of the antenna you'd like to set.
1294            
1295             =head3 Node
1296            
1297             The Matrics node address associated with this object. It defaults to
1298             4.
1299            
1300             =head3 PowerLevel
1301            
1302             The amount of power an antenna should use when doing a read, between 0
1303             and 255. 255 is full-power; the scale of this setting is logarithmic,
1304             so 208 is about 50% power, and 0x80 is about 25% power.
1305            
1306             When this item is retreived, you get the value for the default
1307             antenna. When it's set, it's set for all of the antennas in the
1308             L. To set the level for only one
1309             antenna, use C>, where C> is the number of
1310             the antenna you'd like to set.
1311            
1312             =head3 ReaderVersion
1313            
1314             The software version running on this reader, as a string. Cannot be
1315             L.
1316            
1317             =head3 ReaderSerialNum
1318            
1319             The serial number of this reader, as a string. Cannot be L.
1320            
1321             =head1 SEE ALSO
1322            
1323             L, L,
1324             L, L,
1325             L.
1326            
1327             =head1 AUTHOR
1328            
1329             Scott Gifford ,
1330            
1331             Copyright (C) 2004 The Regents of the University of Michigan.
1332            
1333             See the file LICENSE included with the distribution for license
1334             information.
1335            
1336             =cut
1337            
1338             1;