/[RFID]/3m-810.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /3m-810.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 50 by dpavlin, Wed Jun 24 09:30:28 2009 UTC revision 92 by dpavlin, Fri Jul 23 13:16:51 2010 UTC
# Line 9  use Carp qw/confess/; Line 9  use Carp qw/confess/;
9  use Getopt::Long;  use Getopt::Long;
10  use File::Slurp;  use File::Slurp;
11  use JSON;  use JSON;
12    use POSIX qw(strftime);
13    
14  use IO::Socket::INET;  use IO::Socket::INET;
15    
16  my $debug = 0;  my $debug = 0;
17    
18  my $meteor_server = '192.168.1.13:4671';  my $tags_data;
19  my $meteor_fh;  my $tags_security;
20    my $visible_tags;
 sub meteor {  
         my @a = @_;  
         push @a, scalar localtime() if $a[0] =~ m{^info};  
   
         if ( ! defined $meteor_fh ) {  
                 if ( $meteor_fh =  
                                 IO::Socket::INET->new(  
                                         PeerAddr => $meteor_server,  
                                         Timeout => 1,  
                                 )  
                 ) {  
                         warn "# meteor connected to $meteor_server";  
                 } else {  
                         warn "can't connect to meteor $meteor_server: $!";  
                         $meteor_fh = 0;  
                 }  
         }  
   
         if ( $meteor_fh ) {  
                 warn ">> meteor ",dump( @a );  
                 print $meteor_fh "ADDMESSAGE test ",join('|',@a),"\n"  
         }  
 }  
21    
22  my $listen_port = 9000;                  # pick something not in use  my $listen_port = 9000;                  # pick something not in use
23    my $server_url  = "http://localhost:$listen_port";
24    
25  sub http_server {  sub http_server {
26    
27          my $server = IO::Socket::INET->new(          my $server = IO::Socket::INET->new(
# Line 51  sub http_server { Line 31  sub http_server {
31                  Reuse     => 1                  Reuse     => 1
32          );          );
33                                                                                                                                        
34          die "can't setup server" unless $server;          die "can't setup server: $!" unless $server;
35    
36          print "Server $0 accepting clients at http://localhost:$listen_port/\n";          print "Server $0 ready at $server_url\n";
37    
38          sub static {          sub static {
39                  my ($client,$path) = @_;                  my ($client,$path) = @_;
40    
41                  $path = "www/$path";                  $path = "www/$path";
42                    $path .= 'rfid.html' if $path =~ m{/$};
43    
44                  return unless -e $path;                  return unless -e $path;
45    
# Line 96  sub http_server { Line 77  sub http_server {
77                                  warn "WEB >> $path" if $debug;                                  warn "WEB >> $path" if $debug;
78                          } elsif ( $method =~ m{/scan} ) {                          } elsif ( $method =~ m{/scan} ) {
79                                  my $tags = scan_for_tags();                                  my $tags = scan_for_tags();
80                                  my $json = {};                                  my $json = { time => time() };
81                                  map {                                  map {
82                                          my $d = decode_tag($_);                                          my $d = decode_tag($_);
83                                          $d->{sid} = $_;                                          $d->{sid} = $_;
84                                            $d->{security} = $tags_security->{$_};
85                                          push @{ $json->{tags} },  $d;                                          push @{ $json->{tags} },  $d;
86                                  } keys %$tags;                                  } keys %$tags;
87                                  print $client "HTTP/1.0 200 OK\r\nContent-Type: application/x-javascript\r\n\r\n",                                  print $client "HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n",
88                                          $param->{callback}, "(", to_json($json), ")\r\n";                                          $param->{callback}, "(", to_json($json), ")\r\n";
89                            } elsif ( $method =~ m{/program} ) {
90    
91                                    my $status = 501; # Not implementd
92    
93                                    foreach my $p ( keys %$param ) {
94                                            next unless $p =~ m/^(E[0-9A-F]{15})$/;
95                                            my $tag = $1;
96                                            my $content = "\x04\x11\x00\x01" . $param->{$p};
97                                            $content = "\x00" if $param->{$p} eq 'blank';
98                                            $status = 302;
99    
100                                            warn "PROGRAM $tag $content\n";
101                                            write_tag( $tag, $content );
102                                            secure_tag_with( $tag, $param->{$p} =~ /^130/ ? 'DA' : 'D7' );
103                                    }
104    
105                                    print $client "HTTP/1.0 $status $method\r\nLocation: $server_url\r\n\r\n";
106    
107                            } elsif ( $method =~ m{/secure(.js)} ) {
108    
109                                    my $json = $1;
110    
111                                    my $status = 501; # Not implementd
112    
113                                    foreach my $p ( keys %$param ) {
114                                            next unless $p =~ m/^(E[0-9A-F]{15})$/;
115                                            my $tag = $1;
116                                            my $data = $param->{$p};
117                                            $status = 302;
118    
119                                            warn "SECURE $tag $data\n";
120                                            secure_tag_with( $tag, $data );
121                                    }
122    
123                                    if ( $json ) {
124                                            print $client "HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n",
125                                                    $param->{callback}, "({ ok: 1 })\r\n";
126                                    } else {
127                                            print $client "HTTP/1.0 $status $method\r\nLocation: $server_url\r\n\r\n";
128                                    }
129    
130                          } else {                          } else {
131                                  print $client "HTTP/1.0 404 Unkown method\r\n";                                  print $client "HTTP/1.0 404 Unkown method\r\n\r\n";
132                          }                          }
133                  } else {                  } else {
134                          print $client "HTTP/1.0 500 No method\r\n";                          print $client "HTTP/1.0 500 No method\r\n\r\n";
135                  }                  }
136                  close $client;                  close $client;
137          }          }
# Line 145  my $secure_path = './secure/'; Line 168  my $secure_path = './secure/';
168  my $http_server = 1;  my $http_server = 1;
169    
170  # 3M defaults: 8,4  # 3M defaults: 8,4
171  my $max_rfid_block = 16;  # cards 16, stickers: 8
172    my $max_rfid_block = 8;
173  my $read_blocks = 8;  my $read_blocks = 8;
174    
175  my $response = {  my $response = {
# Line 168  GetOptions( Line 192  GetOptions(
192          'parity=s'    => \$parity,          'parity=s'    => \$parity,
193          'stopbits=i'  => \$stopbits,          'stopbits=i'  => \$stopbits,
194          'handshake=s' => \$handshake,          'handshake=s' => \$handshake,
         'meteor=s'    => \$meteor_server,  
195          'http-server!' => \$http_server,          'http-server!' => \$http_server,
196  ) or die $!;  ) or die $!;
197    
# Line 205  it under the same terms ans Perl itself. Line 228  it under the same terms ans Perl itself.
228    
229  =cut  =cut
230    
 my $tags_data;  
 my $visible_tags;  
   
