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