begin of CPR-M02 support
authorDobrica Pavlinusic <dpavlin@rot13.org>
Mon, 26 Jul 2010 16:39:07 +0000 (18:39 +0200)
committerDobrica Pavlinusic <dpavlin@rot13.org>
Mon, 26 Jul 2010 16:39:07 +0000 (18:39 +0200)
lib/RFID/Serial/CPRM02.pm [new file with mode: 0644]
t/20-CPR-M02.t [new file with mode: 0755]

diff --git a/lib/RFID/Serial/CPRM02.pm b/lib/RFID/Serial/CPRM02.pm
new file mode 100644 (file)
index 0000000..0e33268
--- /dev/null
@@ -0,0 +1,173 @@
+package RFID::Serial::CPRM02;
+
+use base 'RFID::Serial';
+use RFID::Serial;
+
+use Time::HiRes;
+
+sub serial_settings {{
+       device    => "/dev/ttyUSB0",
+       baudrate  => "38400",
+       databits  => "8",
+       parity    => "even",
+       stopbits  => "1",
+       handshake => "none",
+}}
+
+sub cpr_m02_checksum {
+       my $data = shift;
+
+       my $preset = 0xffff;
+       my $polynom = 0x8408;
+
+       my $crc = $preset;
+       foreach my $i ( 0 .. length($data) - 1 ) {
+               $crc ^= ord(substr($data,$i,1));
+               for my $j ( 0 .. 7 ) {
+                       if ( $crc & 0x0001 ) {
+                               $crc = ( $crc >> 1 ) ^ $polynom;
+                       } else {
+                               $crc = $crc >> 1;
+                       }
+               }
+#              warn sprintf('%d %04x', $i, $crc & 0xffff);
+       }
+
+       return pack('v', $crc);
+}
+
+sub cpr_psst_wait {
+       # Protocol Start Synchronization Time (PSST): 5ms < data timeout 12 ms
+       Time::HiRes::sleep 0.005;
+}
+
+our $port;
+
+sub cpr {
+       my ( $hex, $description, $coderef ) = @_;
+       my $bytes = hex2bytes($hex);
+       my $len = pack( 'c', length( $bytes ) + 3 );
+       my $send = $len . $bytes;
+       my $checksum = cpr_m02_checksum($send);
+       $send .= $checksum;
+
+       warn ">> ", as_hex( $send ), "\t\t[$description]\n";
+       $port->write( $send );
+
+       cpr_psst_wait;
+
+       my $r_len = $port->read(1);
+
+       while ( ! $r_len ) {
+               warn "# wait for response length 5ms\n";
+               cpr_psst_wait;
+               $r_len = $port->read(1);
+       }
+
+       my $data_len = ord($r_len) - 1;
+       my $data = $port->read( $data_len );
+       warn "<< ", as_hex( $r_len . $data ),"\n";
+
+       cpr_psst_wait;
+
+       $coderef->( $data ) if $coderef;
+
+}
+
+# FF = COM-ADDR any
+
+sub init {
+       my $self = shift;
+
+       $port = $self->port;
+
+cpr( 'FF  52 00',      'Boud Rate Detection' );
+
+cpr( 'FF  65',         'Get Software Version' );
+
+cpr( 'FF  66 00',      'Get Reader Info - General hard and firware' );
+
+cpr( 'FF  69',         'RF Reset' );
+
+}
+
+sub cpr_read {
+       my $uid = shift;
+       my $hex_uid = as_hex($uid);
+
+       my $max_block;
+
+       cpr( "FF  B0 2B  01  $hex_uid", "Get System Information $hex_uid", sub {
+               my $data = shift;
+
+               warn "# data ",as_hex($data);
+
+               my $DSFID    = substr($data,5-2,1);
+               my $UID      = substr($data,6-2,8);
+               my $AFI      = substr($data,14-2,1);
+               my $MEM      = substr($data,15-2,1);
+               my $SIZE     = substr($data,16-2,1);
+               my $IC_REF   = substr($data,17-2,1);
+
+               warn "# split ",as_hex( $DSFID, $UID, $AFI, $MEM, $SIZE, $IC_REF );
+
+               $max_block = ord($SIZE);
+       });
+
+       my $transponder_data;
+
+       my $block = 0;
+       while ( $block < $max_block ) {
+               cpr( sprintf("FF  B0 23  01  $hex_uid %02x 04", $block), "Read Multiple Blocks $block", sub {
+                       my $data = shift;
+
+                       my $DB_N    = ord substr($data,5-2,1);
+                       my $DB_SIZE = ord substr($data,6-2,1);
+
+                       $data = substr($data,7-2,-2);
+                       warn "# DB N: $DB_N SIZE: $DB_SIZE ", as_hex( $data ), " transponder_data: [$transponder_data] ",length($transponder_data),"\n";
+                       foreach ( 1 .. $DB_N ) {
+                               my $sec = substr($data,0,1);
+                               my $db  = substr($data,1,$DB_SIZE);
+                               warn "block $_ ",dump( $sec, $db );
+                               $transponder_data .= reverse split(//,$db);
+                               $data = substr($data, $DB_SIZE + 1);
+                       }
+               });
+               $block += 4;
+       }
+
+       warn "DATA $hex_uid ", dump($transponder_data);
+       exit;
+}
+
+
+my $inventory;
+
+sub inventory {
+
+cpr( 'FF  B0  01 00', 'ISO - Inventory', sub {
+       my $data = shift;
+       if (length($data) < 5 + 2 ) {
+               warn "# no tags in range\n";
+               return;
+       }
+       my $data_sets = ord(substr($data,3,1));
+       $data = substr($data,4);
+       foreach ( 1 .. $data_sets ) {
+               my $tr_type = substr($data,0,1);
+               die "FIXME only TR-TYPE=3 ISO 15693 supported" unless $tr_type eq "\x03";
+               my $dsfid   = substr($data,1,1);
+               my $uid     = substr($data,2,8);
+               $inventory->{$uid}++;
+               $data = substr($data,10);
+               warn "# TAG $_ ",as_hex( $tr_type, $dsfid, $uid ),$/;
+
+               cpr_read( $uid );
+       }
+       warn "inventory: ",dump($inventory);
+});
+
+}
+
+1
diff --git a/t/20-CPR-M02.t b/t/20-CPR-M02.t
new file mode 100755 (executable)
index 0000000..bfc560a
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+
+use Test::More tests => 2;
+use Data::Dump qw(dump);
+
+use lib 'lib';
+
+BEGIN {
+       use_ok( 'RFID::Serial::CPRM02' );
+}
+
+ok( my $o = RFID::Serial::CPRM02->new( device => '/dev/ttyUSB0' ), 'new' );
+
+