added timeout to 3s for librfid tools
[Biblio-RFID.git] / lib / Biblio / RFID / Reader / librfid.pm
index e4136cc..a72395e 100644 (file)
@@ -22,6 +22,10 @@ Due to limitation of L<librfid-tool> only
 L<Biblio::RFID::Reader::API/inventory> and
 L<Biblio::RFID::Reader::API/read_blocks> is supported.
 
+This version uses modidified C<librfid-tool> which supports
+new C<-s> flag which reads sectors 0-3 with C<-k> key and
+sectors 4-7 with key from C<-s> option.
+
 However, this code might provide template for integration
 with any command-line utilities for different RFID readers.
 
@@ -40,46 +44,116 @@ sub init { 1 }
 sub _grep_tool {
        my ( $bin, $param, $coderef, $path ) = @_;
 
+       my $timeout = 3; # s
+
+       eval {
+
+       local $SIG{ALRM} = sub { die "timeout\n" };
+       alarm $timeout;
+
        warn "# _grep_tool $bin $param\n";
-       open(my $s, '-|', "$bin $param") || die $!;
+       open(my $s, '-|', "$bin $param 2>/dev/null") || die $!;
+
+       my $sid;
+       my $iso;
+
        while(<$s>) {
                chomp;
                warn "## $_\n";
 
-               my $sid;
-               if ( m/success.+:\s+(.+)/ ) {
-                       $sid = $1;
+               if ( m/Layer 2 success.+\(([^\)]+)\).*:\s+(.+)/ ) {
+                       ( $sid, $iso ) = ( $2, $1 );
                        $sid =~ s/\s*'\s*//g;
-                       $sid = uc join('', reverse split(/\s+/, $sid));
+                       my @sid = split(/\s+/, $sid);
+                       @sid = reverse @sid if $iso =~ m/15693/;
+                       $sid = uc join('', @sid);
+                       warn "## sid=[$sid] iso=[$iso]\n";
                }
-
-               $coderef->( $sid );
+               $coderef->( $sid, $iso );
        }
 
+       alarm(0);
+       close($s);
+
+       }; # eval
+
+       if ( $? >> 8 || $@ ) {
+               my $lsusb = `lsusb -d 076b:`;
+               if ( $lsusb =~ m/\S+\s+(\d+)\s+\S+\s+(\d+)/ ) {
+                       my $cmd = "usbreset /dev/bus/usb/$1/$2";
+                       warn "# $cmd\n";
+                       system $cmd;
+               } else {
+                       warn "can't reset device $lsusb";
+               }
+       }
 
 }
 
+my $sid_iso;
+
 sub inventory {
 
        my @tags; 
+       $sid_iso = {};
        _grep_tool 'librfid-tool', '--scan' => sub {
-               my $sid = shift;
-               push @tags, $sid if $sid;
+               my ( $sid, $iso ) = @_;
+               if ( $sid && ! exists $sid_iso->{$sid} ) {
+                       push @tags, $sid;
+                       $sid_iso->{$sid} = $iso;
+               }
        };
        warn "# invetory ",dump(@tags);
        return @tags;
 }
 
+sub tag_type {
+       my ( $self, $tag ) = @_;
+       return $sid_iso->{$tag} =~ m/15693/ ? 'RFID501' : 'SmartX';
+}
+
+our $mifare_keys;
+sub read_mifare_keys {
+       my $key_path = $0;
+       $key_path =~ s{/[^/]+$}{/};
+       $key_path .= "mifare_keys.pl";
+       warn "# $key_path";
+       if ( -e $key_path ) {
+               require $key_path;
+               warn "# mifare keys for sectors ", join(' ', keys %$mifare_keys), " loaded\n";
+       }
+}
+
 sub read_blocks {
+       my ( $self, $sid ) = @_;
 
-       my $sid;
+       my $iso = $sid_iso->{$sid};
        my $blocks;
-       _grep_tool 'librfid-tool', '--read -1' => sub {
-               $sid ||= shift;
-               $blocks->{$sid}->[$1] = hex2bytes($2)
-               if m/block\[\s*(\d+):.+data.+:\s*(.+)/;
 
-       };
+       if ( $iso =~ m/15693/ ) {
+               _grep_tool 'librfid-tool', '--read -1' => sub {
+                       $sid ||= shift;
+                       $blocks->{$sid}->[$1] = hex2bytes($2)
+                       if m/block\[\s*(\d+):.+data.+:\s*(.+)/;
+
+               };
+       } else {
+               read_mifare_keys unless $mifare_keys;
+
+=for unmodified mifate-tool
+               foreach my $sector ( keys %$mifare_keys ) {
+                       my $key = lc $mifare_keys->{$sector};
+                       _grep_tool 'mifare-tool', "-k $key -r $sector" => sub {
+                               $blocks->{$sid}->[$sector] = hex2bytes($1)
+                               if m/data=\s*(.+)/;
+                       };
+               }
+=cut
+               _grep_tool 'mifare-tool', "-k " . $mifare_keys->{0} . " -s " . $mifare_keys->{4} => sub {
+                       $blocks->{$sid}->[$1] = hex2bytes($2)
+                       if m/page=(\d+).*data=\s*(.+)/;
+               };
+       }
        warn "# read_blocks ",dump($blocks);
        return $blocks;
 }