correctly return tags for inventory
[Biblio-RFID.git] / lib / Biblio / RFID / Reader / librfid.pm
1 package Biblio::RFID::Reader::librfid;
2
3 use warnings;
4 use strict;
5
6 use base 'Biblio::RFID::Reader::API';
7 use Biblio::RFID;
8
9 use Data::Dump qw(dump);
10
11 =head1 NAME
12
13 Biblio::RFID::Reader::librfid - execute librfid-tool
14
15 =head1 DESCRIPTION
16
17 This is wrapper around C<librfid-tool> from
18
19 L<http://openmrtd.org/projects/librfid/>
20
21 Due to limitation of L<librfid-tool> only
22 L<Biblio::RFID::Reader::API/inventory> and
23 L<Biblio::RFID::Reader::API/read_blocks> is supported.
24
25 This version uses modidified C<librfid-tool> which supports
26 new C<-s> flag which reads sectors 0-3 with C<-k> key and
27 sectors 4-7 with key from C<-s> option.
28
29 However, this code might provide template for integration
30 with any command-line utilities for different RFID readers.
31
32 Currently tested with only with Omnikey CardMan 5321 which
33 has problems. After a while it stops responding to commands
34 by C<librfid-tool> so I provided small C program to reset it:
35
36 C<examples/usbreset.c>
37
38 =cut
39
40 sub serial_settings {} # don't open serial
41
42 sub init { 1 }
43
44 sub _grep_tool {
45         my ( $bin, $param, $coderef, $path ) = @_;
46
47         warn "# _grep_tool $bin $param\n";
48         open(my $s, '-|', "$bin $param 2>/dev/null") || die $!;
49
50         my $sid;
51         my $iso;
52
53         while(<$s>) {
54                 chomp;
55                 warn "## $_\n";
56
57                 if ( m/Layer 2 success.+\(([^\)]+)\).*:\s+(.+)/ ) {
58                         ( $sid, $iso ) = ( $2, $1 );
59                         $sid =~ s/\s*'\s*//g;
60                         my @sid = split(/\s+/, $sid);
61                         @sid = reverse @sid if $iso =~ m/15693/;
62                         $sid = uc join('', @sid);
63                         warn "## sid=[$sid] iso=[$iso]\n";
64                 }
65                 $coderef->( $sid, $iso );
66         }
67
68
69 }
70
71 my $sid_iso;
72
73 sub inventory {
74
75         my @tags; 
76         _grep_tool 'librfid-tool', '--scan' => sub {
77                 my ( $sid, $iso ) = @_;
78                 if ( $sid ) {
79                         push @tags, $sid;
80                         $sid_iso->{$sid} = $iso;
81                 }
82         };
83         warn "# invetory ",dump(@tags);
84         return @tags;
85 }
86
87 sub tag_type {
88         my ( $self, $tag ) = @_;
89         return $sid_iso->{$tag} =~ m/15693/ ? 'RFID501' : 'SmartX';
90 }
91
92 our $mifare_keys;
93 sub read_mifare_keys {
94         my $key_path = $0;
95         $key_path =~ s{/[^/]+$}{/};
96         $key_path .= "mifare_keys.pl";
97         warn "# $key_path";
98         if ( -e $key_path ) {
99                 require $key_path;
100                 warn "# mifare keys for sectors ", join(' ', keys %$mifare_keys), " loaded\n";
101         }
102 }
103
104 sub read_blocks {
105         my ( $self, $sid ) = @_;
106
107         my $iso = $sid_iso->{$sid};
108         my $blocks;
109
110         if ( $iso =~ m/15693/ ) {
111                 _grep_tool 'librfid-tool', '--read -1' => sub {
112                         $sid ||= shift;
113                         $blocks->{$sid}->[$1] = hex2bytes($2)
114                         if m/block\[\s*(\d+):.+data.+:\s*(.+)/;
115
116                 };
117         } else {
118                 read_mifare_keys unless $mifare_keys;
119
120 =for unmodified mifate-tool
121                 foreach my $sector ( keys %$mifare_keys ) {
122                         my $key = lc $mifare_keys->{$sector};
123                         _grep_tool 'mifare-tool', "-k $key -r $sector" => sub {
124                                 $blocks->{$sid}->[$sector] = hex2bytes($1)
125                                 if m/data=\s*(.+)/;
126                         };
127                 }
128 =cut
129                 _grep_tool 'mifare-tool', "-k " . $mifare_keys->{0} . " -s " . $mifare_keys->{4} => sub {
130                         $blocks->{$sid}->[$1] = hex2bytes($2)
131                         if m/page=(\d+).*data=\s*(.+)/;
132                 };
133         }
134         warn "# read_blocks ",dump($blocks);
135         return $blocks;
136 }
137
138 sub write_blocks {}
139 sub read_afi { -1 }
140 sub write_afi {}
141
142 1