_invalidate_tag when it leaves reader range
[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->{inventory} ||= {};
50         $self->{inventory}->{$_} = 0 foreach keys %{$self->{inventory}};
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                         $self->{blocks}->{$tag} ||= $rfid->read_blocks( $tag )->{$tag};
60                         $self->{afi}->{$tag}    ||= $rfid->read_afi( $tag );
61
62                         $triggers->{enter}->( $self, $tag ) if ! $self->{inventory}->{$tag} && $triggers->{enter};
63                         $self->{inventory}->{$tag} = $t;
64
65                 }
66
67                 foreach my $tag ( grep { $self->{inventory}->{$_} == 0 } keys %{ $self->{inventory} } ) {
68                         $triggers->{leave}->( $self, $tag ) if $triggers->{leave};
69                         $self->_invalidate_tag( $tag );
70                 }
71
72         }
73
74         warn "## tags ",dump($self);
75
76         return grep { $self->{inventory}->{$_} } keys %{ $self->{inventory} };
77 }
78
79 =head2 blocks
80
81   my $blocks_arrayref = $rfid->blocks( $tag );
82
83 =head2 afi
84
85   my $afi = $rfid->afi( $tag );
86
87 =cut
88
89 sub blocks { $_[0]->{ 'blocks' }->{$_[1]} || die "no blocks for $_[1]"; };
90 sub afi    { $_[0]->{ 'afi'    }->{$_[1]} || die "no afi for $_[1]"; };
91
92 =head1 PRIVATE
93
94 =head2 _invalidate_tag
95
96   $rfid->_invalidate_tag( $tag );
97
98 =cut
99
100 sub _invalidate_tag {
101         my ( $self, $tag ) = @_;
102         delete $self->{'blocks'}->{$tag};
103         delete $self->{'afi'}->{$tag};
104         delete $self->{'inventory'}->{$tag};
105         warn "# _invalidate_tag $tag";
106 }
107
108 =head2 _available
109
110 Probe each RFID reader supported and returns succefull ones
111
112   my $rfid_readers = RFID::Biblio::Reader->_available( $regex_filter );
113
114 =cut
115
116 my @readers = ( '3M810', 'CPRM02', 'librfid' );
117
118 sub _available {
119         my ( $self, $filter ) = @_;
120
121         $filter = '' unless defined $filter;
122
123         warn "# filter: $filter";
124
125         my @rfid;
126
127         foreach my $reader ( @readers ) {
128                 next if $filter && $reader !~ /$filter/i;
129                 my $module = "RFID::Biblio::Reader::$reader";
130                 eval "use $module";
131                 die $@ if $@;
132                 if ( my $rfid = $module->new( device => '/dev/ttyUSB0' ) ) {
133                         push @rfid, $rfid;
134                         warn "# added $module\n";
135                 } else {
136                         warn "# ignored $module\n";
137                 }
138         }
139
140         die "no readers found" unless @rfid;
141
142         return @rfid;
143 }
144
145 =head1 AUTOLOAD
146
147 On any other function calls, we just marshall to all readers
148
149 =cut
150
151 # we don't want DESTROY to fallback into AUTOLOAD
152 sub DESTROY {}
153
154 our $AUTOLOAD;
155 sub AUTOLOAD {
156         my $self = shift;
157         my $command = $AUTOLOAD;
158         $command =~ s/.*://;
159
160         my @out;
161
162         foreach my $r ( @{ $self->{_readers} } ) {
163                 push @out, $r->$command(@_);
164         }
165
166         $self->_invalidate_tag( $_[0] ) if $command =~ m/write/;
167
168         return @out;
169 }
170
171 1
172 __END__
173
174 =head1 SEE ALSO
175
176 =head2 RFID reader implementations
177
178 L<RFID::Biblio::Reader::3M810>
179
180 L<RFID::Biblio::Reader::CPRM02>
181
182 L<RFID::Biblio::Reader::librfid>
183