37dd047d5c6f60d6edcc10292d6b41dd563068a7
[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 However, this code might provide template for integration
26 with any command-line utilities for different RFID readers.
27
28 Currently tested with only with Omnikey CardMan 5321 which
29 has problems. After a while it stops responding to commands
30 by C<librfid-tool> so I provided small C program to reset it:
31
32 C<examples/usbreset.c>
33
34 =cut
35
36 sub serial_settings {} # don't open serial
37
38 sub init { 1 }
39
40 sub _grep_tool {
41         my ( $bin, $param, $coderef, $path ) = @_;
42
43         warn "# _grep_tool $bin $param\n";
44         open(my $s, '-|', "$bin $param 2>/dev/null") || die $!;
45
46         my $sid;
47         my $iso;
48
49         while(<$s>) {
50                 chomp;
51                 warn "## $_\n";
52
53                 if ( m/Layer 2 success.+\(([^\)]+)\).*:\s+(.+)/ ) {
54                         ( $sid, $iso ) = ( $2, $1 );
55                         $sid =~ s/\s*'\s*//g;
56                         my @sid = split(/\s+/, $sid);
57                         @sid = reverse @sid if $iso =~ m/15693/;
58                         $sid = uc join('', @sid);
59                         warn "## sid=[$sid] iso=[$iso]\n";
60                 }
61                 $coderef->( $sid, $iso );
62         }
63
64
65 }
66
67 my $sid_iso;
68
69 sub inventory {
70
71         my @tags; 
72         _grep_tool 'librfid-tool', '--scan' => sub {
73                 my ( $sid, $iso ) = @_;
74                 if ( $sid ) {
75                         push @tags, $sid unless defined $sid_iso->{$sid};
76                         $sid_iso->{$sid} = $iso;
77                 }
78         };
79         warn "# invetory ",dump(@tags);
80         return @tags;
81 }
82
83 sub tag_type {
84         my ( $self, $tag ) = @_;
85         return $sid_iso->{$tag} =~ m/15693/ ? 'RFID501' : 'SmartX';
86 }
87
88 our $mifare_keys;
89 sub read_mifare_keys {
90         my $key_path = $0;
91         $key_path =~ s{/[^/]+$}{/};
92         $key_path .= "mifare_keys.pl";
93         warn "# $key_path";
94         if ( -e $key_path ) {
95                 require $key_path;
96                 warn "# mifare keys for sectors ", join(' ', keys %$mifare_keys), " loaded\n";
97         }
98 }
99
100 sub read_blocks {
101         my ( $self, $sid ) = @_;
102
103         my $iso = $sid_iso->{$sid};
104         my $blocks;
105
106         if ( $iso =~ m/15693/ ) {
107                 _grep_tool 'librfid-tool', '--read -1' => sub {
108                         $sid ||= shift;
109                         $blocks->{$sid}->[$1] = hex2bytes($2)
110                         if m/block\[\s*(\d+):.+data.+:\s*(.+)/;
111
112                 };
113         } else {
114                 read_mifare_keys unless $mifare_keys;
115
116                 foreach my $sector ( keys %$mifare_keys ) {
117                         my $key = lc $mifare_keys->{$sector};
118                         _grep_tool 'mifare-tool', "-k $key -r $sector" => sub {
119                                 $blocks->{$sid}->[$sector] = hex2bytes($1)
120                                 if m/data=\s*(.+)/;
121                         };
122                 }
123         }
124         warn "# read_blocks ",dump($blocks);
125         return $blocks;
126 }
127
128 sub write_blocks {}
129 sub read_afi { -1 }
130 sub write_afi {}
131
132 1