3f02424e868d9a08f7a3ccc4d1eae0021a978f81
[Biblio-RFID.git] / lib / RFID / Biblio / Reader.pm
1 package RFID::Biblio::Reader;
2
3 use warnings;
4 use strict;
5
6 use Data::Dump qw(dump);
7 use Time::HiRes;
8 use lib 'lib';
9 use RFID::Biblio;
10
11 =head1 NAME
12
13 RFID::Biblio::Reader - simple way to write RFID applications in perl
14
15 =head1 DESCRIPTION
16
17 This module will probe all available readers and use calls from
18 L<RFID::Biblio::Reader::API> to invoke correct reader.
19
20 =head1 FUNCTIONS
21
22 =head2 new
23
24   my $rfid = RFID::Biblio::Reader->new( 'optional reader filter' );
25
26 =cut
27
28 sub new {
29         my ( $class, $filter ) = @_;
30         my $self = {};
31         bless $self, $class;
32         $self->{_readers} = [ $self->_available( $filter ) ];
33         return $self;
34 }
35
36 =head2 tags
37
38   my @visible = $rfid->tags(
39                 enter => sub {},
40                 leave => sub {},
41   );
42
43 =cut
44
45 sub tags {
46         my $self = shift;
47         my $triggers = {@_};
48
49         $self->{_tags} ||= {};
50         $self->{_tags}->{$_}->{time} = 0 foreach keys %{$self->{_tags}};
51         my $t = time;
52
53         foreach my $rfid ( @{ $self->{_readers} } ) {
54                 warn "# inventory on $rfid";
55                 my @tags = $rfid->inventory;
56
57                 foreach my $tag ( @tags ) {
58
59                         if ( ! exists $self->{_tags}->{$tag} ) {
60                                 eval {
61                                         my $blocks = $rfid->read_blocks($tag);
62                                         $self->{_tags}->{$tag}->{blocks} = $blocks->{$tag} || die "no $tag in ",dump($blocks);
63                                         my $afi = $rfid->read_afi($tag);
64                                         $self->{_tags}->{$tag}->{afi} = $afi;
65
66                                 };
67                                 if ( $@ ) {
68                                         warn "ERROR reading $tag: $@\n";
69                                         $self->_invalidate_tag( $tag );
70                                         next;
71                                 }
72
73                                 $triggers->{enter}->( $self, $tag ) if $triggers->{enter};
74                         }
75
76                         $self->{_tags}->{$tag}->{time} = $t;
77
78                 }
79         
80 warn "XXX ## _tags ",dump( $self->{_tags} );
81
82                 foreach my $tag ( grep { $self->{_tags}->{$_}->{time} == 0 } keys %{ $self->{_tags} } ) {
83                         $triggers->{leave}->( $self, $tag ) if $triggers->{leave};
84                         $self->_invalidate_tag( $tag );
85                 }
86
87         }
88
89         warn "## _tags ",dump( $self->{_tags} );
90
91         return grep { $self->{_tags}->{$_}->{time} } keys %{ $self->{_tags} };
92 }
93
94 =head2 blocks
95
96   my $blocks_arrayref = $rfid->blocks( $tag );
97
98 =head2 afi
99
100   my $afi = $rfid->afi( $tag );
101
102 =cut
103
104 sub blocks { $_[0]->{_tags}->{$_[1]}->{ 'blocks' } || die "no blocks for $_[1]"; };
105 sub afi    { $_[0]->{_tags}->{$_[1]}->{ 'afi'    } || die "no afi for $_[1]"; };
106
107 =head1 PRIVATE
108
109 =head2 _invalidate_tag
110
111   $rfid->_invalidate_tag( $tag );
112
113 =cut
114
115 sub _invalidate_tag {
116         my ( $self, $tag ) = @_;
117         my @caller = caller(0);
118         warn "## _invalidate_tag caller $caller[0] $caller[1] +$caller[2]\n";
119         my $old = delete $self->{_tags}->{$tag};
120         warn "# _invalidate_tag $tag ", dump($old);
121 }
122
123 =head2 _available
124
125 Probe each RFID reader supported and returns succefull ones
126
127   my $rfid_readers = RFID::Biblio::Reader->_available( $regex_filter );
128
129 =cut
130
131 my @readers = ( '3M810', 'CPRM02', 'librfid' );
132
133 sub _available {
134         my ( $self, $filter ) = @_;
135
136         $filter = '' unless defined $filter;
137
138         warn "# filter: $filter";
139
140         my @rfid;
141
142         foreach my $reader ( @readers ) {
143                 next if $filter && $reader !~ /$filter/i;
144                 my $module = "RFID::Biblio::Reader::$reader";
145                 eval "use $module";
146                 die $@ if $@;
147                 if ( my $rfid = $module->new( device => '/dev/ttyUSB0' ) ) {
148                         push @rfid, $rfid;
149                         warn "# added $module\n";
150                 } else {
151                         warn "# ignored $module\n";
152                 }
153         }
154
155         die "no readers found" unless @rfid;
156
157         return @rfid;
158 }
159
160 =head1 AUTOLOAD
161
162 On any other function calls, we just marshall to all readers
163
164 =cut
165
166 # we don't want DESTROY to fallback into AUTOLOAD
167 sub DESTROY {}
168
169 our $AUTOLOAD;
170 sub AUTOLOAD {
171         my $self = shift;
172         my $command = $AUTOLOAD;
173         $command =~ s/.*://;
174
175         my @out;
176
177         foreach my $r ( @{ $self->{_readers} } ) {
178                 push @out, $r->$command(@_);
179         }
180
181         $self->_invalidate_tag( $_[0] ) if $command =~ m/write/;
182
183         return @out;
184 }
185
186 1
187 __END__
188
189 =head1 SEE ALSO
190
191 =head2 RFID reader implementations
192
193 L<RFID::Biblio::Reader::3M810>
194
195 L<RFID::Biblio::Reader::CPRM02>
196
197 L<RFID::Biblio::Reader::librfid>
198