0e3326836db814c7b71c6ca2f16e88f96f718eb5
[Biblio-RFID.git] / lib / RFID / Serial / CPRM02.pm
1 package RFID::Serial::CPRM02;
2
3 use base 'RFID::Serial';
4 use RFID::Serial;
5
6 use Time::HiRes;
7
8 sub serial_settings {{
9         device    => "/dev/ttyUSB0",
10         baudrate  => "38400",
11         databits  => "8",
12         parity    => "even",
13         stopbits  => "1",
14         handshake => "none",
15 }}
16
17 sub cpr_m02_checksum {
18         my $data = shift;
19
20         my $preset = 0xffff;
21         my $polynom = 0x8408;
22
23         my $crc = $preset;
24         foreach my $i ( 0 .. length($data) - 1 ) {
25                 $crc ^= ord(substr($data,$i,1));
26                 for my $j ( 0 .. 7 ) {
27                         if ( $crc & 0x0001 ) {
28                                 $crc = ( $crc >> 1 ) ^ $polynom;
29                         } else {
30                                 $crc = $crc >> 1;
31                         }
32                 }
33 #               warn sprintf('%d %04x', $i, $crc & 0xffff);
34         }
35
36         return pack('v', $crc);
37 }
38
39 sub cpr_psst_wait {
40         # Protocol Start Synchronization Time (PSST): 5ms < data timeout 12 ms
41         Time::HiRes::sleep 0.005;
42 }
43
44 our $port;
45
46 sub cpr {
47         my ( $hex, $description, $coderef ) = @_;
48         my $bytes = hex2bytes($hex);
49         my $len = pack( 'c', length( $bytes ) + 3 );
50         my $send = $len . $bytes;
51         my $checksum = cpr_m02_checksum($send);
52         $send .= $checksum;
53
54         warn ">> ", as_hex( $send ), "\t\t[$description]\n";
55         $port->write( $send );
56
57         cpr_psst_wait;
58
59         my $r_len = $port->read(1);
60
61         while ( ! $r_len ) {
62                 warn "# wait for response length 5ms\n";
63                 cpr_psst_wait;
64                 $r_len = $port->read(1);
65         }
66
67         my $data_len = ord($r_len) - 1;
68         my $data = $port->read( $data_len );
69         warn "<< ", as_hex( $r_len . $data ),"\n";
70
71         cpr_psst_wait;
72
73         $coderef->( $data ) if $coderef;
74
75 }
76
77 # FF = COM-ADDR any
78
79 sub init {
80         my $self = shift;
81
82         $port = $self->port;
83
84 cpr( 'FF  52 00',       'Boud Rate Detection' );
85
86 cpr( 'FF  65',          'Get Software Version' );
87
88 cpr( 'FF  66 00',       'Get Reader Info - General hard and firware' );
89
90 cpr( 'FF  69',          'RF Reset' );
91
92 }
93
94 sub cpr_read {
95         my $uid = shift;
96         my $hex_uid = as_hex($uid);
97
98         my $max_block;
99
100         cpr( "FF  B0 2B  01  $hex_uid", "Get System Information $hex_uid", sub {
101                 my $data = shift;
102
103                 warn "# data ",as_hex($data);
104
105                 my $DSFID    = substr($data,5-2,1);
106                 my $UID      = substr($data,6-2,8);
107                 my $AFI      = substr($data,14-2,1);
108                 my $MEM      = substr($data,15-2,1);
109                 my $SIZE     = substr($data,16-2,1);
110                 my $IC_REF   = substr($data,17-2,1);
111
112                 warn "# split ",as_hex( $DSFID, $UID, $AFI, $MEM, $SIZE, $IC_REF );
113
114                 $max_block = ord($SIZE);
115         });
116
117         my $transponder_data;
118
119         my $block = 0;
120         while ( $block < $max_block ) {
121                 cpr( sprintf("FF  B0 23  01  $hex_uid %02x 04", $block), "Read Multiple Blocks $block", sub {
122                         my $data = shift;
123
124                         my $DB_N    = ord substr($data,5-2,1);
125                         my $DB_SIZE = ord substr($data,6-2,1);
126
127                         $data = substr($data,7-2,-2);
128                         warn "# DB N: $DB_N SIZE: $DB_SIZE ", as_hex( $data ), " transponder_data: [$transponder_data] ",length($transponder_data),"\n";
129                         foreach ( 1 .. $DB_N ) {
130                                 my $sec = substr($data,0,1);
131                                 my $db  = substr($data,1,$DB_SIZE);
132                                 warn "block $_ ",dump( $sec, $db );
133                                 $transponder_data .= reverse split(//,$db);
134                                 $data = substr($data, $DB_SIZE + 1);
135                         }
136                 });
137                 $block += 4;
138         }
139
140         warn "DATA $hex_uid ", dump($transponder_data);
141         exit;
142 }
143
144
145 my $inventory;
146
147 sub inventory {
148
149 cpr( 'FF  B0  01 00', 'ISO - Inventory', sub {
150         my $data = shift;
151         if (length($data) < 5 + 2 ) {
152                 warn "# no tags in range\n";
153                 return;
154         }
155         my $data_sets = ord(substr($data,3,1));
156         $data = substr($data,4);
157         foreach ( 1 .. $data_sets ) {
158                 my $tr_type = substr($data,0,1);
159                 die "FIXME only TR-TYPE=3 ISO 15693 supported" unless $tr_type eq "\x03";
160                 my $dsfid   = substr($data,1,1);
161                 my $uid     = substr($data,2,8);
162                 $inventory->{$uid}++;
163                 $data = substr($data,10);
164                 warn "# TAG $_ ",as_hex( $tr_type, $dsfid, $uid ),$/;
165
166                 cpr_read( $uid );
167         }
168         warn "inventory: ",dump($inventory);
169 });
170
171 }
172
173 1