1 package RFID::Biblio::3M810;
6 use base 'RFID::Biblio';
9 use Data::Dump qw(dump);
14 sub serial_settings {{
15 device => "/dev/ttyUSB1", # FIXME comment out before shipping
29 my ( $count, $str ) = $port->read(3);
30 my $data = $port->read( ord(substr($str,2,1)) );
31 warn "drain ",as_hex( $str, $data ),"\n";
39 my $crc = Digest::CRC->new(
40 # midified CCITT to xor with 0xffff instead of 0x0000
41 width => 16, init => 0xffff, xorout => 0xffff, refout => 0, poly => 0x1021, refin => 0,
44 pack('n', $crc->digest);
48 Time::HiRes::sleep 0.015;
52 my ( $hex, $description, $coderef ) = @_;
53 my $bytes = hex2bytes($hex);
54 if ( substr($bytes,0,1) !~ /(\xD5|\xD6)/ ) {
55 my $len = pack( 'n', length( $bytes ) + 2 );
56 $bytes = $len . $bytes;
57 my $checksum = checksum($bytes);
58 $bytes = "\xD6" . $bytes . $checksum;
61 warn ">> ", as_hex( $bytes ), "\t\t[$description]\n";
62 $port->write( $bytes );
66 my $r_len = $port->read(3);
68 while ( length($r_len) < 3 ) {
70 $r_len = $port->read( 3 - length($r_len) );
75 my $len = ord( substr($r_len,2,1) );
76 my $data = $port->read( $len );
78 while ( length($data) < $len ) {
79 warn "# short read ", length($data), " < $len\n";
81 $data .= $port->read( $len - length($data) );
84 warn "<< ", as_hex($r_len,$data),
86 substr($data,-2,2) eq checksum(substr($r_len,1).substr($data,0,-2)) ? 'OK' : 'ERROR',
90 $coderef->( $data ) if $coderef;
95 my ( $got, $expected ) = @_;
96 $expected = hex2bytes($expected);
98 my $len = length($got);
99 $len = length($expected) if length $expected < $len;
101 confess "got ", as_hex($got), " expected ", as_hex($expected)
102 unless substr($got,0,$len) eq substr($expected,0,$len);
104 return substr($got,$len);
110 'D5 00 05 04 00 11 8C66', 'hw version', sub {
112 my $rest = assert $data => '04 00 11';
113 my $hw_ver = join('.', unpack('CCCC', $rest));
114 warn "# 3M 810 hardware version $hw_ver\n";
118 '13 04 01 00 02 00 03 00 04 00','FIXME: stats? rf-on?', sub { assert(shift,
119 '13 00 02 01 01 03 02 02 03 00'
125 my @tags = inventory;
133 cmd( 'FE 00 05', 'scan for tags', sub {
135 my $rest = assert $data => 'FE 00 00 05';
136 my $nr = ord( substr( $rest, 0, 1 ) );
139 warn "# no tags in range\n";
141 my $tags = substr( $rest, 1 );
142 my $tl = length( $tags );
143 die "wrong length $tl for $nr tags: ",dump( $tags ) if $tl =! $nr * 8;
145 foreach ( 0 .. $nr - 1 ) {
146 push @tags, hex_tag substr($tags, $_ * 8, 8);
152 warn "# tags ",dump @tags;
158 # cards 16, stickers: 8
159 my $max_rfid_block = 8;
163 my ( $data, $hex ) = @_;
164 my $b = hex2bytes $hex;
166 if ( substr($data,0,$l) eq $b ) {
167 warn "_matched $hex [$l] in ",as_hex($data);
168 return substr($data,$l);
173 my $tag = shift || confess "no tag?";
174 $tag = shift if ref($tag);
179 sprintf( "02 $tag %02x %02x", $start, $blocks ) => "read_blocks $tag $start/$blocks", sub {
181 if ( my $rest = _matched $data => '02 00' ) {
183 my $tag = hex_tag substr($rest,0,8);
184 my $blocks = ord(substr($rest,8,1));
185 warn "# response from $tag $blocks blocks ",as_hex substr($rest,9);
186 foreach ( 1 .. $blocks ) {
187 my $pos = ( $_ - 1 ) * 6 + 9;
188 my $nr = unpack('v', substr($rest,$pos,2));
189 my $payload = substr($rest,$pos+2,4);
190 warn "## pos $pos block $nr ",as_hex($payload), $/;
191 $tag_blocks->{$tag}->[$nr] = $payload;
193 } elsif ( $rest = _matched $data => 'FE 00 00 05 01' ) {
194 warn "FIXME ready? ",as_hex $rest;
195 } elsif ( $rest = _matched $data => '02 06' ) {
196 warn "ERROR ",as_hex($rest);
198 warn "FIXME unsuported ",as_hex($rest);
202 warn "# tag_blocks ",dump($tag_blocks);
208 $tag = shift if ref $tag;
209 my $data = join('', @_);
211 warn "## write_blocks ",dump($tag,$data);
213 if ( length($data) % 4 ) {
214 $data .= '\x00' x ( 4 - length($data) % 4 );
215 warn "# padded data to ",dump($data);
218 my $hex_data = as_hex $data;
219 my $blocks = sprintf('%02x', length($data) / 4 );
222 "04 $tag 00 $blocks 00 $hex_data", "write_blocks $tag [$blocks] $hex_data", sub {
224 if ( my $rest = _matched $data => '04 00' ) {
225 my $tag = substr($rest,0,8);
226 my $blocks = substr($rest,8,1);
227 warn "# WRITE ",as_hex($tag), " [$blocks]\n";
228 } elsif ( $rest = _matched $data => '04 06' ) {
229 warn "ERROR ",as_hex($rest);
240 $tag = shift if ref $tag;
245 "0A $tag", "read_afi $tag", sub {
248 if ( my $rest = _matched $data => '0A 00' ) {
250 my $tag = substr($rest,0,8);
251 $afi = substr($rest,8,1);
253 warn "# SECURITY ", hex_tag($tag), " AFI: ", as_hex($afi);
255 } elsif ( $rest = _matched $data => '0A 06' ) {
256 warn "ERROR reading security from $tag ", as_hex($data);
258 warn "IGNORED ",as_hex($data);
261 warn "## read_afi ",dump($tag, $afi);
267 $tag = shift if ref $tag;
268 my $afi = shift || die "no afi?";
273 "09 $tag $afi", "write_afi $tag $afi", sub {
276 if ( my $rest = _matched $data => '09 00' ) {
278 my $tag = substr($rest,0,8);
279 $afi = substr($rest,8,1);
281 warn "# SECURITY ", hex_tag($tag), " AFI: ", as_hex($afi);
283 } elsif ( $rest = _matched $data => '0A 06' ) {
284 warn "ERROR writing AFI to $tag ", as_hex($data);
287 warn "IGNORED ",as_hex($data);
291 warn "## write_afi ", dump( $tag, $afi );