231  my $item_type = {  my $item_type = {
232          1 => 'Book',          1 => 'Book',
233          6 => 'CD/CD ROM',          6 => 'CD/CD ROM',
# Line 250  cmd( 'D5 00  05   04 00 11 Line 270  cmd( 'D5 00  05   04 00 11
270       'D5 00  09   04 00 11   0A 05 00 02   7250', sub {       'D5 00  09   04 00 11   0A 05 00 02   7250', sub {
271          my $hw_ver = join('.', unpack('CCCC', skip_assert(3) ));          my $hw_ver = join('.', unpack('CCCC', skip_assert(3) ));
272          print "hardware version $hw_ver\n";          print "hardware version $hw_ver\n";
         meteor( 'info', "Found reader hardware $hw_ver" );  
273  });  });
274    
275  cmd( 'D6 00  0C   13  04  01 00  02 00  03 00  04 00   AAF2','FIXME: stats?',  cmd( 'D6 00  0C   13  04  01 00  02 00  03 00  04 00   AAF2','FIXME: stats?',
# Line 268  sub scan_for_tags { Line 287  sub scan_for_tags {
287                          if ( ! $nr ) {                          if ( ! $nr ) {
288                                  _log "no tags in range\n";                                  _log "no tags in range\n";
289                                  update_visible_tags();                                  update_visible_tags();
                                 meteor( 'info-none-in-range' );  
290                                  $tags_data = {};                                  $tags_data = {};
291                          } else {                          } else {
292    
# Line 280  sub scan_for_tags { Line 298  sub scan_for_tags {
298                                  warn "## tags ",as_hex($tags), " [$tl] = ",dump( $tags ) if $debug;                                  warn "## tags ",as_hex($tags), " [$tl] = ",dump( $tags ) if $debug;
299                                  _log "$nr tags in range: ", join(',', @tags ) , "\n";                                  _log "$nr tags in range: ", join(',', @tags ) , "\n";
300    
                                 meteor( 'info-in-range', join(' ',@tags));  
   
301                                  update_visible_tags( @tags );                                  update_visible_tags( @tags );
302                          }                          }
303                  }                  }
# Line 297  sub scan_for_tags { Line 313  sub scan_for_tags {
313  if ( $http_server ) {  if ( $http_server ) {
314          http_server;          http_server;
315  } else {  } else {
316          scan_for_tags while 1;          while (1) {
317                    scan_for_tags;
318                    sleep 1;
319            }
320  }  }
321    
322  die "over and out";  die "over and out";
# Line 309  sub update_visible_tags { Line 328  sub update_visible_tags {
328          $visible_tags = {};          $visible_tags = {};
329    
330          foreach my $tag ( @tags ) {          foreach my $tag ( @tags ) {
331                    $visible_tags->{$tag}++;
332                  if ( ! defined $last_visible_tags->{$tag} ) {                  if ( ! defined $last_visible_tags->{$tag} ) {
333                          if ( defined $tags_data->{$tag} ) {                          if ( defined $tags_data->{$tag} ) {
334  #                               meteor( 'in-range', $tag );                                  warn "$tag in range\n";
335                          } else {                          } else {
                                 meteor( 'read', $tag );  
336                                  read_tag( $tag );                                  read_tag( $tag );
337                          }                          }
                         $visible_tags->{$tag}++;  
338                  } else {                  } else {
339                          warn "## using cached data for $tag" if $debug;                          warn "## using cached data for $tag" if $debug;
340                  }                  }
341                  delete $last_visible_tags->{$tag}; # leave just missing tags                  delete $last_visible_tags->{$tag}; # leave just missing tags
342    
343                  if ( -e "$program_path/$tag" ) {                  if ( -e "$program_path/$tag" ) {
                                 meteor( 'write', $tag );  
344                                  write_tag( $tag );                                  write_tag( $tag );
345                  }                  }
346                  if ( -e "$secure_path/$tag" ) {                  if ( -e "$secure_path/$tag" ) {
                                 meteor( 'secure', $tag );  
347                                  secure_tag( $tag );                                  secure_tag( $tag );
348                  }                  }
349          }          }
350    
351          foreach my $tag ( keys %$last_visible_tags ) {          foreach my $tag ( keys %$last_visible_tags ) {
352                  my $data = delete $tags_data->{$tag};                  my $data = delete $tags_data->{$tag};
353                  print "removed tag $tag with data ",dump( $data ),"\n";                  warn "$tag removed ", dump($data), $/;
                 meteor( 'removed', $tag );  
354          }          }
355    
356          warn "## update_visible_tags(",dump( @tags ),") = ",dump( $visible_tags )," removed: ",dump( $last_visible_tags ), " data: ",dump( $tags_data ) if $debug;          warn "## update_visible_tags(",dump( @tags ),") = ",dump( $visible_tags )," removed: ",dump( $last_visible_tags ), " data: ",dump( $tags_data ) if $debug;
# Line 373  sub read_tag_data { Line 388  sub read_tag_data {
388          return $last_block + 1;          return $last_block + 1;
389  }  }
390    
391    my $saved_in_log;
392    
393  sub decode_tag {  sub decode_tag {
394          my $tag = shift;          my $tag = shift;
395    
396          my $data = $tags_data->{$tag} || die "no data for $tag";          my $data = $tags_data->{$tag};
397            if ( ! $data ) {
398                    warn "no data for $tag\n";
399                    return;
400            }
401    
402          my ( $u1, $set_item, $u2, $type, $content, $br_lib, $custom ) = unpack('C4Z16Nl>',$data);          my ( $u1, $set_item, $u2, $type, $content, $br_lib, $custom ) = unpack('C4Z16Nl>',$data);
403          my $hash = {          my $hash = {
# Line 394  sub decode_tag { Line 415  sub decode_tag {
415                  custom => $custom,                  custom => $custom,
416          };          };
417    
418            if ( ! $saved_in_log->{$tag}++ ) {
419                    open(my $log, '>>', 'rfid-log.txt');
420                    print $log strftime( "%Y-%m-%d %H:%M:%S", localtime ), ",$tag,$content\n";
421                    close($log);
422            }
423    
424          return $hash;          return $hash;
425  }  }
426    
427    sub forget_tag {
428            my $tag = shift;
429            delete $tags_data->{$tag};
430            delete $visible_tags->{$tag};
431    }
432    
433  sub read_tag {  sub read_tag {
434          my ( $tag ) = @_;          my ( $tag ) = @_;
435    
# Line 409  sub read_tag { Line 442  sub read_tag {
442          while ( $start_block < $max_rfid_block ) {          while ( $start_block < $max_rfid_block ) {
443    
444                  cmd(                  cmd(
445                           sprintf( "D6 00  0D  02      $tag   %02x   %02x     ffff", $start_block, $read_blocks ),                           sprintf( "D6 00  0D  02      $tag   %02x   %02x     BEEF", $start_block, $read_blocks ),
446                                  "read $tag offset: $start_block blocks: $read_blocks",                                  "read $tag offset: $start_block blocks: $read_blocks",
447                          "D6 00  1F  02 00", sub { # $tag  03   00 00   04 11 00 01   01 00   31 32 33 34   02 00   35 36 37 38    531F\n";                          "D6 00  1F  02 00", sub { # $tag  03   00 00   04 11 00 01   01 00   31 32 33 34   02 00   35 36 37 38    531F\n";
448                                  $start_block = read_tag_data( $start_block, @_ );                                  $start_block = read_tag_data( $start_block, @_ );
449                                  warn "# read tag upto $start_block\n";                                  warn "# read tag upto $start_block\n";
450                          },                          },
451                          "D6 00  0F  FE  00 00  05 01   $tag    941A", sub {                          "D6 00  0F  FE  00 00  05 01   $tag    BEEF", sub {
452                                  print "FIXME: tag $tag ready? (expected block read instead)\n";                                  print "FIXME: tag $tag ready? (expected block read instead)\n";
453                          },                          },
454                            "D6 00 0D 02 06 $tag", sub {
455                                    my $rest = shift;
456                                    print "ERROR reading $tag ", as_hex($rest), $/;
457                                    forget_tag $tag;
458                                    $start_block = $max_rfid_block; # XXX break out of while
459                            },
460                  );                  );
461    
462          }          }
# Line 425  sub read_tag { Line 464  sub read_tag {
464          my $security;          my $security;
465    
466          cmd(          cmd(
467                  "D6 00 0B 0A $tag 1234", "check security $tag",                  "D6 00 0B 0A $tag BEEF", "check security $tag",
468                  "D6 00 0D 0A 00", sub {                  "D6 00 0D 0A 00", sub {
469                          my $rest = shift;                          my $rest = shift;
470                          my $from_tag;                          my $from_tag;
471                          ( $from_tag, $security ) = ( substr($rest,0,8), substr($rest,8,1) );                          ( $from_tag, $security ) = ( substr($rest,0,8), substr($rest,8,1) );
472                          die "security from other tag: ",as_hex( $from_tag ) if $from_tag ne str2bytes( $tag );                          die "security from other tag: ",as_hex( $from_tag ) if $from_tag ne str2bytes( $tag );
473                          $security = as_hex( $security );                          $security = as_hex( $security );
474                            $tags_security->{$tag} = $security;
475                          warn "# SECURITY $tag = $security\n";                          warn "# SECURITY $tag = $security\n";
476                  }                  },
477                    "D6 00 0C 0A 06", sub {
478                            my $rest = shift;
479                            warn "ERROR reading security from $rest\n";
480                            forget_tag $tag;
481                    },
482          );          );
483    
484          print "TAG $tag ", dump(decode_tag( $tag ));          print "TAG $tag ", dump(decode_tag( $tag ));
485  }  }
486    
487  sub write_tag {  sub write_tag {
488          my ($tag) = @_;          my ($tag,$data) = @_;
489    
490          my $path = "$program_path/$tag";          my $path = "$program_path/$tag";
491            $data = read_file( $path ) if -e $path;
492    
493            die "no data" unless $data;
494    
         my $data = read_file( $path );  
495          my $hex_data;          my $hex_data;
496    
497          if ( $data =~ s{^hex\s+}{} ) {          if ( $data =~ s{^hex\s+}{} ) {
# Line 471  sub write_tag { Line 518  sub write_tag {
518    
519          print "write_tag $tag = ",dump( $data ), " [$len/$blocks] == $hex_data\n";          print "write_tag $tag = ",dump( $data ), " [$len/$blocks] == $hex_data\n";
520    
521            my $ok = 0;
522    
523          cmd(          cmd(
524                  "d6 00  ff  04  $tag  00 $blocks 00  $hex_data  ffff", "write $tag",                  "d6 00  ff  04  $tag  00 $blocks 00  $hex_data  BEEF", "write $tag",
525                  "d6 00  0d  04 00  $tag  $blocks  afb1", sub { assert() },                  "d6 00  0d  06 00  $tag  $blocks  BEEF", sub { assert(); $ok++ },
526                    "d6 00  0d  04 06  ", sub {
527                            my $data = shift;
528                            warn "no tag ",as_hex( substr($data,0,8) ), " in range for write\n";
529                    },
530          ); # foreach ( 1 .. 3 ); # XXX 3m software does this three times!          ); # foreach ( 1 .. 3 ); # XXX 3m software does this three times!
531    
532          my $to = $path;          if ( $ok ) {
         $to .= '.' . time();  
533    
534          rename $path, $to;                  my $to = $path;
535          print ">> $to\n";                  $to .= '.' . time();
536    
537                    rename $path, $to;
538                    print ">> $to\n";
539    
540            }
541    
542            forget_tag $tag;
543    }
544    
545    sub secure_tag_with {
546            my ( $tag, $data ) = @_;
547    
548          delete $tags_data->{$tag};      # force re-read of tag          cmd(
549                    "d6 00  0c  09  $tag $data BEEF", "secure $tag -> $data",
550                    "d6 00  0c  09 00  $tag    BEEF", sub { assert() },
551                    "d6 00  0c  09 06  ", sub {
552                            my $data = shift;
553                            warn "no tag ",as_hex( substr($data,0,8) ), " in range for secure\n";
554                    },
555            );
556    
557            forget_tag $tag;
558  }  }
559    
560  sub secure_tag {  sub secure_tag {
# Line 491  sub secure_tag { Line 563  sub secure_tag {
563          my $path = "$secure_path/$tag";          my $path = "$secure_path/$tag";
564          my $data = substr(read_file( $path ),0,2);          my $data = substr(read_file( $path ),0,2);
565    
566          cmd(          secure_tag_with( $tag, $data );
                 "d6 00  0c  09  $tag $data 1234", "secure $tag -> $data",  
                 "d6 00  0c  09 00  $tag  1234", sub { assert() },  
         );  
567    
568          my $to = $path;          my $to = $path;
569          $to .= '.' . time();          $to .= '.' . time();
# Line 543  sub writechunk Line 612  sub writechunk
612  sub as_hex {  sub as_hex {
613          my @out;          my @out;
614          foreach my $str ( @_ ) {          foreach my $str ( @_ ) {
615                  my $hex = unpack( 'H*', $str );                  my $hex = uc unpack( 'H*', $str );
616                  $hex =~ s/(..)/$1 /g if length( $str ) > 2;                  $hex =~ s/(..)/$1 /g if length( $str ) > 2;
617                  $hex =~ s/\s+$//;                  $hex =~ s/\s+$//;
618                  push @out, $hex;                  push @out, $hex;
# Line 615  sub checksum { Line 684  sub checksum {
684          warn "## checksum ",dump( $bytes, $xor, $checksum ) if $debug;          warn "## checksum ",dump( $bytes, $xor, $checksum ) if $debug;
685    
686          if ( defined $checksum && $xor ne $checksum ) {          if ( defined $checksum && $xor ne $checksum ) {
687                  print "checksum doesn't match: ", as_hex($xor), " != ", as_hex($checksum), " data: ", as_hex($bytes), "\n";                  warn "checksum error: ", as_hex($xor), " != ", as_hex($checksum), " data: ", as_hex($bytes), "\n" if $checksum ne "\xBE\xEF";
688                  return $bytes . $xor;                  return $bytes . $xor;
689          }          }
690          return $bytes . $checksum;          return $bytes . $checksum;
# Line 657  sub readchunk { Line 726  sub readchunk {
726                  warn "## DISPATCH payload to with rest", dump( $payload, $to, $rest ) if $debug;                  warn "## DISPATCH payload to with rest", dump( $payload, $to, $rest ) if $debug;
727                  $dispatch->{ $to }->( $rest );                  $dispatch->{ $to }->( $rest );
728          } else {          } else {
729                  print "NO DISPATCH for ",dump( $full ),"\n";                  die "NO DISPATCH for ",as_hex( $full ), " in ", dump( $dispatch );
730          }          }
731    
732          return $data;          return $data;

Legend:
Removed from v.50  
changed lines
  Added in v.92

  ViewVC Help
Powered by ViewVC 1.1.26