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