0f559fd83b91349071ca348c1939ad1e27f83057
[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         close($s);
69         if ( $? >> 8 ) {
70                 my $lsusb = `lsusb -d 076b:`;
71                 if ( $lsusb =~ m/\S+\s+(\d+)\s+\S+\s+(\d+)/ ) {
72                         my $cmd = "usbreset /dev/bus/usb/$1/$2";
73                         warn "# $cmd\n";
74                         system $cmd;
75                 } else {
76                         warn "can't reset device $lsusb";
77                 }
78         }
79
80 }
81
82 my $sid_iso;
83
84 sub inventory {
85
86         my @tags; 
87         $sid_iso = {};
88         _grep_tool 'librfid-tool', '--scan' => sub {
89                 my ( $sid, $iso ) = @_;
90                 if ( $sid && ! exists $sid_iso->{$sid} ) {
91                         push @tags, $sid;
92                         $sid_iso->{$sid} = $iso;
93                 }
94         };
95         warn "# invetory ",dump(@tags);
96         return @tags;
97 }
98
99 sub tag_type {
100         my ( $self, $tag ) = @_;
101         return $sid_iso->{$tag} =~ m/15693/ ? 'RFID501' : 'SmartX';
102 }
103
104 our $mifare_keys;
105 sub read_mifare_keys {
106         my $key_path = $0;
107         $key_path =~ s{/[^/]+$}{/};
108         $key_path .= "mifare_keys.pl";
109         warn "# $key_path";
110         if ( -e $key_path ) {
111                 require $key_path;
112                 warn "# mifare keys for sectors ", join(' ', keys %$mifare_keys), " loaded\n";
113         }
114 }
115
116 sub read_blocks {
117         my ( $self, $sid ) = @_;
118
119         my $iso = $sid_iso->{$sid};
120         my $blocks;
121
122         if ( $iso =~ m/15693/ ) {
123                 _grep_tool 'librfid-tool', '--read -1' => sub {
124                         $sid ||= shift;
125                         $blocks->{$sid}->[$1] = hex2bytes($2)
126                         if m/block\[\s*(\d+):.+data.+:\s*(.+)/;
127
128                 };
129         } else {
130                 read_mifare_keys unless $mifare_keys;
131
132 =for unmodified mifate-tool
133                 foreach my $sector ( keys %$mifare_keys ) {
134                         my $key = lc $mifare_keys->{$sector};
135                         _grep_tool 'mifare-tool', "-k $key -r $sector" => sub {
136                                 $blocks->{$sid}->[$sector] = hex2bytes($1)
137                                 if m/data=\s*(.+)/;
138                         };
139                 }
140 =cut
141                 _grep_tool 'mifare-tool', "-k " . $mifare_keys->{0} . " -s " . $mifare_keys->{4} => sub {
142                         $blocks->{$sid}->[$1] = hex2bytes($2)
143                         if m/page=(\d+).*data=\s*(.+)/;
144                 };
145         }
146         warn "# read_blocks ",dump($blocks);
147         return $blocks;
148 }
149
150 sub write_blocks {}
151 sub read_afi { -1 }
152 sub write_afi {}
153
154 1